高品質なソフトウェアはコストに見合う価値があるか?
2019年5月29日
ソフトウェア開発プロジェクトにおける共通の議論は、ソフトウェアの品質向上に時間を費やすことと、より価値のある機能をリリースすることに集中することの間で繰り広げられます。通常、機能を提供しようとするプレッシャーが議論を支配し、多くの開発者がアーキテクチャやコード品質に取り組む時間がないと不満を抱いています。
ベタリッジの法則とは、疑問符で終わる見出しやタイトルの記事はすべて「いいえ」と要約できるという格言です。私のことを知っている人なら、私がそのような法則を覆したいと思っていることを疑うことはないでしょう。しかし、この記事はそれをさらに超えており、質問そのものを覆します。この質問は、品質とコストの間の一般的なトレードオフを想定しています。この記事では、このトレードオフがソフトウェアには当てはまらないこと、つまり、高品質なソフトウェアは実際には生産コストが安いことを説明します。
私の文章のほとんどはプロのソフトウェア開発者を対象としていますが、この記事では、ソフトウェア開発のメカニズムに関する知識を前提としないことにします。この記事が、ソフトウェアの取り組みについて考えるすべての人々、特にソフトウェア開発チームの顧客として行動するビジネスリーダーのような人々にとって価値のある記事になることを願っています。
私たちは品質とコストのトレードオフに慣れています
冒頭で述べたように、私たちは皆、品質とコストのトレードオフに慣れています。スマートフォンを買い替えるとき、私はより高速なプロセッサ、より良い画面、より多くのメモリを備えたより高価なモデルを選ぶことができます。あるいは、それらの品質をあきらめて、支払う金額を減らすこともできます。これは絶対的なルールではありません。時には、高品質な商品が安く手に入るお買い得品もあります。多くの場合、私たちは品質に対する価値観が異なります。一部の人々は、ある画面が別の画面よりもどれだけ優れているかにはあまり気づきません。しかし、ほとんどの場合、この仮定は当てはまり、高品質は通常、より多くのコストがかかります。
ソフトウェアの品質には多くの意味があります
ソフトウェアの品質について話すのであれば、それが何かを説明する必要があります。ここに最初の複雑さがあります。ソフトウェアの品質として数えられるものはたくさんあります。私はユーザーインターフェイスについて考えることができます。ユーザーインターフェイスは、私がやらなければならないタスクを簡単に誘導し、効率を高め、不満を取り除くでしょうか?私はその信頼性について考えることができます。エラーや不満を引き起こす欠陥が含まれているでしょうか?もう一つの側面は、そのアーキテクチャです。ソースコードは明確なモジュールに分割されており、プログラマーは今週作業する必要があるコードのどの部分を簡単に見つけて理解できるでしょうか?
これら3つの品質の例は、網羅的なリストではありませんが、重要な点を説明するのに十分です。私がソフトウェアの顧客またはユーザーである場合、品質として言及するいくつかのものを評価しません。ユーザーは、ユーザーインターフェイスが良いかどうかを判断できます。役員は、ソフトウェアが自分のスタッフの作業効率を向上させているかどうかを判断できます。ユーザーと顧客は欠陥に気づきます。特に、欠陥がデータを破損させたり、システムをしばらく動作不能にしたりする場合はそうです。しかし、顧客とユーザーはソフトウェアのアーキテクチャを認識できません。
したがって、ソフトウェアの品質属性を外部(UIや欠陥など)と内部(アーキテクチャ)に分けます。違いは、ユーザーと顧客は、ソフトウェア製品を高品質にする外部品質を確認できるが、より高い内部品質とより低い内部品質の違いを区別できないことです。
一見すると、内部品質は顧客にとって重要ではありません
内部品質は顧客やユーザーが見ることができないものであるため、重要なのでしょうか?レベッカと私がフライトの遅延を追跡および予測するアプリケーションを作成するとしましょう。両方のアプリケーションは同じ重要な機能を果たし、両方とも同様にエレガントなユーザーインターフェースを備えており、両方ともほとんど欠陥がありません。唯一の違いは、彼女の内部ソースコードがきちんと整理されているのに対し、私のソースコードは複雑に絡み合っているということです。もう1つの違いは、私が6ドルで販売しているのに対し、彼女は10ドルで販売しているということです。
顧客はこのソースコードを見ることはなく、アプリの動作に影響を与えないため、レベッカのソフトウェアに4ドル追加で支払う人がいるでしょうか?より一般的に言えば、より高い内部品質のためにもっとお金を払う価値がないことを意味するはずです。
別の言い方をすれば、外部品質のためにコストを交換するのは理にかなっていますが、内部品質のためにコストを交換するのは理にかなっていません。ユーザーは、より優れたユーザーインターフェイスを得るためにもっとお金を払いたいかどうかを判断できます。ユーザーインターフェイスが追加のお金を払う価値があるほど優れているかどうかを評価できるためです。しかし、ユーザーはソフトウェアの内部モジュール構造を見ることはできません。それがより優れていると判断することはなおさらできません。影響のないもののためにもっとお金を払うのはなぜですか?そうであるならば、なぜソフトウェア開発者は自分の仕事の内部品質を改善するために時間と労力を費やす必要があるのでしょうか?
内部品質はソフトウェアの拡張を容易にします
では、なぜソフトウェア開発者は内部品質を問題にするのでしょうか?プログラマーはほとんどの時間をコードの変更に費やします。新しいシステムでも、ほぼすべてのプログラミングは既存のコードベースのコンテキストで行われます。ソフトウェアに新機能を追加する場合、私の最初のタスクは、この機能が既存のアプリケーションのフローにどのように適合するかを理解することです。次に、そのフローを変更して、私の機能を適合させる必要があります。多くの場合、アプリケーションにすでに存在するデータを使用する必要があるため、データが何を表しているのか、周囲のデータとどのように関連しているのか、そして私の新機能に必要なデータは何かを理解する必要があります。
これらはすべて、私が既存のコードを理解することに関係しています。しかし、ソフトウェアは理解するのが非常に簡単ではない可能性があります。ロジックが絡み合ったり、データが追跡しにくかったり、何かを参照するために使用される名前が6か月前にトニーには理にかなっていても、会社を辞めた理由と同じくらい私には不可解な場合があります。これらはすべて、開発者がクルフトと呼ぶものの一種です。つまり、現在のコードと理想的なコードの差です。
内部品質の主な特徴の1つは、アプリケーションがどのように機能するかを簡単に理解できるようにすることで、追加するものを確認できるようにすることです。ソフトウェアが個別のモジュールにうまく分割されている場合、500,000行のコードをすべて読む必要はなく、いくつかのモジュールで数百行を簡単に見つけることができます。明確な命名に努力を払った場合、詳細を解読しなくても、コードのさまざまな部分が何をするかをすぐに理解できます。データが基になるビジネスの言語と構造に合理的に従う場合、カスタマーサービス担当者から得たリクエストにどのように関連するかを簡単に理解できます。クルフトは変更方法を理解するのにかかる時間を増やし、間違いを犯す可能性も高めます。間違いに気づいた場合、何が問題でそれをどのように修正するかを理解する必要があるため、さらに時間がかかります。間違いに気づかなければ、本番環境で欠陥が発生し、後で修正するのにさらに時間がかかります。
私の変更は将来にも影響します。この機能を導入するための簡単な方法が見えるかもしれませんが、それはプログラムのモジュール構造に反するルートであり、クルフトを追加します。その道を進むと、今日は私にとってより速くできますが、将来数週間または数か月でこのコードを扱う必要のある他の全員を遅らせることになります。チームの他のメンバーが同じ決定を下すと、変更が容易なアプリケーションはすぐにクルフトを蓄積して、わずかな変更を行うだけで数週間の労力がかかるようになる可能性があります。
顧客は新機能が迅速に提供されることを気にしています
ここで、内部品質がユーザーと顧客にとって重要である理由のヒントが見られます。内部品質が向上すると、新機能の追加が容易になり、したがってより迅速かつ安価になります。レベッカと私は今同じアプリケーションを持っているかもしれませんが、今後数か月で、レベッカの高い内部品質により、毎週新機能を追加できるのに対し、私はクルフトを切り抜けて、たった1つの新機能をリリースしようと立ち往生しています。私はレベッカのスピードと競争することはできず、すぐに彼女のソフトウェアは私のソフトウェアよりもはるかに機能的になります。すると、私の顧客は全員私のアプリを削除し、代わりにレベッカのアプリを入手します。彼女は価格を上げることができるにもかかわらずです。

内部品質の影響を視覚化する
内部品質の基本的な役割は、将来の変更コストを下げることです。しかし、優れたソフトウェアを作成するにはいくつかの追加の労力が必要であり、短期的にいくつかのコストがかかります。
これを視覚化する方法は、次の疑似グラフを使用することです。ソフトウェアの累積機能対それを生成する時間(したがってコスト)をプロットします。ほとんどのソフトウェアの取り組みでは、曲線は次のようになります。

これは、内部品質が低い場合に起こることです。最初は急速に進歩しますが、時間が経つにつれて新機能を追加するのが難しくなります。小さな変更でも、プログラマーは理解するのが難しいコードの広い領域を理解する必要があります。変更を加えると、予期しない破損が発生し、テスト時間が長くなり、修正が必要な欠陥が発生します。
高い内部品質に集中することは、生産性の低下を減らすことです。実際、一部の製品では、以前の作業を利用することで新機能を簡単に構築できるため、開発者が加速できるという反対の効果が見られます。この幸運な状況は、それを実現するために熟練した規律のあるチームが必要であるため、よりまれなケースです。しかし、時折、それが見られます。

ここでの微妙な点は、内部品質が低い方が高い追跡よりも生産性が高い期間があるということです。この間、品質とコストの間にはある種のトレードオフがあります。もちろん、問題は、線が交差するまでの期間はどのくらいかということです。
この時点で、これが疑似グラフである理由に遭遇します。ソフトウェアチームによって提供される機能を測定する方法はありません。この出力、したがって生産性を測定できないため、内部品質が低いことの結果(測定も難しい)に確固たる数値を当てはめることは不可能です。出力を測定できないことは専門職の間では非常に一般的です。弁護士や医師の生産性をどのように測定すればよいでしょうか?
私が、線が交差する場所を評価する方法は、私が知っている熟練した開発者の意見を求めることです。そして、その答えは多くの人々を驚かせます。開発者は、質の低いコードが数週間以内に著しく彼らの作業を遅くすることに気づきます。そのため、内部品質とコストのトレードオフが適用される猶予はあまりありません。小さなソフトウェア開発であっても、良いソフトウェアプラクティスに注意を払うことは有益であり、それは私の経験からも断言できます。
最高のチームでさえ、クルフト(不要物)を作り出します
多くの開発者以外の人々は、粗悪なコード(cruft)は、開発チームが不注意でミスをした場合にのみ発生するものと考えがちですが、最高のチームであっても、作業中に必然的にある程度の粗悪なコードを作り出してしまいます。
私はこの点を、最高の技術チームリーダーの1人と話した時の話で説明するのが好きです。彼は、大成功と広く評価されたプロジェクトを終えたばかりでした。クライアントは、システムの機能と構築時間とコストの両方について、納品されたシステムに満足していました。私たちのメンバーも、プロジェクトでの作業経験について前向きでした。技術リーダーは概ね満足していましたが、システムのアーキテクチャがあまり良くなかったと打ち明けました。私は「どうしてそんなことがありえるのか - あなたは私たちの最高のアーキテクトの一人ではないか?」と反応しました。彼の答えは、経験豊富なソフトウェアアーキテクトなら誰でも知っているものです。「私たちは良い決断をしましたが、今になって、どのように構築すべきだったかを理解したのです」と。
ソフトウェア業界の多くの人を含め、多くの人々はソフトウェアの構築を大聖堂や高層ビルの建設に例えます。結局のところ、なぜ私たちはシニアプログラマーに「アーキテクト」という言葉を使うのでしょうか?しかし、ソフトウェアの構築は、物理的な世界では未知の不確実性の世界に存在します。ソフトウェアの顧客は、製品に必要な機能についておおまかなアイデアしか持っておらず、ソフトウェアが構築されるにつれて、特に初期バージョンがユーザーにリリースされると、さらに多くのことを学びます。ソフトウェア開発の構成要素である言語、ライブラリ、プラットフォームは、数年ごとに大きく変化します。物理的な世界で同様の例えをすると、顧客が建物の半分が建設され占有された後、通常、新しいフロアを追加し、フロアプランを変更する一方で、コンクリートの基本的な特性は1年おきに変化することになります。
このレベルの変化を考えると、ソフトウェアプロジェクトは常に新しいものを創造しています。これまで解決されたことのある、よく理解された問題に取り組むことはほとんどありません。当然のことながら、ソリューションを構築するにつれて、問題について最も多くを学ぶため、チームがソフトウェアのアーキテクチャがどうあるべきかを本当に最もよく理解するのは、構築に1年ほど費やした後だという話をよく聞きます。最高のチームでさえ、ソフトウェアには粗悪なコードが存在するでしょう。
違いは、最高のチームは粗悪なコードを生成する量がはるかに少ないだけでなく、生成した粗悪なコードを十分に取り除くことで、機能を迅速に追加し続けることができるという点です。彼らは、問題を迅速に表面化させ、バグを取り除く時間を減らすために、自動化されたテストを作成することに時間を費やします。彼らは頻繁にリファクタリングを行い、粗悪なコードが邪魔になるほど蓄積する前に取り除くことができるようにします。継続的インテグレーションは、チームメンバーが目的を異にして作業することによって粗悪なコードが蓄積されるのを最小限に抑えます。一般的な例えとしては、キッチンで作業台や器具を片付けるようなものです。料理をするときに汚さないことはできませんが、すぐに片付けなければ、汚れが乾いて落としにくくなり、すべての汚れたものが次の料理の邪魔になります。
高品質なソフトウェアは生産コストが安いです
これらすべてをまとめると
- 内部品質を無視すると、粗悪なコードが急速に蓄積されます。
- この粗悪なコードは、機能開発を遅らせます。
- 優れたチームであっても粗悪なコードを生成しますが、内部品質を高く保つことで、それを制御することができます。
- 内部品質が高いと、粗悪なコードを最小限に抑え、チームはより少ない労力、時間、コストで機能を追加できます。
残念ながら、ソフトウェア開発者は通常、この状況をうまく説明することができません。数え切れないほど、私は「(経営陣は)時間がかかりすぎるので、質の高いコードを書かせてくれない」と言う開発チームと話をしてきました。開発者は、適切なプロフェッショナリズムの必要性を正当化することで、品質への注意を正当化することがよくあります。しかし、この道徳的な議論は、この品質にはコストが伴うことを意味し、彼らの議論を台無しにします。困ったことに、その結果生じる粗悪なコードは、開発者の生活をより困難にし、顧客のコストを増大させます。内部品質について考えるとき、私たちは経済的な議論としてのみアプローチすべきだと強調します。内部品質が高いと、将来の機能のコストが削減され、優れたコードを書くことに時間を費やすことは、実際にはコストを削減することを意味します。
これが、この記事の見出しの質問が要点を外している理由です。内部品質の高いソフトウェアの「コスト」はマイナスです。私たちが人生のほとんどの決定で慣れ親しんでいる、コストと品質の通常のトレードオフは、ソフトウェアの内部品質には意味がありません。(慎重に作成されたユーザーエクスペリエンスなど、外部品質には当てはまります。)コストと内部品質の関係は、異常で直感に反する関係であるため、通常、吸収するのが困難です。しかし、それを理解することは、最大の効率でソフトウェアを開発する上で不可欠です。
内部品質の低さがもたらす影響の測定
(追加: 2024-01-29)
上で述べたように、内部品質や生産性をどのように測定するかはよくわかっていないため、内部品質の重要性に関する定量的な証拠を得ることは困難です。しかし近年、その試みが増えています。
私が目にした特に興味深い論文の1つは、Adam TornhillとMarkus Borgによるこの研究です。彼らは、独自のツールであるCodeSceneを使用して、39の独自のコードベースのファイルの健全性レベルを判断しました。その結果、低品質なコードの問題を解決するのに、高品質なコードの場合よりも2倍以上時間がかかり、低品質なコードの欠陥密度は15倍高いことがわかりました。
重要な改訂
2019年5月29日: 公開