このページはこちら に移転しました。 このページは更新を停止しています。今後更新があれば移転先で行います。
始めに
以下の文書は、フレデリック・ブルックスの「人月の神話」を個人的視点でまとめたものです。日本語版も参考にはしていますが、基本的には英語の原著をベースにまとめています。また、以下で出てくるページ番号は日本語版ではなく原著のページ番号です。 原著に書かれていないことは、極力書かないようにしましたが、日本語に訳す関係や内容をまとめる関係で、意訳のようになっているところもあります。
この本の1~15章は1975年、16章は1986年、17~19章は1995年に書かれています。著者は、後に書いた章で以前に書いた章の内容について追補したり撤回したりしています。このまとめではそれらのフィードバックをあらかじめ反映し、内容の足し引きを行った後の状態を提示しようと試みています。ただ、この試みは完璧ではありません。特にウォーターフォールモデルに関しては、第19章で著者は、ウォーターフォールモデルは誤っている、だが、1~15章の文章はウォーターフォールモデルを暗黙の内に想定してしまっておりその影響が全般に及んでいると述べています。したがって、ウォーターフォールモデル以外の開発モデルを念頭に置いて1~15章の個々の内容を吟味するような作業は、最終的には読者1人1人が注意深く元の本を読んで行うしかないと思われます。
なお、この本を読む場合には、まず18章に目を通すことをおすすめします。18章は、1~15章における著者の主張を抜き出し箇条書きでまとめたのものです。 また、18章の内容がこのようなものであるため、このまとめに18章はありません。
参照した原著と日本語版
Brooks, Fred P. (1995). “The Mythical Man-Month: Essays on Software Engineering” (Anniversary Edition). Addison-Wesley. ISBN 0-201-83595-9.
フレデリック・P・ブルックス Jr. 著 滝沢 徹・牧野 祐子・富澤 昇 訳. (2014). “人月の神話” (新装版). 丸善出版. ISBN 978-4-621-06608-9.
第1章 開発コストと開発の喜びと苦しみ
プログラムシステム製品の開発コスト
大規模システムプログラム開発において、設定されたゴール、スケジュール、及び、予算を全て満たした事例は少ない。 一方で、大きな開発チームが作った製品を上回るプログラムをガレージの2人組が作った事例はある。 この対比について考えるには、何が作られているのかに目を向ける必要がある。
単なるプログラム:プログラマ個人で使うもの。よくプログラマ個人が想定する生産性はこれに対するものである。
プログラム製品:多くの環境や入力データに対応し、誰でもテスト・修正・拡張が可能なもの。入力可能範囲をカバーしたり境界値を確認したりする十分な数のテストケースが必要。デバッグ済みの単なるプログラムに比べ開発コストは少なくとも3倍。
プログラムシステム:協調して機能するプログラムコンポーネントの集まり。協調のための仕組みやコンポーネントの間での資源の分配が必要。コンポーネントの可能な組み合わせ全てについてカバーできるようなテストが必要。プログラムシステムの1コンポーネントの開発コストは単なるプログラムに比べ少なくとも3倍。
プログラムシステム製品:システムかつ製品であるもの。開発コストは単なるプログラムに比べ少なくとも9倍。
プログラムシステム製品の開発チームという体制に対して、ガレージの2人組という体制が取って代わらない理由がここにある。
(「少なくとも何倍」というのは著者による推定である。)
開発の喜び
物を作る純然たる喜び。例えば、泥遊びで作った泥団子。
他人のために有用な物を作る喜び。例えば、お父さんの仕事場用にと作ったペン立て。
複雑でパズルのようなものを作る魅力。例えば、ピンボールのような。
新しく学ぶ喜び。本質的には同じプログラムを再び書くことはない。
頭の中で思い描いたことを現実にできるほどの柔軟性を持つプログラムというもので仕事をする喜び。プログラムはやり直しが効いて扱いやすいが、このことは第2章で触れるように問題でもある。
開発の苦しみ
完璧でなくてはならないこと。伝説に登場する呪文のように一語一句間違えてはいけない。
責任に見合う権限が与えられないこと。仕事の環境やゴールでさえコントロールできることはまれである。ただし、どんな分野であれ、物事を成し遂げる仕事においては、正式な権限が責任に見合うだけ与えられることはないようだ。完遂へ向かう勢いの中で、正式な権限ではなく実際の権限が得られるのだ。
他人のひどいプログラムに付き合う必要があるとき。
つまらないバグ取り。楽しい仕事だけではない。
多くの人が思うよりもデバッグには時間がかかること。よって、テストは延々続くし、最後の難しいバグはなかなか取れない。
技術は常に進んでいるため、製品は完成したときには常に時代遅れであるということ。しかし比較対象が未完成であるならば、その完成にはどうせ時間がかかるのだ。相手がコンセプト段階であり、その実装がまだ存在していない場合は特にそうである。
第2章 見積もり失敗の原因と対処法
ソフトウェア開発の失敗の原因は開発期間の不足によるものが圧倒的に多い。その理由と対策は以下の通りである。
原因1 楽観主義などの要因により、コストを低く見積もる傾向がある(見積もったコストが量的に不足している)。
楽観主義。「全部うまく行くだろう」。それぞれの仕事にかかる時間は、かかるべきと考えられる時間だけであろう。
人が何かを作るときの3段階:アイデア(idea)、実装(implementation)、利用者との相互作用(interaction)
実装には、物理的制約(時間や空間の制約)があり、これが予期せぬ実装の難しさを生むことがある。
アイデアの欠陥は実装段階になってから明確になる。また、アイデアの欠陥は見過ごされやすい。なぜなら、自分が作ったアイデアよりは、自分が作ったわけでもない物理的制約のせいにしがちだからだ。
プログラムの扱いやすさ(やり直しが効いて扱いやすいという第1章で触れられた開発の喜び)は、実装の難しさを忘れ、アイデアの欠陥を見落とす要因の1つである。
単一の作業ならまだしも、一連の作業が全て上手く行き、全てで遅れが発生しない確率は、ゼロに近い。
原因2 人月が開発の進捗を表すという誤った考え(順序的制約と人員数によるコスト変動の軽視)。
農作物の収穫は、多数の人で取りかかれば早く終わる。一方で、どんなに多くの人が手助けしても、妊娠期間を短くすることは出来ない。この違いはどこから来るのだろうか。
順序的制約があると、作業を複数に分割できても平行して行うことが出来ない。例えば、デバッグにおいて混乱を避けるために、コードの修正と修正後の確認を1つずつ実施しようとするならば、現在作業中のバグの修正・確認が終わらなければ、次のバグの修正・確認の開始が出来ない。
平行して行う作業の分割数(=作業人数)に応じて増加するコストがある。
教育・訓練コスト:新たに開発チームに加わるメンバーは、技術、その開発の目的、目的を達成するための戦略、及び、作業計画について、教育・訓練が必要である。他人が肩代わりは出来ないので、教育・訓練コストはメンバー数に比例して増加する。
コミュニケーションコスト:分担された各作業間で、担当者同士2者間調整が必要であるとする。すると、分割数がnの場合、n(n-1)/2通りの組み合わせで調整が必要となる。これは分割数nの2乗で増加する項を持つコストである。2者間調整で足りず、3者以上が1回の会議で同時に調整する必要があれば、コストはよりひどく増加するだろう。
ソフト開発は複雑な相互関係を本質的に扱っているので、コミュニケーションに必要な労力はどうしても大きい。
作業人数(=分割数)を増やすとコストも増える。さらに、コミュニケーションコストは2乗以上で増える。そのため、作業人数を増やしていくと、どこかで開発期間は短くならなくなり、逆にどんどん長くなっていく。
定量的研究による裏付け(第19章 pp. 273-274より)
Barry Boehmが63のソフトウェアプロジェクトに対して行った定量的研究では、以下が示された。
Boehmが立てたモデルを使うと、見積もった人月からコスト最適スケジュール時間が計算できる。
計画されたスケジュールがこの最適時間より短くなるにつれ、コスト曲線が急激に上昇する。
投入された人数にかかわらず、この最適時間の3/4以下の期間で成功したプロジェクトはほとんどない。
原因3 顧客の要望を書いただけの開発完了予定日。
ソフトウェア開発では、他分野に比べ顧客の要望に合うようにスケジュールが立てられることが多い。
データは不足しやすく、定量的にはなりにくく、直感による部分が大きいソフトウェア見積もりを開発サイドが弁護するのはとても難しい。
しかし、例え顧客が開発完了予定日を思いのままに出来たとしても、実際の開発完了を思いのままに出来るわけではない。
原因4 他の工学分野に比べ、進捗が適切にモニタリングされていない。
他の工学分野では立証され日常的に利用されている技術が、ソフトウェアエンジニアリングでは革新と考えられている。
原因5 開発の遅れに対して人員を追加するという不味い対応が行われやすい。
どんなに早く、どんなに有能な人を確保できたとしても、教育・訓練(技術、目的、戦略、計画)は必要である。
教育・訓練には開発チームの既存メンバーから最低でも1人を担当させる必要がある。
この教育・訓練の間は、新メンバーとこの既存メンバーの人月の多くは、教育・訓練コストとして消える。
教育・訓練コストに加え、コミュニケーションコストの増加もある。
極端な人員増加では、チーム構成を質的にも変化させてしまう。
安易な人員増加はソフトウェアの品質も低下させる。
人員追加と開発完了時期の簡単な計算例
人員増加によるコスト増加を計算に入れれば、増員しても開発完了が増員前と変わらなかったり、増員した方がむしろ遅くなったりする結果となる計算例。
詳細は第2章の「Regenerative Schedule Disaster」の項を参照のこと。
関連研究(第19章 pp. 274-275より)
Abdel-HamidとMadnickは著書で以下のように結論づけた。遅れているプロジェクトに人員を追加すると、必ず開発コストは増加する。開発完了は必ずしも遅れるとは限らない。特に早期の人員追加は末期に比べればずっと安全である。
Stutzkeの研究でも同じような結論が得られている。また、Stutzkeは人員追加について実践的なアドバイスを与えている。例えば、末期に開発プロジェクトに追加される人々は、意欲があり、かつ、プロセスの変更や改善には挑戦せずに現行のプロセスに従って喜んで仕事をする人々でなくてはならないとコメントしている。
対処法1 開発期間の半分をテスト期間に割り当てる。
(ここでの議論は特に、ウォーターフォールモデルが暗黙的前提になってしまっていることに注意が必要である。後に書かれた第19章で言及されているように、ウォーターフォールモデルがそもそも間違っている。ウォーターフォールモデルの一巡ではなく、別の開発モデルであるスパイラルやアジャイルのイテレーションにおいても、それぞれの論点が成立するのかは読者の判断に任されるのであろう。)
著者の調査によると、半分の期間をテスト期間に割り当てている開発プロジェクトは少ないが、大半のプロジェクトでは結局開発期間の半分がテスト期間になってしまっている。
ソフトウェアコンポーネントのデバッグとシステムテストは、もっとも順序的制約を受けやすい。
バグの数と難しさで必要な時間は異なるが、楽観主義のせいで実際より少なく見積もる傾向があるため、テスト部分のスケジュール作成は最も失敗をしやすい。(そもそも実装と平行して行う単体テストで全てのバグが取れていると楽観してしまうと、実装後のテスト期間に見つかるバグは存在しないことになってしまう。当然実際は違う。)
十分なテスト期間の割り当ては、開発遅延による二次的コストのリスクを下げる。
二次的コストの発生の仕方:テスト期間を十分に設けない -> テスト期間に入るまでは遅れが表面化しない -> そのソフトウェアを利用してビジネスを行う顧客企業に突然のように遅れが通知される -> 莫大な二次的コスト
テスト期間を十分設けていれば、このような事態になるリスクを下げられる。
対処法2 遅れがはっきりしたときは、人員追加ではなくスケジュールの立て直しを。機能削減も有効。
「小さな遅れを重ねるな」
各作業を注意深く完全に実施するのに十分な時間を持つ新しいスケジュールを立てて、二度と遅れが発生しないようにする。
機能の削減などで作業量を削減しても良い。
公式に、慎重に、計画を立て直すのが一手。
時間不足の設計と不十分なテストにより、静かに仕事が減っていくのを眺めるのが別の一手。
対処法3 見積もりに関するデータと手法の共有。
生産性や不良発生についての数値指標や見積もり手法などを開発し、公表して、ソフトウェア開発者全体で共有する。
対処法4 気を強く持つ。
良いデータと手法が共有されるまでは、気を強く持って、自分の見積もりを弁護するしかない。 言われた希望に従っただけの見積もりと比べるならば、勘と変わらない程度であっても、まだまともだと信じて。
対処法5 開発期間短縮より開発コスト低減を優先したスケジュールを立てる。
開発期間は、順序的制約の範囲でしか短く出来ない。
開発人員は、独立して同時に実行出来る作業の数より、多くすることはできない。
これらの制約に基づいて、より少ない人員でより長い期間をかけて開発するスケジュールを立てることは可能である。
このようなスケジュールを立てるときには、ソフトウェアが開発完了時点において時代遅れで価値のないものにならないかどうかだけには注意すること。
第3章 職務の専門化を用いたチーム編成:優秀な開発者でも少数では開発できない規模の開発を行うために
少数で開発できるならそうすれば良いが、そうできない規模の開発もある。 少なくない人数で開発するにはチーム編成の工夫が重要となる。
前提の整理
少数の優秀な開発者で開発できるならそうした方が良い。
多数の平凡な人達より、少数の優秀な人達で開発した方が良いと、 コンピュータの学会の集まりに来るような人達は皆そう思っている。 その主な理由は以下の2つ。
生産性に大きな個人差がある。ある研究事例では、プログラマの生産性の最低と最大では10倍の開きがあった。
第2章で述べたとおり、関わる人数の増加は開発コストを増加させる。コミュニケーションのコストとコミュニケーション失敗の埋め合わせ(つまりシステムデバッギング)は、主要な開発コストである。
また、単なる大量動員で開発すると、コストは上昇し、開発は遅れ、効率は悪化し、出来上がる製品は統一感に欠けるというのは、過去の事例(OS/360、Exec 8、Scope 6600、Multics、TSS、SAGEなどなど)が示すことでもある。
優秀な開発者でも少数では開発できないほどの規模は存在する。
OS/360のピーク時では、1000人が関わり、3年間で5000人年が投じられた。
7倍優秀な10人が、コミュニケーションコスト減によりさらに7倍生産的に働いたと単純に仮定しても、7 * 10 * 7 = 490であり、10年間かけても5000人年には満たない。
ミルズの案:一人の主開発者を皆が助けるチーム編成
以下のように、仕事を上手く分化・特化させ、開発の根本的な部分は1人が行い、それをその他の人達が助けるチーム編成。 例えるなら、外科手術において1人の執刀医が手術するのを麻酔科医や看護師が助けるのに近い。
主開発者:根本的に開発を行う人。チーフプログラマ。手術で例えれば執刀医。
行うことは、機能や性能に関する要件や要求の定義、設計、コーディング、テスト、及び、ドキュメント作成。
主開発者は、優れた才能、10年に及ぶ経験、システムに関する知識、及び、アプリケーションに関する知識(応用数学やビジネスデータ処理)が必要。
副開発者:主開発者を代行可能な補佐役。航空機運航で例えれば副操縦士。
主開発者のどの仕事も行えるが、経験は少ない。
主な役割は、主開発者と一緒になって、設計を考えたり、議論したり、評価したりすることである。ただし、副開発者の意見に従う義務は主開発者にはない。
チーム間の調整では、チームの代表をしばしば務める。
全てのコードについてよく知っている。
他の設計ができないかを調査する。
主開発者に何かあったときの保険でもある。
コーディングをしても良いが、書いたコードの責任を持つのは主開発者である。
事務官:主開発者が開発に集中することを可能にする人事や庶務のプロ。
主開発者は人事や総務の面でもチームのトップであるが、開発に集中するため、そういった仕事(人、物、金、場所など)の実務のほとんどを事務官が行う。
1人の事務官が2チームを担当できるが、法律、契約、報告、または財務に関して、顧客から相当な量の要求がある場合には、1人で1チームを担当しても良い。
編集者:ドキュメント作成の監督者。
主開発者が書いたり口述筆記させたりした原稿に対して、校正、評価、修正、引用箇所や参考文献の整備、改版の管理などを行って良いドキュメントにする。
秘書2人:事務官と編集者、それぞれに対する秘書。
開発庶務係:開発環境の整備・運用やプログラム製品の全ての技術情報の記録・管理などを行う人。
プロジェクト管理や開発環境の整備・運用のために以下のような業務を行い、全てのチームメンバーに対して、必要な開発環境が利用でき、必要な情報が閲覧できるようにする。
ファイルの管理(バージョン管理システムやバイナリファイル保存方法などに関する整備と運用)
ビルドシステム運用
テストシステム運用
ビルドやテストの管理(計画と結果の記録の管理)
上記のうちバッチ化(自動化)されていない部分について手を動かすのも、開発庶務係の仕事である。
(残存しているバグやどのバージョンでバグが修正されたかの情報の管理であるバグ管理について著者は言及していないが、プログラム製品の全ての技術情報を管理するとしているので、バグ管理も開発庶務係の仕事に含まれると考えて良いだろう。)
ツール担当者:チームのニーズに合ったツールを用意する人。
プログラミングやデバッグのためのツールについて、主開発者の要望を基に、チームに合ったツールを提供する。ツールが常に問題なく利用できるように、ツールの用意(必要があればカスタマイズや作成を行う)・メンテナンス・アップグレードを行う。
テスタ:テストケースの作成とテストフレームワークをセットアップする人。
製品仕様などからテストケースを作成したり、主開発者が日々行うデバッグのためのテストデータを作成したりする。
テストの順番の計画やコンポーネントテスト(単体テスト)に必要なフレームワークのセットアップも行う。
言語技師:開発に使用する言語のエキスパート。
難易度が高かったり、不明点があったり、トリッキーであったりするような処理について、その言語において適切で効率的なやり方を見つけるのが仕事。
そのために2、3日を使ってちょっとした研究を行う。
一人で2、3チームを担当可能。
ミルズの案の効果
チームには10人が関与するが、開発するシステムについて考える主体は1つと言って良い(主開発者の単独作業か、副開発者と2人の共同作業)。
チーム内のコミュニケーションの仕方が単純明快であるため効率的(図3.1参照のこと)。
ベーカーの論文によって、このチーム構成案がうまく行ったことが報告されている。
仕事の分割がなく主副関係があることの効果(以下の従来との比較を参照のこと)。
「プログラマ2人による従来の開発」(以下「従来」)と「主開発者と副開発者による開発」(以下「主副」)との比較
従来:2人で仕事を分割し、それぞれで設計と実装を行う。
主副:主開発者と副開発者の両方が、設計でもコードでも全体を知っている。これにより、リソース調整のための労力は軽減される。また、出来上がったものが概念的に整合していること(conceptual integrity)が確保される。
従来:2人は対等であり、考え方や立場の違いは、話し合われたり妥協されたりする必要がある。そして、仕事は分割されているので、両者が関わる全体の戦略やインターフェイス部分にこれらの違いは集約される。つまり、どちらのメモリスペースがバッファに使われるのかといったことから、戦略やインターフェイスが出来上がってしまうのである。
主副:仕事が分割されていないので立場による違いは起きない。考え方の違いに対しては主副の関係から主開発者が一方的に決着をつける。
スケールアップの方法
ミルズ案の10人のチームを20用意すれば200人が投入できる。チーム内で10人が7つの専門領域で働いていても、開発するシステムを考える主体は1つなので、各チームの担当部分の概念的整合性(conceptual integrity)は劇的に改善している。よって、200人中のたった20人の主開発者がどう調整を行えば良いかを考えれば良い。
この調整に必要なテクニックの詳細は後の章で述べるが、要点は以下の通り。
システム全体にも概念的な整合性が必要。よって、1人のシステムアーキテクトによるトップダウンの設計が必要。
アーキテクチャと実装を明確に区別し、アーキテクトはアーキテクチャに専念する。
(組織構成、特に主開発者と事務官の関係は、ミルズの案に限られるわけではない。詳細は第9章の「Organization in the Large Programming Project」とそれに続く項を参照のこと。)
第4章 アーキテクチャと実装の分離:使いやすいシステムを作るために最も考慮すべきこと
使いやすさの指標
使いやすさ=Gain/Cost
Gain:機能を利用することで得られた時間
Cost:機能の使うために失われた時間
Costの例は、マニュアルを勉強したり、覚えたり、探したりするのにかかった時間である。
単に機能が多いだけで、それらを使うためのCostが大きいならダメ。
単純(simplicity)な機能構成になっていても、機能要素を複雑に組み合わせないとやりたいことができないようではダメ。つまり、明快(straightforwardness)であることも必要。
単純明快であるためには、概念的な整合性(conceptual integrity)が必要。概念的な整合性を得るには、意見が一致していて共鳴するところがある少数の人達がアーキテクチャを作る必要がある。設計を単純に分割して多数の人に行わせてしまうと概念的な整合性は得られない。
以上から、使いやすいシステムを作るには、少数のアーキテクトでアーキテクチャを作る必要がある。
(著者は、システム設計において最も考慮すべき重要なことは、概念的な整合性だと主張している。)
アーキテクチャとは(実装とはどう違うのか)
アーキテクチャとは、完全かつ詳細なユーザーインターフェイスの仕様であり、それはマニュアルの記載内容である。
アーキテクトはユーザーの目線に立つ。販売や製造の立場ではない。
アーキテクチャは何が起きるか、実装はそれをどう引き起こすか。
時計に例えれば、アーキテクチャは文字盤であり、実装は箱の中の駆動源や精度を保つ仕組みである。ユーザーは、文字盤、つまり、アーキテクチャを理解すれば、時計の中身が違っていても時刻を読める。
他の例:プログラミング言語の仕様はアーキテクチャであり、対応する実装はコンパイラである。
少数にアーキテクチャをまかせて大丈夫な理由
アーキテクト以外が良いアイデアや良い機能を提案しても良い。アーキテクトの仕事は、概念的な整合性のためにアイデアや機能を取捨選択することに重きがある。良い機能がたくさんあっても、概念的な整合性がないのなら、使いやすいシステムではない。
実装の設計もまた創造的な作業である。使いやすさが最も強くアーキテクトにかかっているように、コストパフォーマンスは最も強く実装担当者の創意工夫にかかっている。
諸芸術で言われるように、制約は創造にプラスに働く。アーキテクチャの制約があればこそ、実装担当者は、まだ誰も取り組んでいない目の前の実装に集中でき、その創意工夫が生まれるのである。制約が無いと、アーキテクチャに関することばかりを考え、議論して、実装が進まなくなる。
アーキテクチャの作業時期と実装の作業時期
少数でアーキテクチャを作り終わってから、実装担当者達を投入するのが1つのやり方。このやり方をした場合の見積もりに対して開発期間が長すぎると考え、始めから多くの人員を投入したが、開発期間は短くならず品質は下がったというのが著者の経験である。経験では、アーキテクチャ作りに多数の人が関わり、概念的な整合性が低下すると、テスト期間も延びる。
アーキテクチャが完成する前から実装担当者が出来ることは多くあるので、それを行うというのがもう1つのやり方。プログラムを実行するマシンなどを含めた実行環境を理解する、実行環境に合うアルゴリズムや実装の仕方を検討する、性能目標(処理速度やメモリ消費量)を設定する、必要になるツールを準備するといった作業は、最終的な仕様で実現されるであろう機能の概要だけが分かっている段階からでも始められる作業である。
第5章 アーキテクトの暴走を防ぐ方法と2回目の設計の危険性
アーキテクチャと実装を分離したときに、実装不可能な仕様やコストを度外視した機能をアーキテクトがアーキテクチャに盛り込むのを防ぐ方法として以下のものがある。
アーキテクトと実装担当者の間で、徹底的に、注意深く、そして、思いやりを持ってコミュニケーションを行う。
コストの見積もりを良くする方法として、開発初期から継続してアーキテクトと実装担当者がコミュニケーションを持つことがある。
コストの折り合いがつかないときには、アーキテクトが実装を提案したり、実装担当者がアーキテクチャに対する変更を提案したりしても良い。しかし、アーキテクチャと実装の分離を念頭に置き、相手の領分に対して提案しているのだということや、感情的にならないことに気をつけて行うこと。(これらの注意事項の詳細は、第5章の「Interactive Discipline for the Architect」の項を参照のこと。)
続いて以下は、後述の「The Second-System Effect」を念頭に置いた対策である。
アーキテクトは、設計のしすぎ、つまり、無駄だったり価値の低かったりする機能や仕様を作っていないかについて、自身にとって2つめとなるシステムを設計するときは特に気をつける。
システムの基本的前提や目的が変化していないかに注意する。時代遅れになっている技術の改良にコストを注ぎ込んでしまい、新たに必要になっている技術への取り組みが不足することになっていないかに注意をする。
それぞれの小さな機能に対して、その機能に見合う代償を割り当てておく。例えば、メモリ使用量などの具体的なリソース使用上限を割り当てておく。この割り当ては、実装作業中にもガイドや警報装置として役に立つ。
以下は、プロジェクトマネージャーの立場からの対策である。
既に2つ以上のシステムを設計したことがある人をシニアアーキテクトにする。
無駄な物を作ることに駆り立てる要因を念頭に置いて、設計の詳細がシステムのコンセプトと目的に合致しているかを確認するための質問を考え、投げかける。
The Second-System Effect
2つめのシステム設計は、設計しすぎになりやすく、最も危険である。著者はこれを「The Second-System Effect」と名付けた。 その理由は以下の通りである。
初めてのシステムを設計するときは、注意深く自重しながら設計するものである。そして、初めてのシステムでは見送って、次回、つまり2つめのシステムに取って置かれた事項が溜まるものである。
3つめ以降のシステムを設計するときには、2つ以上のシステムの設計経験があるため、その経験の中からシステムに共通する一般的な性質や各システムで異なる特徴を確認することが出来る。
第6章 仕様を正しく伝える方法
どうすればアーキテクトが決めた仕様の通りに実装が行われるのか。どうすれば多数の人が開発に参加する状況で概念的な整合性を維持できるのか。これらを達成するための技術について概略を以下に示す。詳細は原著のこの章を参照のこと。
仕様書としてのマニュアル
マニュアルは外部仕様書であり、アーキテクトが作成する文章の中で最も重要である。
フィードバックを受けて、マニュアルは開発中に何度も修正される。よって、マニュアルの版と改版日は実装担当者のためにきちんと管理すること。
ユーザーが目にしない部分、つまり、実装の領分については記述しないこと。
アーキテクトが10人いたとしても、マニュアルを書くのは1人か2人にすること。文体の、そして、製品としての一貫性を保つためである。
何が規定されているのかと同じくらい何が規定されていないのかも注意深く記述すること。
形式的記述を用いた定義
自然言語ではなく形式的記述を用いても良い。例としては、プログラミング言語の仕様でよく利用されるBNF(バッカス・ナウア記法)や、PL/Iで行われた形式的記述がある。
形式的記述は厳密だが、仕様がなぜそうなっているかの理由の説明に向かないなどの欠点もある。よって、自然言語との併用が現実的である。
形式的記述と自然言語を併用する場合には、どちらが基本となるものでどちらが派生物なのかを明記すること。どちらのやり方も過去に実例がある。
形式的記述を構文(syntax)以外にも使おうとすると実装に踏み込んでしまいやすい。したがって、形式的記述で規定しているは外部仕様のみであること、そして、その内容が何であるかを明示するよう注意すること。
互換機の開発などで既に実装が存在する場合は、実装を仕様とし、その挙動を確認するテストを用意して、新たな実装をそのテストをパスするように作ることがある。しかし、このやり方には厄介なデメリットがある。例えば、エラー時の挙動などを仕様として規定しすぎる傾向があるのだ。こうした挙動は、しばしば過去に誰からも検討されておらず、別の機種に実装しようとすると処理速度などで問題となるような仕様になりすい。そのため、注意が必要なのである。
アーキテクトによるソースコードのインターフェイス部分の記述
モジュールのインターフェイスに相当する部分をアーキテクトが直接書いても良い。具体的には、関数や変数の宣言を書いたヘッダファイルをアーキテクトが書くのである。これにより、アーキテクチャを守らせることが出来る。
会議と意思決定の工夫
週に1回の会議と半年に1回の会議など、2つの異なるレベルの会議を設ける。
会議の出席者、誰が議長か、議題の種類、進行、焦点、資料などを工夫する。
会議だけでなく、その前後のプロセスや最終的な決定をいつどう行うかなどを工夫する。
始めから複数の実装を開発することが持つ仕様を守る効果
実装が1つの場合は、実装とマニュアルではマニュアルの方が修正が楽である。よって、実装とマニュアルに記述された仕様に食い違いが発生したときに、マニュアルにある仕様の方が変更されやすくなる。
実装が2つ以上あり互換性が必要な場合は、マニュアルと正しく動いている実装を直すよりも間違いのある実装を直す方が低コストになる。結果として、仕様に関して規律や綺麗な状態を保ちやすくなる。
アーキテクチャに対する質問への回答記録の公開
疑問を持った場合に実装担当者がアーキテクトに質問することは推奨されるべきだ。なぜなら、勝手に推測して作業を進めるよりも良いからだ。
この質問と回答を他の人からも見られるような仕組みを作っておくと良い。この仕組みは略式ではあるが迅速で分かりやすい。
製品テスト部門との早期からの連携
設計が適切に理解されていなかったり正確に実装されていなかったりする部分をテスト部門は見つけ出すことが出来る。
したがって、テスト部門にも適切に設計情報が届くようにして、テスト部門が早期に、そして、設計と同時に動き出せるようにすべきである。
第7章 コミュニケーションと組織と文書
コミュニケーションは重要である。そのため、組織が重要である。コミュニケーションを円滑にするためには、電話、電子メール、技術的打ち合わせといったものから、グループ間の依存関係の明確化や文書管理まで、あらゆる手段を活用すべきである。
文書管理
プロジェクトに関する文書は全て一元的に管理し、全ての関係者が必要な情報をすぐに見られるようにすること。それらの文章を管理するツリー形式などの構造は、後々のことを考えて始めから整えておくこと。
あらゆる文書を管理対象とすること。具体的には、目標、外部仕様、インターフェイス仕様、技術標準、内部仕様、管理上の覚え書きなどの文章も対象である。
すぐに更新内容が反映されることが重要である。
更新履歴の管理も必要である。更新履歴は、更新内容の概要と具体的にいつどこがどのように更新されたかの情報を含む。更新履歴によって、最後に読んだ版と最新版との差分の把握が容易になる。
組織
組織の目的は、関係者間で必要なコミュニケーションと調整の量を減らすことにある。
ツリー構造を成している組織を考えたときに、その一部を成している部門の効率性の鍵となるのは技術ディレクターの役割とプロデューサーの役割である。
技術ディレクターの役割は、アーキテクトの担う役割である。ほぼ技術的な仕事で、部門内でのコミュニケーションが中心となる。
プロデューサーの役割は、人や物といった開発リソースを確保したり管理したりする役割である。開発スケジュールを調整する役割も含まれる。部門外とのコミュニケーションが中心となる。
この2つの役割の割り振り方には以下の3パターンがある。どのパターンを採用するかは人材次第である。利用可能な人材に合わせて組織は作るべきなのだ。
2つの役割を同じ人が務めるパターン。このパターンは、両方の役割について能力を持った人材が必要である。また、大規模なプロジェクトでは仕事量の面で1人が両方やるのは無理がある。よって、適するのはプログラマ6人のチームぐらいまでである。
プロデューサー役の人が上司で、技術ディレクター役の人が右腕となるパターン。技術ディレクターの役割に費やす時間を確保するため、その役割の人をマネジメントの指揮系統の連なり(係長、課長、部長、・・・)の中には位置づけないこと。しかし一方で、技術面の権限をきちんと技術ディレクター役の人に確保することが重要。このためにプロデューサー役の人が行うべき工夫の詳細は第7章の「The producer may be boss, the director his right-hand man.」の項を参照のこと。
技術ディレクター役の人が上司で、プロデューサー役の人が右腕となるパターン。要するに第3章のミルズの案。
第8章 見積もり
いくつかの研究によって、ソフトウェアの作成にかかる労力はその規模に対して指数関数的に増大することが示されている。これは開発人員の増加によるコミュニケーションの増加が無かったとしてもである。よって、同一人数で規模が2倍だから作業時間は2倍のような見積もりをしてはならない。
業務時間の全てがプログラミングやデバッグに使えるわけではないことをきちんと考慮に入れて見積もること。機器トラブル、割り込み業務(当該プロジェクトには無関係だが優先度が高くすぐに終わる業務)、会議、事務的作業、社内業務、病欠、私用などで失われる時間も考慮すること。
プログラマ間やシステム部分間の相互作用が多いほど、時間あたりに進められる設計とプログラミングの量が減る、つまり、生産性が下がることが研究によって示されている。
開発内容(OSなのかコンパイラなのかなど)によっても、生産性は大きく異なる可能性がある。開発人数や開発期間にも違いはあるものの、デバック済みプログラムの命令数を人時間で割った値で生産性を比較すると開発内容によって何倍も違いがあることが過去の研究では報告されている。
1人が時間あたりに生産できる要素数(語数や行数)は、プログラミング言語によってあまり変わらないようだ。したがって、開発内容に適したプログラミング言語を用いることで記述量を減らせるならば、人時間も減らせる可能性がある。
第9章 リソース配分の決め方
それぞれのコンポーネントやチームにリソースを割り振るときには、以下に気をつけること。
それぞれのリソースについてバラバラに割り当てを行うのではなく、関連するリソースはまとめて割り当てを考えること。例えば、メモリに入りきらないデータはディスクに置かれることが多いので、メモリサイズとディスクアクセスはセットにして割り当てること。
割り当てを具体的に決める段階では、割り当てを受ける各モジュールが何をしなくてはならないかを正確に決めておくこと。機能の割り振りが曖昧だと、リソースが足りなくなったときに別のモジュールに対する機能の押し付け合いになってしまう。
それぞれのコンポーネントやチームが個別最適やセクショナリズムに陥っていないかに常に注意すること。システム全体を考える態度やユーザー志向の態度をチームメンバーに育ませることが最も重要な管理職の役割だと言っていいだろう。
メモリスペースと処理速度のトレードオフにうまく対処するためにできることとして以下の2つがある。
過去の経験や生まれ持った機転だけに頼らせるのではなく、開発チームにプログラミング技術についてきちんと教育・訓練を受けさせる。新たな言語やマシンの場合は特にそうである。特性やノウハウは、迅速に学ばれ、共有されなくてはならない。
プログラミングにはキュー、サーチ、ハッシュ、ソートなどの技術(テクノロジー)があると認識すること。そして、それらのライブラリ(コンポーネント)を用意することの必要性を認識すること。
メモリ不足で困ったときには、データやテーブルの表現を考え直すとうまく行くことがある。
第10章 マネジメントにおけるドキュメントの構成と重要性
ドキュメントの構成
マネジメントで重要なことは以下の5項目であり、各項目の右側のものが対応する文書である。
何を:目的・目標、製品仕様
いつ:スケジュール
いくらで:予算
どこで:スペースの割り当て
誰が:組織構成図
各文書の内容の詳細は第10章の「Documents for a Computer Product」と「Documents for a software Project」の項を参照のこと。
マネジメントの仕事では、何らかの形のコミュニケーションを行っている時間が長く、頭の中にないデータを必要とする仕事はそう多くない。そのデータが必要な仕事では、一握りの書類が提供するデータが本当に必要なデータであり、また、十分なデータでもある。
ドキュメントの重要性
文書作成は、マネジメントの仕事を進める良い機会である。書いたということは、曖昧にせず、決めたということであり、明確にしたということである。また、書いてみて問題に気づくこともある。
ドキュメントはコミュニケーションの役に立つ。誰かにとって当たり前のことは、別の人にとってはそうではないかもしれない。
ドキュメントは、重点や方針に変更が必要かを見るためのデータベースとなり、またチェックリストにもなる。
組織の構成とその組織が作ったシステムの関係
Conwayの法則:
組織が作るシステムは、その組織のコミュニケーション構造のコピーにしかならない。
Conwayによれば、最初のシステム設計は組織構成図を反映し、そして、ほぼ間違いなく正しくない。
システム設計を自由に変更するならば、組織も自ら進んで変化しなくてはならない。
第11章 ソフトウェアの一生:初期の失敗、メンテナンス、そして終焉
変化と開発
一発で完璧なものを作るのはほぼ不可能だ。失敗した仕様や設計をやり直す機会が開発の過程として存在する計画を始めから立てる必要がある。
顧客の要求・要件も不変ではない。プログラムが作られ、テストされ、使用されていくにつれ、顧客のニーズも考えも変わっていくものだ。
開発の戦略や技術も、開発者が新しく何かを学べば変化していくものだ。
変化に対応しやすくするには、変化を見越した適切な形で、モジュールも、関数も、インターフェイスも、ドキュメントも作成すべきだ。
変化に対応するには、バージョン番号を付けて区切りを設け、バージョン毎にスケジュールと凍結日を付与する必要がある。
変化と組織
設計者がドキュメントを書きたがらないのは、怠惰からでも時間不足からでもない。まだ考える余地があると思いつつ決めたことを文章化したくないという気持ちからだ。何にせよ、もし「批判が来ても大丈夫にしておかないとまずい」というような脅威を感じさせる組織体制になってしまっているならば、完全に防御できるもの以外は何も文章に書かれない。
変化に対応できるシステムを作るよりも、変化に対応できる組織を作ることの方が難しい。しかし、システムに変更があったなら開発体制にも変更が必要だ。
組織の管理形態には工夫が必要だ。実例として、全ての職位を廃止した例もあるし、管理系と技術系で二重の職位階層を設け状況に応じて技術者がマネージャーになったりその逆ができたりする体制を作った例もある。
能力的に可能であるならば、上級職の人は、マネジメントと技術(プログラミング)の両方がいつでも出来る人であり続けるべきである。チームのトップである主開発者が自身の手も動かすという第3章のミルズの案は、このことを可能にする根本的解決策の1つである。
また、ミルズの案では、割り当てる仕事をチーム単位で変更することが比較的容易である。これにより、システムの、そして、それを作っている組織の変更が比較的容易となるのである。
プログラムのメンテナンス:2歩進んで1歩下がる
広く利用されているプログラムをメンテナンスするコストを合計すると、典型的には開発コストの40%以上になる。
副作用の見落としなどにより、ある不具合の修正が別の不具合を生むことがままある。ソフトウェアの構造がまったくきれいなままだったり、ドキュメントが非常に良かったりでもしない限りは、遠くに及ぶ副作用には見落としが発生するだろう。
完璧な回帰テストは理想だが、それを実現するためのコストはとても高い。
副作用がより少なくなるように、もしくは、よりはっきり分かるように開発すれば、メンテナンスコストを大幅に削減できる。つまり、少数の人員で少数のインターフェイスになるように設計すれば、バグは少なくなる。
プログラムの終焉:1歩進んで1歩下がる
ある研究では、モジュールの総数がリリース番号に比例して増加した一方で、影響を受けるモジュールの数はリリース番号に対して指数的に増加したことが観察されている。
修正を重ねていくにつれ、ソフトウェアに元々あった構造は失われ、混沌とした状態になっていく。そして、不具合修正によって発生した不具合の修正だけで手一杯になっていき、ソフトウェアはいつしか進歩しなくなる。
その上、時が経つにつれ、ハードウェアは変わり、ユーザーの要求・要件も変わっていく。事実は、ソフトウェアは永久には使えないということである。新しいソフトウェアを一から作るときがいつか来るのである。
こうして、ソフトウェアはその寿命を終える。
第12章 機材やツール、ソース管理など開発の道具立てについて
ツールを個人的に抱えこむのは良くない。個人的ツールはコミュニケーションなどの問題を生む。また、開発対象や開発環境は変わっていくので、適切にメンテナンスされていないツールは寿命が短いことにも注意が必要だ。
汎用的な開発の道具立て(機材やツールなど)については、共通化した開発とメンテナンスを行うべきだ。一方で、チームの特性や好みに合わせてツールを用意する担当者を、第3章のミルズの案のように、各チームに置くべきだ。そのツール担当者は、全ての共通ツールについて習熟していて、その使い方をチームメンバーに教えたり、チームに必要な特殊なツールを作ったりするのだ。
よって、プロジェクトマネージャーは、共通ツールと各チームの特殊ツールの両方の開発に対応した体勢とリソース配分を行うべきだ。各チームにツール担当者を置かず、1部署に集めてしまうやり方はうまくいかない。
管理が必要な道具立ては、ユーティリティと呼ばれるようなツールやデバッグやテストのためのツールだけではない。コンピュータなどの機材とその利用スケジュールや、開発に使う基本ソフトとそれにより利用できる機能についての基本方針(service philosophies)、プログラミング言語とその言語の利用ポリシーなども管理が必要である。
機材の利用スケジュールの管理は、まだ量産されていない新しいハードウェア向けに開発しているときなどは、特に必要である。
OS/360の開発では、機材の利用時間の割り振り方として、時間枠を余り細かくせずにまとまったブロックとして割り振った方がうまく行った。
新ハードのためのソフト開発では、2つの点でシミュレータの価値は大きい。1点めは、新ハードの実物が出来上がるずっと前からデバックを開始できること。2点めは、開発に伴い日々変更される新ハードの実物よりシミュレータの方が安定していること。ハードの不良、たいてい出たり消えたりするその不良や、しまいには何が何だかよく分からない挙動は、デバッグをするやる気を失わせるので、安定したシミュレータは思ったより長期にわたって重要だ。
クロス開発において、ターゲット向けではなく開発マシン向けにコンパイルし、それで出来る範囲のデバッグをしてしまうのは効率的なやり方だ。
ソースコードなどは、きちんとバージョンを管理すること。また、その管理では、各人での開発、とりまとめ(integration)、リリースの各段階がきちんと区別されていること。そして、とりまとめやリリースの段階にあるものを変更できるのは、その権限を持った人のみとすること。
マニュアルなどの文書を管理するシステムは、きちんと整備・運用すること。
パフォーマンスシミュレータはあった方が良い。とても早い時期から取り組むこと。また、シミュレーション結果には真摯に向き合うこと。
高級言語や対話型プログラミングは良い道具だ。(高級言語の有用性や、バッチ処理に対する対話的な(インタラクティブな)機能の有用性は、当時とは違い既に広く認められていると思うので、それらの有用性について書かれた詳細は省略する。)
第13章 設計とテストとデバッグの戦略
バグが入らないように設計する方法
第4、5、6章で議論した概念的な整合性(conceptual integrity)のためのアーキテクチャの努力を行い、仕様や定義を出来る限り明確にし、書き手によって暗黙の前提が違っていたというような事態を避けること。
コーディングのずっと前に、テストチームに仕様を渡し、不足やあやふやな点がないか綿密に調べてもらうこと。
トップダウンで設計すること。つまり、全体の構成から小さな部分に向かって、いくつかのステップに分けて設計を行うこと。各ステップでは、出来る限り高レベルの表記を用い、現ステップでは不要な詳細は隠すこと。このトップダウンの過程の中で、他から独立して詳細が設計できるモジュールを見いだしていくこと。
詳細の設計で困難な問題が見つかった場合など、必要な場合はステップをさかのぼってやり直すこと。
テストとデバッグ
コンピュータを動かしてデバッグ作業をする前に、どのようにデバッグするかの計画を立てるべきだ。デバッグ作業の後には、ログの保存や分かったことを記録するなどの後始末を行うべきだ。
システムテストには、デバッグ済みの、つまり、バグを見つけて修正した後のコンポーネントを用いること。バグが残っているコンポーネントを組み合わせてテストするのは著しく効率が悪い。
テスト期間中もソースコードなどのバージョンをきちんと管理すること。こうすることで、変更を全て記録し、応急的な修正と正式な修正の区別が付くようにすること。
システムテストでは、コンポーネントを1つずつ足していくこと。つまり、全てがダミーのものである状態から始めて、1つずつ本物のコンポーネントに交換していくこと。追加の際は、追加コンポーネントのテストだけでなく、実施済みのテストも再度行うこと。つまり、追加の際は回帰テストも行うこと。
既にシステムテストへ追加済みのコンポーネントを更新する場合も、1つずつ交換して回帰テストを行えば良い。
それぞれのコンポーネントの開発チームがテストベッドとして共通に使うバージョンは、頻繁に変更しない方が良い。このバージョンは、統合テストが終わっているものの中で最新のものが基本となるが、バージョンとバージョンの間を広く空けて、その間にまとまった量の改良や修正が入るようにするべきだ。このテストベッドの変更は少なからず作業を遅らせるので、効率的に開発できる安定した期間を増やすためには、間隔を広く取る必要がある。例えば、応急的な修正は定期的なタイミングを待って共通テストベッドバージョンに取り込むことにして、このときまでにはテストと文書を伴った正式な修正にしておくというやり方がある。
第13章に関する補足事項
(設計・テスト・デバッグの良い手法が載っているとして、第13章では参考文献が複数挙げられている。)
(第13章の「Structured programming」の節に書かれている主張は、多くのプログラミング言語に取り込まれ、一般化したと思われるので省略する。)
(第13章の「Component Debugging」の項では、デバッグ手法の歴史的変遷が述べられており、これまでに登場したsupervisory programなどの名称が具体的に何を指すのか、また、本書の文章が書かれた当時の技術的前提がどのようなものであるかなどを理解するのに役立つ。)
(第13章の「Build plenty of scaffolding」の節では、テストやデバッグのための足場(scaffolding)の具体例が書かれている。)
第14章 スケジュールが破綻する原因とその対策
Q. どうしたらプロジェクトが1年も遅れるのか?
A. 1日ずつが重なって。
ちょっとしたことによる半日や1日の遅れが積み重なってスケジュールは大幅に遅れていく。例えば、病欠、故障、納入待ち、雪、裁判員、家庭の事情、緊急顧客対応、社内監査、などなどが積み重なって遅れるのである。
マイルストーンの文言
マイルストーンに設定するイベントは、刃先のような鋭さで、具体的、明確、かつ、判定可能でなければならない。
悪い例
コーディング90%完了
デバッグ99%完了
計画完了
良い例
アーキテクトと実装担当者が署名済みの仕様書
コーディング100%完了、バージョン管理システムにコミット済み
デバッグ版が全てのテストケースをパスする
マイルストーンが非常に明確で曖昧さが無いことは、上司がその完了を簡単に確かめられるかどうかよりも重要だ。マイルストーンが非常に明確であれば、ごまかそうとする人はそうはいない。逆にマイルストーンが曖昧だと、報告者の意図と異なる都合の良い形で上司が報告を理解することがよく起こる。
複数の事例を用いた研究では以下3点が見いだされている。
2週間毎に慎重に更新されている作業時間の見積もりは、その作業の開始時期が近づくにつれてあまり変動しなくなる(見積もりの落ち着いた先が、実際の作業時間と比較してどの程度正しいかは別として)。
過大だった見積もり時間は、作業に入るとその期間を通して徐々に短くなる。
過小だった見積もり時間は、作業に入っても完了予定の3週間前になるまではあまり変動しない。
マネージャーは鋭いマイルストーンを設定すべきである。曖昧なマイルストーンは、投入済み作業時間に関して誤った印象を与え続け、回復不能な状態に至らしめる。その結果、スケジュールの遅れは慢性化し、チームのやる気は失われる。
PERT図やクリティカルパススケジュールの利用と「ハッスル」
これら(PERT図やクリティカルパススケジュール)の利用により、遅れるとプロジェクト全体の遅れに直結するタスクを特定でき、また、現在直結しないタスクでもどれだけ遅れるとその遅れが全体に直結するようになるのかが判明する。また、遅れを別のところで挽回する方法を考えるときの資料を得ることにもなる。
これらを利用するには、プロジェクトの最初期に非常に具体的な計画作業を大量に行う必要がある。しかし、このこと自体に最も価値がある。
これらの利用は必要ではあるが、こういう類いの計算や計測は「ハッスル」を鎮める作用があることには注意が必要である。ここでいう「ハッスル」はスポーツで言えば必要以上に速く走ったり必要以上に挑戦したりする類いの行為である。「ハッスル」は優れたプログラミングチームには不可欠なものだ。なぜなら、「ハッスル」した結果として生まれる余裕が小さなトラブルへの対処を可能にし、遅れが1日ずつ積み上がっていくのを防ぐからである。
現場から適切に情報が上がるようにするには
現場の管理職からさらに上位の管理職へ全ての情報が伝えられる必要は無い。しかし、教育に関する状態を把握するための情報と計画に無く処置が必要なことに関する情報は、上位の管理職が必要な情報である。そして、何も対策をしないと必要な情報であっても上に伝えられず隠されてしまう。
対策1 役割の衝突の緩和
この対策の1つめは、上下の管理職の間で役割の衝突を和らげることである。
下位の管理職が解決できる問題に対して上位の管理職は手を出さないよう自制しなくてはならない。
また、明らかに状況の検討を行っている最中は、問題解決への行動を上位の管理職は決して起こしてはならない。例えば、報告書を1段落も読まないうちに受話器を上げて指示を出すようなことはしてはならない。こういう対応をすると、情報は隠されるようになる。逆に、上司が報告を受け取ってもパニックや下を無視した行動を起こさないと知っていれば、部下は正直な現状の評価を報告するようになる。
会議の類いを状況検討と問題解決のどちらかに分類し、上位の管理職がそれに応じて自制することは、この対策の助けになる。状況検討会議と問題解決会議を順に経るなら、少なくとも状況は皆が知ることとなり、そして、上位の管理職は問題に踏み込む前に2回は考えることになる。
対策2 マイルストーンレポートの作成
この対策の2つめは、マイルストーンとその完了状況を一覧にしたマイルストーンレポートを定期的に作成することである。
マイルストーンレポートに2種類の予定日を併記するやり方は有効な可能性がある。1つの予定日は、プロジェクトマネージャーが管轄する予定日であり、プロジェクト全体の計画の視点からスケジュールされる。もう1つは、各マイルストーンに対応する現場の管理職が管轄する予定日であり、見積もりの正確さに重点が置かれる。後者の日付に対してはプロジェクトマネージャーは手を出してはならない。
進捗管理の専門チームを設けるのは大規模開発では非常に価値がある。人数は1から3名で、管理職の仕事である進捗管理を事務面で補佐する。具体的には、各マイルストーンの状況確認やPERT図の更新などを行う。この専門チームの持つ権限は、マイルストーンの追加や変更がないか、また、既存のマイルストーンで完了したものがないかを、現場の管理職に尋ねる権限だけである。この専門チームの働きにより管理職は決定を下すことに集中できる。
第15章 人間がプログラムを理解できるようにドキュメントを書く
プログラムを書いた人自身にとってすらドキュメントは重要である。なぜなら、未来の自分はその詳細をたいてい忘れているからだ。
良いドキュメントを作る癖を付けさせるには、何よりもそのやり方を実際に見せることだ。怠惰や時間の無さを克服するための心構えを新人プログラマにたたき込むようなやり方は、概ね失敗に終わってきた。
ドキュメントに必要な記載内容
それぞれの記述項目の詳細は第15章の「What Documentation Is Required?」の項を参照のこと。
プログラムを使用するときに向けて
概要の記述が不足しないように気をつける。全体像から始めて詳細な説明に至る流れに気をつける。
書くべき記述項目は以下の9つ。用途目的、動作環境、入出力データの範囲、実現される機能と利用されているアルゴリズム、入出力の形式、操作方法(異常終了における挙動の説明も含める)、選択可能事項(options)、実行時間、計算精度とその確認手段
簡潔さと正確さに気をつける必要はあるが、これら9項目は大概3、4ページで記述できる。
これら9項目のドキュメントの大半はプログラムを書き始める前に草稿を用意するべきである。なぜなら、これらは、計画における基本的決定事項を具体化したものだからである。
プログラムが正常か確認するときに向けて
プログラムが壊れていないかや正しく動くかを確認できる小規模なテストケースがユーザーに提供されるべきだ。
また、修正後に走らせる徹底的なテストも必要であり、これは主に3種類に分けられる。
主要ケース(Mainline cases):主要な機能を典型的なデータでテストするもの。
ぎりぎりで妥当なデータ:入力として認められているぎりぎりの値でプログラムが適切に機能するかテストするもの。テストに使う値は最大値や最小値、例外的な値ではあるが入力として認められている全ての値などである。
ぎりぎりで妥当でないデータ:入力として認められない値が来たときに、適切なエラーメッセージが表示されるかテストするもの
(回帰テストという言葉を著者は用いていないが、修正後に走らせる徹底的なテストは回帰テストと考えて良いだろう。また、2と3のテストは境界値テストと捉えても良いだろう。)
プログラムを変更するときに向けて
プログラムを変更したり修正したりするときには、内部構造を始めとしたプログラムの完全な詳細情報が必要となる。この中でも特に概観(overview)に関する情報が重要であり、これは以下の5つからなる。また、これらの情報は、コメント使ってソースコードに統合することが可能である。
フローチャートまたはサブプログラム構造図(フローチャートについては後述の点に注意。また、サブプログラム構造図がどのような図であるかは第15章の「The Flow-Chart Curse」の節とFig. 15.1を参照のこと。)
アルゴリズムの完全な説明、もしくは、それが記載されている文献の情報
ファイルレイアウトの説明
記憶デバイスなどからのデータ移動経路の構造の概観と各経路で何が完了するかの概観
元の設計の観点から考えた修正に関する議論、プログラムの起点(hooks)と終点(exits)の性質と位置、プログラムを最初に書いた人がどのような修正が望ましくそれをどのように行おうと考えていたかについての広範な議論、及び、隠れた危険についての所見
フローチャートはほとんど必要ない
フローチャートはまったくもって過大評価されている。多くのプログラムはフローチャートを全く必要としないし、必要があったとしても多くは1ページに収まるフローチャート1つで十分で、それ以上を必要とするプログラムはほとんど無い。
読み手に全体像を分かりやすく示す1枚の図が重要なのであって、フローチャートという形式にとらわれる必要は無い。ましてやフローチャートの規格や標準にある細かな規則は1枚の全体図を書くときには必要無い。
高級言語で開発するなら逐一の詳細を記したフローチャートは不要である。逐一のフローチャートは、歴史的には、アセンブラ言語での開発のために導入されたものである。体系だった高級言語で記述されたソースコードと比較して逐一のフローチャートが役立つのはGOTOの行き先を示す矢印ぐらいである。
プログラムを書く前に詳細なフローチャートを作成することが規則となっている現場で、経験豊かなプログラマが実際にそうするのを見たことがない。また、多くの現場で、ソースコードからフローチャートを生成するプログラムを使っている。こういうことは、恥ずかしいとか嘆かわしいとかいうよりも、良い判断が行われていると言うべきである。諸先輩方も私たち自身も達成できなかった時代遅れの慣行を新人プログラマに背負わせるべきではない。
ソースコードとドキュメントはなるべく1つのファイルにまとめる。
ソースコードに出てくる(変数名や関数名といった)名前は、最大限読み手に意味を伝えられるものにすること。
インデントを適切に行って従属関係や入れ子(nesting)を分かりやすくすること。
まとまった量の文章からなるコメント(paragraphs of comment)をソースコードにしっかり記述すること。組織が堅苦しい規則を設けている場合は特に、行単位のコメントが過多で、この文章からなるコメントが不足していることが多い。
どうなっているかよりも、何故そうなっているかを書くこと。目的 が理解の鍵である。高級言語の構文でさえも目的を伝えることは出来ない。(第18章の15.14より)
1つのファイルにまとめる利点
ソースコードとドキュメントを別々のファイルにすると、同期を取って不整合が起きないようにするのが難しくなる。1つのファイルにするならこの問題が起きにくい。
ソースコードを書くと同時に必要なドキュメントを書くことがやりやすい。
ソースコードに書いてある変数名やデータ構造を別のドキュメントに丸写ししなくて済む。変数宣言と同じ行にその説明のコメントを書くような場合にこの利点は顕著である。
第16、17章 本質的な難しさのため、生産性・信頼性・単純さ(simplicity)のどれにおいても劇的な改善をもたらす特効薬は存在しない
(これらの章における「本質的」といった言葉の用法について、17章の「Accident」の項で著者は補足をしている。著者は実装作業を本質的でない仕事に分類しているが、実装作業を軽視しているわけではない。開発の難しさを2種類に分けて考えたということが要点である。)
データとその関係性、アルゴリズム、及び、機能(functions)の呼び出しという相互に影響を与える概念で構成される複雑な構造を創り出すことがソフトウェア開発において本質的な仕事である。メモリサイズや計算速度といった様々な制約を満たしながらプログラミング言語を用いてその構造を実装する作業は本質的な仕事ではない。
ソフトウェア開発で難しい点は、概念的レベルの構造に対する仕様、設計、及び、テストであり、実装作業や実装が忠実に行われているかのテストではないと、著者は信じている。もしこれが正しいならば、ソフトウェア開発はいつまで経っても難しいままであり、特効薬は根本的に存在しない。
高級言語、タイムシェアリング、プログラミング環境によって本質的でない仕事を減らすことには成功してきた。
残っている仕事のほとんどが本質的な仕事であるならば、本質的でない仕事を例え完全に無くしたとしても、大幅な改善にはならない。
単独で大幅な改善をもたらす特効薬のようなものは見当たらないが、複数の革新を地道に積み上げていくことで大幅な改善を達成できるはずだ。
ソフトウェアの本質的な難しさ
複雑さ
ソフトウェアは本質的に複雑である。
自動車や建築物にあるような同じ部分の繰り返しがない。なぜなら、同じ処理は1つのサブルーチンにまとめられるからだ。
状態数(numbers of state)が多い。
ソフトウェアにおけるスケールアップは、比例させて単純に大きさを何倍かにすることではなく、要素の数を増やすことだ。多くの場合、それらの要素は比例よりも複雑な形で相互影響するため、ソフトウェア全体は規模に比例する以上に複雑になる。
この複雑さが開発もマネジメントも難しくしている。
複雑さ故に概要を理解するのも難しい。ソフトウェアの説明から複雑さを除こうとするとたいてい本質的な部分まで除いてしまうことなる。
この複雑さは学習と理解のための莫大な負担を生む。そして、その負担は人員交代を大惨事にしてしまう。
周りに合わせることを要求されること
多くの場合、既存のややこしい仕組みやインターフェイスに従ってソフトウェアを作る必要がある。
その既存のもののややこしさの大半は、物理法則のようなものではなく、気まぐれで作られた何の道理もないものである。そして、そのややこしさは様々な人々によって作られ異なっているのだ。
ソフトウェアの方が従わなくてはならない理由
最も後から登場したから
最も従わせやすいと思われているから
いかなるケースでも、多くのややこしさは他のインターフェイスに従うことから発生している。よって、この多くのややこしさは、ソフトウェアを単独で再設計したところでどうにもならない。
頻繁な変更
顧客に渡った製品に手を加えることが最も多いのはソフトウェアである。建物・自動車・コンピュータハードウェアのどれよりも頻繁に変更が行われる。
変更が多い理由の一部
機能という最も変更を要求されやすいものをシステムの中で体現するのはソフトウェアである。
ソフトウェアは他の物と比べて変化させやすい。建物も実際に変更されるが、変更のコストが高いことを皆分かっており、それが気まぐれな変更を防いでいるのだ。
成功したソフトウェアは変更される。
機能拡張が要望される。
その長い寿命の間にハードウェアが変化していく。
目に見えない
ソフトウェアは目に見えないし、視覚化することも出来ない。
ソフトウェアの構造を制約し単純化する方向には進んでいるが、本質的に視覚化不能なままである。その構造全体を1枚(1種類)の図で表すことはできない。また、その構造はたいてい平面的でも階層的でもない。(図にするのに適したそういう性質を持った構造になっていない。)
本質的な難しさへの対策
既製品のソフトウェアを買う。
どんなソフトウェア製品でも、それを一から作るよりは買う方が安い。しかも、即座に手に入る。さらに、ドキュメントや保守が優れている場合も多い。
根底にあるのは、 n 人のユーザーで同じソフトを使えばユーザーあたりの開発コストは 1/n になることである。別の見方をすれば、n の数のコピーが利用されるならば、開発の生産性も n 倍になるということである。
パッケージソフトを1つのコンポーネントとして利用する。
(以下、第19章の「Buy and Build - Shrink-Wrapped Packages As Components」より)
ソフトウェアの生産性を根本的に向上させるには、より高いレベルでモジュールやオブジェクトを組み合わせて作るしかない。
既存のパッケージソフトを1つのコンポーネントとして他と組み合わせ、より機能が多くよりカスタマイズされたシステムを作るやり方は方向性として有望だ。
ただし、1つのパッケージソフトを中心としたカスタマイズや拡張では間に合わず、複数のパッケージソフトを連携させる必要がある場合には、それぞれのパッケージソフトが連携に適したインターフェイスを持っていることが必要となる。
ラピッドプロトタイピングを用いて仕様の改良を繰り返し行う。
何をつくるべきか、つまり、顧客の要求が何なのかを明らかにすることは開発で最も難しい部分だ。
実際にソフトを作って顧客が実際に試すことを1回もしないうちに、完璧な仕様を作ることは不可能だ。
よって、プロトタイプを作り、顧客に試してもらって、仕様を繰り返し直していくことは重要である。ここでいうプロトタイプは、重要なインターフェイスと基本機能だけは動いて基本的な作業だけはできるソフトウェアである。
このための手法とツール、つまり、プロトタイプを作って仕様を直していくサイクルを回すための手法とツールは、本質的な難しさへの対策として最も有望なものの1つである。
育てるように少しずつソフトウェアを作っていく。
ソフトウェアを建築物にたとえて、事前に正確に設計して欠陥無く作れると考えるのは止めよう。むしろ生き物を育てることのようにソフトウェア開発を考えよう。
まずダミーを呼び出すだけだが動きはするプログラムから始めて、そこに肉付けをする形でソフトウェアを作っていこう。
このアプローチを取ることで、トップダウンで設計することやプロトタイプを作成することにもなる。また、常に動くシステムが手元にあることになる。そして、動くシステムは開発者にやる気を出させる。
優れた設計者を育成する。
ソフトウェアの設計において、ダメな設計と良い設計の違いは設計手法かも知れないが、良い設計と優れた設計の違いは設計者が優れているかどうかである。
設計者の違いの影響は小さくない。平均的な設計者と優れた設計者では10倍近い差がある。歴史的にも、Unixのような胸をわくわくさせるようなソフトウェアの多くは卓越した設計者が1人か少数で設計したものである。
優れたマネージャーも足りないが、優れた設計者はもっと足りない。優れたマネージャーを見つけたり育てたりするのと同じく、優れた設計者を見つけ育てる努力をするべきであり、組織はそのための仕組みを用意するべきである。(そのための具体的な著者の提言は「Great designer.」の項を参照のこと。)
17章で触れられているその他の対策
p. 210 後ろから2段落目:再利用と交換とが可能なコンポーネントによるアプローチ。
p. 212 2段落目の列挙:階層化されたモジュールやオブジェクトによってソフトウェアを作っていく。
pp. 222-225 ソフトウェアの再利用は対策になり得る。数学用のソフトのように、専門用語により機能の特定が容易で、かつ、作るのが難しいソフトは、新しく作るよりも既存のコンポーネントを探す方がコストが低いことが明白であり、実際再利用が行われている。しかしながら、そのような再利用に向いた分野は限られている。そうでない分野では、再利用可能なソフトウェアコンポーネントを作ることがそもそも難しい。再利用のためには、どの部分に汎用性があるかを適切に見極め、さらに良い設計と素晴らしいドキュメントが必要である。当然、再利用しないソフトに比べ開発コストは上昇する。作る難しさだけでなく、さらに、再利用可能コンポーネントを使う難しさもある。プログラミング言語の機能を組み合わせて実現されたコンポーネントは、言語の機能よりも当然複雑になる。よって、どのコンポーネントをどのように使えばどのようなことができるかを利用者は学習する必要がある。したがって、この学習を容易にする方法の研究が必要である。
まとめ作成者の個人的メモ
p. 186 最後の文:高級言語の改良もある程度を越えると、高級言語の複雑な構成要素をめったに使わない人にとっては負担となる。
p. 190 人工知能には期待していない。なぜなら、異なる分野で共通に利用できる技術が少なく、それぞれの分野・問題に応じた作業が大半であるからだ。また、人工知能であることがプログラミングの実践の中に大きな違いを生んでいるようにも見えない。
p. 193 微分方程式の解き方のような問題、つまり、いくつかのパラメータで記述され、解法が十分研究されているような問題においては、ソースコード生成システムは強力だ。
p. 194 グラフィカルプログラミングまたはビジュアルプログラミングからは素晴らしい成果は出てこないだろう。なぜなら、前述の通りソフトウェアは視覚化するのが難しいからだ。
p. 195 プログラム検証(verification)は余りに労力がかかるため、内容のあるプログラムはほんのわずかしか検証されてこなかった。しかも、難しいのは適切な仕様を探し出すことであるのに、プログラム検証が出来ることはプログラムが仕様に合っているかの確認だけである。よって、検証技術は特効薬にはならないだろう。
p. 219 電動ドリルや電動ノコギリのようにカスタマイズできて様々に使えることはパッケージソフトにとって重要である。なぜなら、それによってエンドユーザーが自分のしたいことがパッケージソフトの組み合わせで出来るかもしれないと思うようになり、パッケージソフトを使うことに抵抗感がなくなるからである。多くのケースで、カスタムソフトの方が良いとパッケージソフトに抵抗するのは、ソフトウェア関係者ではなくエンドユーザーである。
オブジェクト指向プログラミングについて
p. 189 最後の段落:オブジェクト指向プログラミングは、設計の表現の難しさという本質的でない難しさしか取り除けない。
p. 221 James Cogginsの意見より:小さなカプセル化は小さな利益しかもたらさないので、粒度が大きいクラスが重要である。そして、その大きなクラスの設計には、顧客(ユーザー)の知見が重要であり、そのため、顧客の協力が重要である。
p. 221 David Parnasの意見より:オブジェクト指向はソフトウェア設計(design)の1種類として教えられるべきだったのに、特定のツールを使うことがオブジェクト指向だと教えられてしまった。その結果、人々は、オブジェクト指向言語を使ってまずい設計を行った。
p. 273 (第19章より)再利用できるように設計されテストされたクラスライブラリは、第1章で述べたプログラム製品に類するものであるという事実について、多くの人々は無視することを選んだ。汎用的で、頑健で、テストされ、ドキュメントも付いた製品相当の品質を持つクラスを作るための初期コストを支払わないまま、クラスのかなりの再利用を無駄に願う人々もいる。 (第1章で著者は、単なるプログラムに比べプログラム製品は少なくとも3倍のコストがかかるとしている。)
第19章 人月の神話を発表した後の20年を振り返って
ウォーターフォールモデルは間違っている。
ウォーターフォールモデルの前提にある誤った考え
アーキテクチャや実装の設計には問題が無く、全ての失敗はそれらを具現化するときの作業で生じるものであり、全ての失敗は単体テストとシステムテストの期間に修正できると想定している。この想定は誤りだ。
全行程を1度だけ行うことを前提にしている。そのため、システムテストや実際のユーザーによる評価が最終盤に行われることになる。その結果、使い易さやパフォーマンス、エラーや悪意を伴った操作への耐性などの問題は、最終盤に見つかることになる。なお、実際のユーザーによる評価を、何かに置き換えることは不可能だ。序盤での仕様の検査に置き換えることも当然できない。
全ての設計、ほとんどのコーディング、及び、多くの単体テストを終えた後に、端から端までシステムテストを行うために、部品を合体させる、つまり、システムを一度に作ることを想定している。実際には、以下で示すように、インクリメンタルな作り方の方が優れている。
ウォーターフォールモデルが広まった背景とその後
ウォーターフォールモデルは、全ての軍用ソフトウェアに適用されるアメリカ国防総省の規格であるDOD-STD-2167の中へと祭り上げられてしまった。
そのため、思慮深い専門家のほとんどが不適切さに気づき使用を止めた後でも、ウォーターフォールモデルは長く残ることになってしまった。
アメリカ国防総省自身も、1988年の改訂版であるDOD-STD-2167Aでは、スパイラルモデルなどのより新しい開発モデルの使用を認めた。ただし、実際の調達の大半ではウォーターフォールモデルが使われ続けていることが報告されている。一方で、米国国防科学委員会は、1994年の報告書において、より現代的なモデルの全面的な使用を支持している。
上流工程へのフィードバックが必要だ。
実装の設計で分かったことによりアーキテクチャのやり直しが必要になることもあるし、コーディングで分かったことによりアーキテクチャや実装の設計に変更が生じてもおかしくはない。
コーディングの前に、アーキテクチャと実装の間の設計サイクルを2回以上繰り返すのは筋の通ったやり方だ。
インクリメンタル開発、つまり、少しずつ追加しながら作るやり方の方が優れている。
インクリメンタル開発の方法
最初は、メインルーチンから空のサブルーチンを呼び出すだけのようなプログラムを作る。つまり、実質的には何もしないが、コンパイルして、走らせて、正しく動作したこと(空のサブルーチンが意図したように呼ばれたこと)を確認できるものをまずは作る。
次に、基本的機能のみを持った入力モジュールや出力モジュールを1つずつ作って追加していく。つまり、機能を1つずつ作って追加していく。
全ての基本的機能が動くようになったら、今度はモジュールを1つずつ少しずつ改良していく。
インクリメンタル開発の利点
常に動くシステムがあるので、ユーザーによる評価を極めて早期に開始できる。
常に動くシステムがあるので、予算の分だけ作るという戦略を採用できる。これにより、機能不足との引き換えになるかもしれないが、スケジュールや予算の超過を完全に防ぐことが出来る。
入念に努力して開発を進めていれば、デバッグとテストが完了したシステムが常にあることになる。ただし、システムが増大するにつれ、回帰テストも増大することに注意。
動くシステムを早期に見ることは士気を大いに高める。
マイクロソフトのデイリービルド
プログラマとテスタで構成されるチームを複数設け、このうちの1チーム以上が、毎日、新機能と共にモジュールをチェックインする。
毎晩、開発中のシステムをビルドしてテストを走らせる。
ビルドしたものが壊れていたら、問題が判明して修正されるまで、プロセス全体を止める。
全てのチームメンバーがその状態を常に知っているようにする。
モジュールやクラスの内部はそれらの利用者には隠すべきだ。
本質的な難しさに取り組んで生産性を上げる方法の1つは、プログラム言語の1文より大きな概念的まとまり、つまり、サブルーチンやモジュール、クラスなどでプログラムを組み立てることである。すなわち、それらの概念的まとまりを事前に作りそろえておいて、それらにパラメータを与えて組み合わせるだけでプログラムができるようにするのである。
このアプローチの重要な源流はカプセル化の考えであるので、モジュールやクラスの内部に相当するコードは隠し、上手に定義したインターフェイスだけをモジュールやクラスの利用者に公開すべきである。また、内部を隠すことにより、変更に強いプログラムになる。
ただし、このようなモジュールやクラスは、第1章で述べたプログラム製品に相当する。製品相当の品質を持つ再利用可能なモジュールやクラス、つまり、汎用的で、頑健で、テストされ、ドキュメントも付いたそれらを作るのは単にプログラムを作るのに比べコストが大きい。(第1章で著者は、少なくとも3倍のコストがかかるとしている。)
成功するかは、ほとんど人にかかっている。
成功に導く要因として、人員の質とその人員による組織とマネジメントが、ツールや技術よりも重要であると著者は確信している。
BoehmのCOCOMOモデルによれば、チームの質が他を引き離して成功のための最大要因である。
DemarcoとListerは、著書である「Peopleware: Productive Projects and Teams」で、同じ組織で働くプログラマの生産性と不良発生レベルの両方がオフィス環境と相関を持つことを実データを用いて示した。
自ら経験したり注視したりしたのは6例ほどだが、ある研究所から別の研究所にプロジェクトを移して成功した例を見たことがない。全ての場合で新しいチームは最初からのやり直しになっていた。DemarcoとListerは、無形だが不可欠な資産としてチームのfusion(融合または結束と訳せるか)にかなりの注意を払っている。プロジェクトの移動は、前のチームにあったfusionを破壊してやり直しをもたらすのではないだろうか。
まとめ作成者の個人的メモ
p. 257 システムの規模がとても大きく、1人のアーキテクトでは対応できない場合は、いくつかのサブシステムに分割して複数人のアーキテクトで分担する必要がある。この分割では、サブシステム間のインターフェイスが最小になるように、かつ、インターフェイスを厳密に定義するのが最も容易になるように分割するべきだ。
p. 258 市場から要求があるのだからと機能を盛り込んでいくと、バージョンアップのたびに、使いづらく遅いソフトウェアになっていってしまう。対策としてターゲットとするユーザー像を文字にしてアーキテクトの間で共有することが必要だ。そして、実際にどんな属性を持ったユーザーがどのように分布しているかを調査するのは困難なので、分布は仮定してしまうのが良いやり方だ。なぜなら、分布を仮定するための思考と議論は、状況を分析する作業とユーザー像を共有する作業として、それ自体が有益だからである。
pp. 260-264 GUIの発展と概念的な整合性(conceptual integrity)
pp. 268-269 Parnasのプログラムファミリーの概念は、インクリメンタル開発に応用できるかもしれない。
pp. 270-271 Harelの定義によれば、プロトタイプとは、概念的モデルの準備工程で行われた設計上の決定事項のみを反映し、実装への考慮が主導する決定事項は反映しないプログラムである。この定義に従った場合、インクリメンタル開発における早期のユーザー評価とプロトタイピングは、関係はしているが別物であり、片方だけを行うことも可能である。例えば、製品の一部には全くならないプロトタイプを作って、早期にユーザーの評価を得ても良い。逆に、インクリメンタル開発において、最初の節目のビルドが、ユーザー評価に使えないものであっても良い。ちなみに、プログラムの代わりに人間がシステムの応答をシミュレートしてもプロトタイピングは行える(Wizard of Oz technique)。また、早期にパフォーマンスの解析を行うために部分的なプログラムを作ることもあるだろう。
pp. 277-279 上の組織が権限を手放してより下の組織に渡し、仕事の進め方やスケジュールを下の組織に任せることは、個人の創造性と自主性を高めることにつながる。マイクロソフトやIBMでは実際にこういった取り組みが行われており、成果が上がったという証言もある。
pp. 279-282 20年を振り返って最も驚くべきニュースである何百万台ものコンピュータの普及に関して、その社会に与えた影響とソフトウェア開発に与えた影響の考察。
コンピュータの普及にも当てはまる3つの重要なこと。1.誰もが使えるくらいに安いこと。2.ちょっとしたことのために使えること。3.人間の創造性への欲求と相性が良いこと。
p. 283 汎用的な手法や言語には向かわず、データベース問い合わせ言語に代表されるようなニッチな分野それぞれに合わせた手法や言語で開発を行う方向へ、昔からのソフトウェア産業は進んでいった。この方向性は、企業や官公庁が自ら使うために作るソフトウェアのような分野で顕著である。一方で、多数存在していたOSはいくつかに集約された。
p. 284 パッケージソフト産業は、激烈な競争がある自由市場であり、多くの企業はスタートアップ企業として始まった。このため、仕事の過程よりも仕事を成し遂げたかに強烈な焦点が当てられた。そして、昔からのソフトウェア企業では難しかった個人の実績に応じて報酬を与えることが、このスタートアップ文化では可能になった。
pp. 287-289 ソフトウェア工学は絶望的なわけではなく未成熟なだけではないかと化学工学の発展の歴史を見て著者は思っている。新たな技術・手法・ツールの継続的な開発と習得が、常識にとらわれないことが、そして、自分達が簡単に間違えることへの謙虚さと自分達の限界への謙虚さが、今後も求められるのだろう。