A Philosophy of Software Design を読んだ

2024-02-02

本に぀いお

衚玙画像

党線英語なのですが、かなり読みやすい英語で蚘茉されおいるず感じたした。

ずにかくモゞュヌルずいうのは情報を抜象化し、隠蔜しおこそ意味があるずいうスタンスで、これを「深いモゞュヌル」ず呜名しおいるのがナニヌクでした。

基本的にこういう蚭蚈関連の技術曞はNotion䞊でメモをずりながら読むこずが倚いので、せっかくならこのメモをブログにも残しおおこうず思い、各章のメモを残しおおきたす。

今埌も䜕かいい技術曞を芋぀けたら同じように蚘茉しおいこうかなヌず思いたす。

各章のメモ

Chapter 1 Introduction

シンプルなデザむンがより倧きくパワフルなシステム構築を可胜にするず蚀っおいる。

この本では 2 ぀のアプロヌチを説明しおいお

  • コヌドをシンプルに、より明らかにするこずで耇雑性を枛らすアプロヌチ
  • 耇雑性を局所化するずいうアプロヌチ
    • オブゞェクト指向など
    • この本では modular design ず呌ばれおいる

継続的な開発ずは぀たり継続的な再蚭蚈を意味しおいる

たず耇雑性ずはなにかを述べた䞊で、それらを最小化する開発のアプロヌチを述べる

Chapter 2 The Nature of Complexity 耇雑性の定矩

システムを理解し倉曎するこずが難しくなった構造のこずを耇雑性ず述べおいる。

耇雑性を Isolating (孀立) させるこずで、党䜓的な耇雑性を枛らすこずができる

コヌドを読む偎の人間が耇雑だず思ったらそれは耇雑である

耇雑性の症状ずしお 3 ぀を䞊げおいる

  • Change Amplification: 倉曎箇所が倚いずいうこず
    • 倉曎箇所が耇数にたたがっおいる
  • Cognitive Load: 認知負荷
    • グロヌバル倉数や䞀貫性の欠劂、モゞュヌル間の䟝存関係など
  • Unknowns unknown: 分からないこずが分からない
    • これが䞀番悪いず述べおいる
    • 知らないずいけないこずのにそれを知るすべがない状態
    • よい蚭蚈の重芁なゎヌルに「明らかさ」がある

耇雑性は䟝存性ずあいたいさの 2 ぀によっお匕き起こされる

耇雑性は埐々に生たれおいくので、それを生み出さないようにするメンタリティが必芁

Chapter3 Working Code Isn't Enough 動くコヌドでは䞍十分

Strategic Programming ず Tactical Programming の察比

  • Tactical
    • 可胜な限り玠早く動くものを䜜る
  • strategic
    • 良い蚭蚈を求めお時間を投資する
  • strategic がいいず筆者は述べおいる
    • ゜フトりェアは長い期間生存するため

いわゆる財政的な負債ず違い、技術的負債は完党に返枈されるこずはないず述べおおり、なので返枈し続けろ ずいうこずを蚀っおいる

Chapter4 Modules Should Be Deep モゞュヌルは深くあるべし

  • ゜フトりェアの耇雑性を制埡する 1 ぀に modular design がある。これは開発者が向き合わないずいけない耇雑性をできるだけ最小化するアプロヌチ。
    • この modular design のゎヌルは、モゞュヌル間の䟝存関係を最小化するこずにある。よりモゞュヌルは、実装よりもむンタヌフェヌスがシンプルになっおいるこず。
  • シンプルなむンタヌフェヌスで居力な機胜を提䟛するモゞュヌルを deep 深いず筆者は呌ぶ。
    • ぀たり狭いむンタヌフェヌスで機胜的に振る舞うメ゜ッドがいいず蚀っおいる。広いむンタヌフェヌスで倧したこずをしないモゞュヌルは耇雑性を隠蔜できおいない。こっちは shallow ず呌ばれおたりする
    • Unix I/O や GC を、deep module の代衚䟋に䞊げおいる。倚くの問題や耇雑な問題を I/F を介しお、あるいは I/F すらも隠蔜しお実行しおいる
  • LinkedList が shallow module の代衚䟋。耇雑性を隠蔜できおいない
    • おそらくデヌタ構造をそのたたマッピングしおいるだけ ずいうこずだろう
  • Classitis ずいう蚀葉に぀いお
    • メ゜ッドやクラスは小さく䜜れずいう教えがあるので、そうやりがちで、その状態を Classitis ず筆者は呌ぶ
    • 確かに 1 ぀ 1 ぀のクラスや関数は小さくなるが、党䜓的な耇雑性は隠蔜できおいない、むしろ耇雑性が増える
      • 小さいクラスは、より機胜的に振る舞うこずには貢献しない
  • 筆者はメカニズムを知らなくおも効果的に䜿える ずいうこずを重芁芖しおいそう。それを知らないずなにか䞍郜合が生じるこずに異を唱えおいる感がある
    • モゞュヌルを導入したずしおも、情報の抜象床が倉わっおいない堎合はむしろ耇雑性が䞊がるずいうスタンス。なので deep なモゞュヌルがいいず述べおいる

5 ç«  Information Hiding 情報隠蔜

  • 知識がモゞュヌルの実装に埋め蟌たれおいおか぀それがむンタヌフェヌスには衚出しおいない状態を目指す
  • 新しいモゞュヌルを蚭蚈するずきは情報知識がそのモゞュヌル内に隠蔜されおいるか泚意深く考えるべき
  • 時系列で扱いたいデヌタを耇数のクラスに分散させるこずは、その知識をクラス間で共有しおいるこずになり、奜たしくないずいうスタンス。これを temporal decomposition ず述べおいる
    • 䟋えば HTTP サヌバは temporal decomposition の䟋
    • リク゚ストヘッダヌのパヌスやレスポンスヘッダヌの構築は時系列に、か぀レスポンスヘッダヌはリク゚ストヘッダヌに䟝存しおいたりするので、クラス蚭蚈ずしお分けるべきではないず述べおいる
  • この思想で䜜られるモゞュヌルは自然ず「深い」モゞュヌルになっおいくので、deep module のひず぀の手段や考え方が情報隠蔜information hiding) である
    • クラスをより倧きいものにするこずで情報隠蔜はより達成される
    • クラスを小さく、個別に分けるずいうスタンスに真っ向から異議を唱えおいる感じがある

6 ç«  General-Purpose Modules are Deeper 汎甚的なモゞュヌルは深い

  • 過床に特別なケヌス゚ッゞケヌスなどは゜フトりェアを耇雑化させるひず぀の芁因
    • general purpose(汎甚的なモゞュヌル) はよりシンプルで理解するこずが容易ずなる
    • 特別なケヌスが匕き起こす問題ず汎甚性の利点を話す
      • 特殊ケヌスは完党に取り陀けないので、どう分けるかに぀いおも話す
  • より䞀般的なモゞュヌルを远うスタンスは、 負債解消ぞの投資のマむンドセットに近い
    • 元々筆者も YAGNI でいいのではずいう考え方だったが、いく぀かの孊生のプロゞェクトを芋お、どの堎合においおも general-purpose なクラスのほうがよかったずいうこずに気づいた
      • これはたずえそのクラスが再利甚されなかったずしおも
  • 経隓ずしお、somewhat general-purpose がいい塩梅だず蚀っおいお、むンタヌフェヌスはより䞀般的であるこずを目指し぀぀実装は YAGNI 的に実装するずいうもの
    • 今欲しいものを実装はするが、むンタヌフェヌスは䞀般的なものを目指しお蚭蚈を進める
  • より䞀般的なナヌスケヌスで利甚できるメ゜ッドを実装するこずで、実装量は枛るし、認知負荷を䞋げるこずができる
    • 結局これも抜象床を䞊げるむンタヌフェヌスを甚意するこずで解決するアプロヌチ
    • これっお information hiding(5 章のや぀) だよねずいう話
    • 䟋えばテキスト゚ディタヌの実装で、backspace の挙動を実装したい時に、そのたた backspace ずいうメ゜ッドを生やしおも、それっお情報の抜象化ができおいないですよねずいう話をしおいる
      • backspace が抌された時の挙動ずいうこずはわかるが、じゃあそれっおどういう凊理をしおるんですかずいうのがメ゜ッドシグネチャからわからないので結局実装を芋る必芁があるよねずいう
  • 今の必芁なもの党おをカバヌできる最もシンプルなむンタヌフェヌスは䜕かを問い続けるこずが重芁
    • Questions to ask yourself
  • 普遍的に扱えないかずいう芳点で考慮し蚭蚈に反映させるこずで特別扱いしないずいけないケヌスを枛らすこずができる
    • if 文を枛らすようなアプロヌチを怜蚎したい

7 ç«  Different Layer, Different Abstraction 異なるレむダヌ、異なる抜象化

  • 䌌たような抜象化を隣接したレむダが行うず、パススルヌメ゜ッドずいう圢で問題が衚出する
    • 実際には䜕もしないパススルヌメ゜ッドは、綺麗な責務の分割ができおいないこずを瀺すこずが倚い。どういう責務分割なのか混乱を招くしクラス間の䟝存を生む
    • これはクラスを「浅く」する
  • 同じむンタヌフェヌスでもいい䟋ずしお Dispatcher を挙げおいる
    • どのメ゜ッドにディスパッチするかを遞択する Dispatcher ずその実際の凊理ずなるメ゜ッドは同じむンタヌフェヌスシグネチャを持぀可胜性がある
    • これは提䟛しおいる機胜や抜象化のレむダが異なるため蚱されるケヌス
  • Decorator には吊定的な立堎をずっおいる
    • 特殊なケヌスを考慮した浅いクラスやモゞュヌル、パススルヌメ゜ッドが倧量に䜜られるこずになり、これは前章で述べた内容ず盞反しおいる
      • デコレヌタは導入するず酷䜿されやすいずいうこずも述べおいる、わかる
    • デコレヌタの統合や、そもそもデコレヌタを䜿わないクラスを芋぀けるなどの手法を提案しおいる

8 ç«  Pull Complexity Downwards 耇雑性を匕き蟌む

  • モゞュヌルは開発者より䜿う人の方が倚いので、実装が耇雑になったずしおも䜿う人にずっおむンタヌフェヌスがシンプルな方がいいず述べおいる
    • 䟋倖や蚭定(Config)に぀いおもむンタヌフェヌスを倖郚に公開しおいるので耇雑性を䞊げる芁因ず蚀っおいる
  • configuration parameter蚭定パラメヌタ を正しい倀に蚭定するこずは難しいあるいは䞍可胜ず述べおいる
    • ゆえに蚭定項目を倖郚に公開する前に、「正しいデフォルト倀を我々提䟛偎に蚭定できないか」を問うべき
    • 蚭定パラメヌタは䞍完党な゜リュヌションを提䟛しおいるず述べおいる
      • それぞれのモゞュヌルは個々で問題を解決すべき

9 ç«  Better Together Or Better Apart? 䞀緒にするべきか分けるべきか

  • 现分化のやりすぎは良くない
    • コンポヌネント、むンタヌフェヌスの数が増えるこずになり、これは耇雑性をうむ
    • 现分化したコンポヌネントをオヌケストレヌションする局が必芁になる
    • 分断を生む
      • 完党に分離されおいるなら良い
      • 䟝存があるずコンポヌネント間を行ったり来たりする必芁が出おくるので良くない
    • 耇補を生む
  • 関係のないものは分けお、関連するものは䞀緒に扱った方がいいずしおいる
    • 関連しおいるこずを瀺すもの
      • 情報を共有しおいる
        • デヌタを読んで、パヌスしお、のような凊理はデヌタを読むずころずパヌスするずころで同じ知識を共有しおいる
          • HTTP サヌバの䟋など
      • 䞀緒に䜿われる
      • 抂念が重なっおいる
      • 他の箇所を芋ないず理解が難しい
  • メ゜ッドの分割の基準ずしお行数を採甚するこずに反察しおいる
    • メ゜ッド分割を「しすぎだ」ず述べおいる
    • シンプルなメ゜ッドシグネチャで読むこずが簡単なのであれば分ける必芁がない
      • これは “deep” なメ゜ッド
    • メ゜ッドを分けるこずで行き来が増え、メ゜ッドのむンタヌフェヌスも増え、耇雑性が増す
  • メ゜ッドを蚭蚈する際のゎヌルは「抜象」を提䟛するこず
  • メ゜ッド間を行き来するこずは抜象を提䟛できおおらず、red flag だず述べおいる
    • メ゜ッドに切り出すずいうこずはその先で具䜓的に䜕をしおいるかを知らなくおもわかるようになっおいるはず

10 ç«  Define Errors Out Of Existence 存圚しないように゚ラヌを定矩する

  • 䟋倖はクラスが持぀むンタヌフェヌスの䞀郚である
    • 倚くの䟋倖はクラスを “shallow” にしお、耇雑なむンタヌフェヌスずなる
  • 䟋倖を投げるこずは簡単だが、それを受け取っおハンドリングする偎は難しい
    • すなわち呌び出し偎でハンドリングしなければならない䟋倖を枛らすこずが重芁
    • なんならハンドリングが必芁な䟋倖をなくすこずが䞀番いいず蚀っおいる
      • セマンティクスを再定矩するこずで䟋倖を枛らすこずができる
        • Java の文字列のメ゜ッドの話
      • 䟋倖をマスクする
        • 䟋倖を投げたずころでそれを受けるナヌザにはどうしようも解決ができないこずもある
          • ファむルシステムサヌバの゚ラヌなど
          • どうせ埩旧したタむミングでリトラむするんだから、䟋倖は吐かずにハングさせおおいたたたにするのが合理的
            • 䟋倖を投げたかったらクラむアント偎でタむムアりトを蚭定しお手動で゚ラヌを投げればいい
            • デフォルトは䞀番䜿い勝手がいい状態にするべきずいう思想がここにも珟れおいる
  • 䜕が重芁で䜕が重芁でないかを芋極めるこずが必芁
    • 重芁でない゚ラヌは隠されるべきだし重芁な゚ラヌは倖郚に通知できるようになっおいるべき
      • 発生頻床がレアだったり、リカバリ䞍可胜な゚ラヌのハンドリングで耇雑性を䞊げる必芁はない

11 ç«  Design it Twice 二床蚭蚈する

  • 色々なパタヌンをあげながら蚭蚈方針を考えるのがいい
    • 䞀番いい蚭蚈だず思っおいおも別のパタヌンを考え、pros/cons を敎理するこずで、よりベストな蚭蚈に近づくずいう話
  • むンタヌフェヌスレベルの蚭蚈をしたら実装レベルでも耇数のパタヌンを怜蚎したい
    • 実装レベルの堎合は シンプルさずパフォヌマンス性を重芖する

12 ç«  Why Write Comments? The Four Excuses なぜコメントを曞く4 ぀の蚀い蚳

  • コメントを曞くプロセスは、システムぞの理解だけでなく、蚭蚈をより向䞊させるものだず蚀っおいる
  • 4 ぀の蚀い蚳
    • 良いコヌドはそれを芋ればわかるself-documenting)
      • クラスむンタヌフェヌスやメ゜ッドシグネチャはコヌドを芋ればわかる
      • より抜象床の高い「メ゜ッドが䜕をしおいるか」や「結果、返り倀の意味」に぀いおはコヌドでしか説明するこずができない
      • 蚭蚈䞊の意思決定、特定のメ゜ッドを呌ぶべき条件 など、コヌドでしか説明できない䟋はたくさんある
      • 「コヌドを読めば分かる」ず蚀っお䞀぀のメ゜ッドをさらに分割しおいくようになるず、「浅い」モゞュヌルが出来䞊がっおいく
      • コメントは抜象化を提䟛し、これはモゞュヌル化が目指すものず同じこずだ
        • そのメ゜ッドを䜿う時コヌドを読たないずいけないのであれば、それは䜕も抜象化がないずいうこずを衚しおいる
        • 自然蚀語はこの抜象化に䞀圹買うこずができる
    • コメントを曞く時間がない
      • これに察抗するには「investment mindset」長期的な思考が重芁
      • コメントの蚘茉は実装の 10%も時間がかからないが、利益はすぐに享受できる
    • コメントが远埓できないずミスリヌディングになる
      • 倧きいコメントの修正は倧きい実装の倉曎に䌎うものであり、どうやっおも実装よりコメントの蚘茉に時間がかかるこずはないのだから、より最新のコメントに远埓させるのはそこたでの努力は必芁ずしないだろう
    • 芋たこずがあるコメントに䟡倀を感じたこずがない
      • よいドキュメンテヌションずメンテナンスの方法を知ればいい
  • コヌドずしお曞くこずのベヌスの考えは、コヌドでは衚珟できない蚭蚈者のマむンドを蚘茉する
    • ロヌレむダヌのトリッキヌなクセのあるコヌドから、ハむレむダヌのクラス蚭蚈たで適甚可胜

13 ç«  Comments Should Describe Things that Aren’t Obvious from the Code コメントはコヌドから明らかでないものを曞くべき

  • 開発者は、コヌド読むよりも倖郚に公開された宣蚀コメント含めおから抂芁を理解するべき
    • 良いコメントは、コヌドず別の粒床で抜象化されおいるこずだず述べおいる
  • コメントに関する 4 ぀のカテゎリに぀いお
    • Interface
      • クラスの意味やメ゜ッドの振る舞い
      • 実装ずむンタヌフェヌスを分けおコメントずしお残せるかに着目する
        • 残せない堎合は「浅い」メ゜ッドである
      • 副䜜甚は返り倀からは刀断できないのでむンタヌフェヌスレベルのコメントずしお残す
    • Data structure member
      • デヌタ構造に関するもの
    • Implementation comment
      • 実装に関するもの
      • 実装に関しお䜕をしおいるかを衚すものでどうやっおいるかではない
        • how ではなく what を曞く
        • トリッキヌなこずをしおいる堎合は why も曞く
    • Cross-module comment
      • 䟝存するモゞュヌルに関するもの
    • 最初の 2 ぀が特に重芁ず述べおいる。すべおのクラスやメ゜ッドはコメントを持぀べき
      • きっずここら蟺は「deep」なクラスやメ゜ッドであるこずが暗に前提になっおいるんだろう
  • コヌドを読んだこずがない人が、コメントだけで曞けるようになるかを問うずよい
  • メ゜ッド名や倉数名などず違う語圙を䜿っおコメントで補足するずいいコメントの最初のステップになるず蚀っおいる
    • コメントは動詞ではなく名詞に察しおフォヌカスするず冗長なコメントになるのを避けるこずができる
    • このコヌドは䜕をしおいるのかコヌドを説明するシンプルな語圙は䜕かこのコヌドで最も重芁なこずは䜕かこれらを問い、コメントずしお残すこずで抜象や抂芁を提䟛するコメントを曞くこずができる
  • 読み手が曖昧だず感じたらそれは曖昧なので、そういう指摘に察しお、どこが曖昧かを議論するこずを恐れおはいけない

14 ç«  Choosing Names 呜名

  • 「たあたあ」な呜名に甘えおはいけない
    • 時間をずっお、正確で、曖昧さがなく、盎感的な名前を぀けるべき
  • 呜名も抜象化の䞀぀の圢匏だず蚀っおいる
  • 呜名に困るずいうこずは、倉数の定矩や目的が曖昧ずいうこずを衚しおおり、蚭蚈の匱みを特定し、向䞊するいい機䌚ず捉えるこずができる
  • それが䞀貫しおいるなら短い倉数名でも良いが、短い倉数はコンフリクトしがちで、同じ倉数が異なるコンテキストで䜿われるならやめた方がいい
    • i, j はルヌプ倉数、ずか、そういうのなら良い

15 ç«  Write The Comments First 最初にコメントを曞く

  • コメントを曞くのに最適なタむミングは、コヌドを曞き始める最初だず述べおいる
    • 埌からコヌドを曞こうずするず埌回しにした結果、曞かないずいうこずが起こりがち
  • コメントを最初に曞くこずの恩恵は 3 ぀
    • 蚭蚈に関する蚘憶がフレッシュなので、忘れるこずがないこず
      • 実装に集䞭するず蚭蚈に関連した意思決定の内容を忘れおしたうこずがある
    • コメントを最初に曞くこずは良い蚭蚈を提䟛する
      • コメントを曞く行為によっお自身に察するレビュヌ䜜甚が働く
      • 実装の前にコメントを曞くこずで、より抜象な事柄を察象にしたコメントを曞くこずができ、それがいいコメントに぀ながる
      • コメントで衚珟する内容がファットな堎合は、うたく責務分割ができおいないこずを瀺唆しおいたりする
    • コメントを曞くこずが楜しい
      • 良い蚭蚈の指暙ずなるため、それを䜿っおさらに蚭蚈に関する探究ができるずいうこずで筆者は楜しいず述べおいる

16 ç«  Modifying Existing Code 既存コヌドの改修

  • tactical ず strategic の話で、strategic のアプロヌチをずるべきずいう話が再び登堎する
  • 実装ず近い䜍眮にコメントを蚘茉するこずで、コメントが倉曎に远埓されない問題を解決できる
  • コミットログたで芋るこずは少ないので、コミットではなくそれをコヌドコメントに曞けないかを問うべき
    • コミットログにはなぜその倉曎が必芁だったのか等の背景情報を蚘茉するずいい
  • コメントが重耇しお耇数箇所に蚘茉されるず、必ず片方が远埓できなくなるので避けるべき
  • コミットする際に、差分をセルフチェックし、コメントの最新化が挏れおいないかをチェックする
  • そもそも抜象床が高いコメントであれば実装のたびに頻繁に修正する必芁がなくなるので、そういうアプロヌチも怜蚎したい

17 ç«  Consistency 䞀貫性

  • 䞀貫性が適甚できるもの
    • 呜名
    • コヌディングガむド
    • むンタヌフェヌス
    • デザむンパタヌン
  • 䞀貫性の維持に必芁な芁玠
    • ドキュメント
    • 匷制力
      • 違反チェックのツヌル
    • 郷に入っおは郷に埓う
      • 呚囲のコヌドを芋枡しお理解する
    • 既存のルヌルを倉曎しない
      • better idea では十分でない

18 ç«  Code Should be Obvious コヌドは明らかであるべき

  • 䞍明瞭さは新しい開発者にずっおシステムが明らかでない時に生たれる
    • 䞍明瞭さはコヌドの読み手が刀断するものなので、コヌドレビュヌがそれを刀断するいいプロセスになる
  • 明瞭さを実珟するために重芁なテクニックは 2 ぀
    • 良い呜名
    • 䞀貫性
  • オブゞェクト指向に぀いお
    • 芪ず子で䟝存関係ができるような実装はやめるべき
    • 䟋えば、芪偎でデフォルトの振る舞いを定矩しおいお、子クラスでそれをオヌバラむドしたりしなかったりするケヌス
      • 共有できる振る舞いは composition ベヌスなアプロヌチを怜蚎したい
  • アゞャむル開発に぀いお
    • 泚意したいのは、tactical programming に収束しおしたう可胜性があるこず
      • 個々の機胜実装だったりむテレヌションの時間制玄だったりで、短期的な芖野に陥りがち
    • むテレヌティブに、抜象されたものを開発しおいく
  • テスト駆動開発に぀いお
    • 「テストを通すこず」が最優先ずなっお、ベストな蚭蚈を芋぀けるような力孊が働かなくなる懞念があるず述べおいる

20 ç«  Designing for Performance パフォヌマンスのための蚭蚈

  • 既存のコヌド䞊でパフォヌマンス改善をする堎合
    • たず仕様を満たす最小限のコヌドを曞く
      • この際に既存のコヌドがどうなっおいるかは気にしない
    • その最䜎限の仕様を満たすコヌドず珟圚のコヌドずを突き合わせお、ギャップを埋めおいくこずをする
    • ゚ッゞケヌスの考慮等で遅くなっおいる堎合があるので、分離できないかを怜蚎する