索引 / 001 JA
A Philosophy of Software Design(ソフトウェア設計の哲学) cover

コンピュータサイエンス

コンピュータサイエンス

A Philosophy of Software Design(ソフトウェア設計の哲学)

John Ousterhout

英語原題: A Philosophy of Software Design

ソフトウェア設計の中心的な課題である複雑さの管理を扱う短い本。設計に重点を置いたソフトウェアの授業を教えてきた著者の経験をもとに、単純なインタフェースを持つ深いモジュール、情報隠蔽、注意深い命名とコメントを提唱し、設計が理解しにくく変更しにくくなりつつあることを示す警告サインの一覧を示す。

前提知識: 授業での大きめの課題など、何らかの言語で中規模のプログラムを書き、保守した経験。

難易度レベル
初級
学術レベル
学部
software designcomplexitymodularityabstractioncode quality

01 / 読書ガイド

読書ガイド

引用

Ousterhout, J. (2021). A Philosophy of Software Design (2nd ed.). Yaknyam Press.

章の要約

22章、200ページに満たない短い本で、扱う問題は一つである。ソフトウェアをクラスやメソッドといったモジュールにどう分解すれば、システムの複雑さを管理可能に保てるか。本書は著者がスタンフォード大学で教えるソフトウェア設計の授業から生まれ、例の多くはGUIテキストエディタなどの学生のプロジェクトから取られている。巻末には、設計原則の要約と、本文全体で導入される設計上の問題の警告サイン「レッドフラグ」の要約がまとめられている。著者によれば第2版の変更は少なく、第21章の追加、第6章の改訂・拡充(他の章から内容を移した)、そしてロバート・マーティンの Clean Code と本書の見解を比べる節の追加である。

第1–3章:Introduction(序論);The Nature of Complexity(複雑さの本質);Working Code Isn't Enough(動くコードだけでは足りない)

第2章は複雑さを定義し、その症状(変更の増幅、認知負荷、未知の未知)と原因(依存関係と不明瞭さ)を挙げ、複雑さが少しずつ蓄積すると論じる。第3章は戦術的プログラミングと戦略的プログラミングを対比する。後者は、設計に前もって少し多く時間をかけて後の時間を節約する投資の考え方である。どれだけ投資すべきか、スタートアップの場合も含めて論じる。

第4章:Modules Should Be Deep(モジュールは深くあるべきだ)

中心となる比喩である。深いモジュールは単純なインターフェースの背後に強力な機能を提供し、浅いモジュールはあまり隠さないままインターフェースを増やす。インターフェースと抽象化を扱い、「クラス病」(小さなクラスの乱立)を戒め、例としてJavaとUnixの入出力を比べる。

第5章:Information Hiding (and Leakage)(情報隠蔽(と漏洩))

情報隠蔽と、その失敗の形である情報漏洩を説明し、時間的分解も取り上げる。HTTPサーバーを題材にした一連の例で、クラスの多すぎ、パラメータの扱い、レスポンスのデフォルト値を扱う。

第6章:General-Purpose Modules are Deeper(汎用的なモジュールのほうが深い)

著者は、過度の特殊化がソフトウェアの複雑さの最大の原因かもしれないと論じる。エディタのプロジェクトのテキストクラスを使い、特定のキーに結びついたメソッドを、範囲の挿入と削除という汎用的なAPIで置き換える様子を示す。適切なバランスを見つけるための問いを挙げ、特殊化を上へ(あるいは下へ)押しやる方法をデバイスドライバの例で説明し、汎用的なアンドゥ履歴を特殊な操作から切り離し、コードから特殊ケースをなくすよう説く。

第7–8章:Different Layer, Different Abstraction(層が違えば抽象も違う);Pull Complexity Downwards(複雑さを下へ引き下ろせ)

第7章は、受け渡しだけのメソッドや変数、デコレータ、インターフェースと実装の違いを、隣り合う層が同じ抽象を繰り返している兆候として扱う。第8章は、複雑さを吸収すべきなのはモジュールの利用者ではなく実装者だと論じ、エディタのテキストクラスと設定パラメータを例に挙げ、この考えを行き過ぎさせないよう注意する。

第9章:Better Together Or Better Apart?(まとめるべきか、分けるべきか)

コードをまとめる基準(情報を共有している、インターフェースが単純になる、重複がなくなる)、エディタからの例、メソッドの分割と結合を論じる。新たな節は、関数は非常に短くあるべきだという Clean Code の助言に異を唱え、長さより深さが大事だとする。

第10章:Define Errors Out Of Existence(エラーを定義によって消し去る)

例外が複雑さの大きな源だと論じ、それを減らす方法を示す。エラーが起こりえないようにAPIを定義する(Windowsでのファイル削除とJavaのsubstringメソッドが例)、低いレベルで例外を隠す、例外処理を集約する、単にクラッシュさせてよい場合を考える、特殊ケースを設計によって消す、である。

第11章:Design it Twice(二度設計せよ)

一つの設計に決める前に、複数の設計を検討するよう勧める短い章である。

第12–16章:Why Write Comments? The Four Excuses(なぜコメントを書くのか:四つの言い訳);Comments Should Describe Things that Aren't Obvious from the Code(コメントはコードから明らかでないことを記述すべきだ);Choosing Names(名前の選び方);Write The Comments First(コメントを先に書け);Modifying Existing Code(既存コードの修正)

本書で最も長いまとまりはドキュメントについてである。第12章はコメントを書かないよくある四つの言い訳に答え、第2版ではコメントは失敗だという Clean Code の見方を退ける。第13章は、コメントが何を付け加えるべきかを説明する。低いレベルでの精密さ、高いレベルでの直観、インターフェースのドキュメント、モジュールをまたぐ設計判断である。第14章は、明確なイメージを生む、正確で一貫した名前を求める。第15章は、設計の道具としてコードより先にコメントを書くよう説く。第16章は、戦略的な考え方を既存コードの修正とコメントの維持に当てはめる。

第17–18章:Consistency(一貫性);Code Should be Obvious(コードは自明であるべきだ)

第17章は一貫性の例、それを確保する方法、行き過ぎへの警告を示す。第18章は、読み手にとってコードをより自明にするものと、そうでなくするものを挙げる。

第19章:Software Trends(ソフトウェアの潮流)

オブジェクト指向の継承、アジャイル開発、単体テスト、テスト駆動開発、デザインパターン、ゲッターとセッターを、本書の原則に照らして評価する。

第20章:Designing for Performance(性能のための設計)

性能についての考え方、変更前に計測すること、クリティカルパスを中心に設計することを扱い、著者のRAMCloudシステムからの長い例を示す。

第21–22章:Decide What Matters(何が重要かを決めよ);Conclusion(結論)

新しい第21章は、良い設計とは重要なものとそうでないものを分けることだと説く。てこの効く点を探す、重要なものをできるだけ少なくする、重要なものを目立たせ、繰り返し、中心に置くことで強調する、そして重要でないものを重視しすぎる誤りと重要なものを見落とす誤りの両方を避ける。本書は短い結論で終わる。

主要概念

第1–3章:複雑さと心構え

  • 複雑さ:本書全体が扱う問題。第2章はその原因を依存関係と不明瞭さにたどる。
  • 変更の増幅、認知負荷、未知の未知:複雑さが表れる三つの症状。
  • 戦略的プログラミングと戦術的プログラミング:次の機能を動かすことだけでなく、設計に継続的に投資すること。

第4–10章:モジュール設計

  • 深いモジュール:単純なインターフェースの背後にかなりの機能を隠すモジュール。
  • 情報漏洩:一つの設計判断が複数のモジュールに反映され、変更がそのすべてに及ぶこと。
  • ある程度汎用的:インターフェースは複数の用途に足る程度に汎用的にし、実装は現在の必要を満たすこと。
  • 複雑さを下へ引き下ろす:呼び出し側すべてではなく、実装者に複雑さを引き受けさせること。
  • エラーを定義によって消し去る:エラーのケースが生じないようにインターフェースを設計すること。

第11–18章:プロセス、コメント、読みやすさ

  • 二度設計せよ:一つに決める前に別の設計案を検討すること。
  • 設計の道具としてのコメント:コードより先にコメントを書き、後から説明するのではなく設計を形づくるのに使うこと。
  • 自明なコード:読み手があまり考えずにすぐ理解できるコード。

第19–22章:潮流、性能、優先順位

  • クリティカルパス:性能が重要な場面で実行されなければならないコード。本書のRAMCloudの例では、不要なメソッド呼び出しや特殊ケースの検査をそこから除いている。
  • レッドフラグ:設計上の問題を示す、名前の付いた症状。巻末にまとめられている。
  • 何が重要かを決める:設計の重要な少数の側面を見極め、それを中心にシステムを構成すること。

批判的分析

長所

  • 一つの考えを一貫して適用する。 どの章も複雑さとその原因に立ち返るので、覚えやすく、助言をコードレビューで使いやすい。
  • 授業で試された具体的な例。 エディタ、HTTPサーバー、アンドゥの例は著者の授業から取られ、学生の欠陥のある設計とよりよい設計の両方を示す。レッドフラグの一覧は原則を使えるチェックリストに変えてくれる。
  • 立場をはっきり示す。 本書はよくある助言に反論する。最も明確なのは、メソッドの長さとコメントについて Clean Code と意見を異にする第2版の節であり、テスト駆動開発やゲッターとセッターといった潮流の評価もそうである。学生は自分の経験に照らして検証する材料を得られる。
  • 短い。 200ページ未満なので、他の課題を押しのけずにプロジェクト型の授業と並行して読める。

短所

  • モジュールレベルの設計に限られる。 本書が扱うのはプログラム内部のクラス、メソッド、インターフェースである。要求、分散システム規模のアーキテクチャ、テストの実践、チームやプロセスは扱わず、それらはこのコースの他の本が扱う。
  • 一人の経験に根ざしている。 著者は本書を自身の授業とシステム開発から引き出した哲学として示しており、根拠は実証研究ではなく例と議論である。Clean Code をめぐるやりとりが示すように、読者が特定の立場に反対することもありうる。
  • プロジェクト経験のない読者には得るものが少ない。 例はクラス、インターフェース、例外に慣れていることを前提とし、主にJava風のコードで書かれている。助言は、ある程度の規模のプログラムに苦労した後でこそ身にしみる。
  • 第1版からの変更は少ない。 著者自身、第1版をもっている人は第2版を買う必要はないかもしれないと述べ、新しい内容を無料の抜粋として公開している。

コースにおける位置づけ

ソフトウェア工学のコースの中で、本書はコードそのものの設計についての本である。最も近い仲間は Thomas と Hunt の The Pragmatic Programmer で、短いトピックの形でより幅広い仕事の習慣と実践を扱うのに対し、Ousterhout は一つの問いを深く掘り下げる。二冊を一緒に読めば、幅と一貫した設計の語彙の両方が得られる。

Sommerville の Software Engineering は要求から進化までライフサイクル全体を扱い、Software Engineering at Google は組織規模での文化、プロセス、ツールを論じ、Bass、Clements、Kazman の Software Architecture in Practice はシステム全体と品質特性のレベルでの設計判断を扱い、Jackson の Software Abstractions はAlloyによる設計の形式的モデリングを紹介する。Ousterhout は複雑さのコストを具体的にすることで、それらすべてへの準備になる。ある程度大きなプログラミングプロジェクトの最中か、その直前に、早めに読むのがよい。

本書の使い方

本書は、大きめの授業課題のような中程度の規模のプログラムを書いて保守した経験のある学生や、現役のプログラマーに向いている。特定の言語は必要ないが、例の多くはJava風のコードである。

  • 中核: 第1–10章。他のすべての章で使われる語彙(複雑さ、深いモジュール、情報隠蔽、汎用的なインターフェース、エラー)をここで身につける。
  • ドキュメント: 第12–15章は最も直接的に実践的である。プロジェクトの最初のコードレビューの前に読むとよい。
  • 任意、または後で: 潮流と性能を扱う第19–20章、そして本書の優先順位のまとめとしての第21章。

自分のコードを開いて読むこと。各章を読んだら、自分が書いたモジュールを巻末のレッドフラグに照らして見直し、次に書くインターフェースで「二度設計せよ」を試すとよい。Clean Code との比較は議論の題材によい。マーティンの立場と Ousterhout の反論を読み、自分のコードベースにはどちらが当てはまるかを考えてみるとよい。