なになれ

IT系のことを記録していきます

A Philosophy of Software Designの3章要約

内輪で「A Philosophy of Software Design」の輪読会を始めました。
本内容は、1章、2章を紹介するとともに自分の担当である3章を要約する記事です。
今後も定期的に要約記事を投稿します。

www.amazon.co.jp

著者の意図としては設計の哲学を教える薄い本とのことで、良い設計について考えるようになってほしいという思いから書かれたようです。

www.youtube.com

経緯

下記「A Philosophy of Software Design」を紹介するスライドがバズっていて、気になったのがきっかけです。
ソフトウェアの設計はどんなポジションでも共通的に身につけておくべきスキルになるし、自分はうまく設計できたと思った経験があまりないので、これを機会に学ぶのも良いだろうと思いました。

speakerdeck.com

1章、2章の紹介

他担当の方が要約した1章、2章の内容を引用します。

  • 1章 序文
  • 2章 複雑さの本質
  • この本の目的は2点
    • ソフトウェアの複雑さの本質を説明する
    • 開発の際の複雑さを最小化するためのテクニックを説明
  • ソフトウェア開発の最大の制約はプログラムの複雑化
    • 開発が進むこと(関係者の増加)で依存関係が増加しこれが複雑化につながる
    • 複雑化によって理解がさらに難しくなり開発速度低下、バグの頻度増加、コスト増加
  • 複雑化への対応以下2つの方法でソフトウェアをシンプルにする
    • 1.コードをより単純化、明白化して複雑さを解消
    • 2.複雑性のカプセル化(moduler design) - 一度にすべての複雑性の対応を回避できる
  • 現在の開発はウォーターフォールモデルの反省からインクリメンタル開発を行っている

    • 初期設計がベストでなく改善を行う必要がある。ソフトウェアの設計には終わりがない
    • 常に良い設計を考えるべき、設計のスキルを向上は複雑性を認識して気をつけること
  • 複雑さの定義はソフトウェアシステムの構造に関してシステムを理解し修正することを難しくするもの

    • システムを理解し修正するのが難しい場合は複雑であり、理解し修正するのが簡単な場合は単純
    • 変更に時間がかかるもの
  • システム全体の複雑さ(C)は、各部分pの複雑さ(cp)を、開発者がその部分に費やす時間の割合(tp)で重み付けしたもので決まる
  • 複雑さの兆候とは3つある
    • Change amplification: 変化の増幅
      • 簡単そうに見える変更でも、多くの箇所でコードの修正が必要になること
    • Cognitive load: 認知的負荷
      • 開発者が必要な情報を学ぶのに時間がかかり、重要なことを見逃してバグが発生するリスクが高くなること
    • Unknown unknowns: 未知なる未知?
      • 最も悪いもの
      • 開発ために修正箇所、そのために必要な情報が明確でない
  • 複雑さの原因は、「依存性」と「不明瞭性」の2つ
    • 依存関係はソフトウェアの基本的な部分でなくすことはできないが、ソフトウェア設計の目標の1つは、依存関係の数を減らし、残った依存関係をできる限り単純で明白なものにすること
    • 不明瞭さとは、重要な情報が明白でない場合に発生
      • 依存関係に関連しており、依存関係が存在することが明らかでない場合
      • 不明瞭さは不十分な文書のために発生
      • 不明瞭さを減らす最良の方法は、システム設計を単純化すること
    • 依存性は、変化の増幅と高い認知負荷につながる。曖昧さは未知の未知を生み出し、また、認知的負荷の一因となる。依存性と不明瞭性を最小化する設計技法を見出すことができれば,ソフトウェアの複雑性を低減することができる
  • 複雑さの漸進的な性質によって制御が難しくなる
    • 複雑さは1つの破滅的なエラーによって引き起こされるのではなく、たくさんの小さな塊として蓄積されていく
    • 複雑さの増大を抑えるには、第3章で説明する「ゼロ・トレランス」哲学を採用する必要

3章要約

  • 3章 動作するコードでは不十分
  • 背景
    • プログラミング作業には戦術的プログラミングと戦略的プログラミングがある
    • できるだけ早く機能を動作させたいので戦術的プログラミングを採用することが多いが、戦略的プログラミングの方が良い設計を生み出しやすく、長期的に見て低コストになる
  • 戦術的プログラミングについて
    • タスクをできるだけ早く終わらせようとして最適な設計を探す時間を惜しむ
    • 複雑さはインクリメンタルなものなので、多くのプログラマーがこのようなやり方をしていると急速にシステムの複雑性は増す
    • 側から見ると、機能の完成が早い人を評価し、遅い人を評価しないとなるが、早い人は戦術的にプログラミングを行っている可能性がある
  • 戦略的プログラミングについて
    • コードが動くだけでは不十分という考えのもとに長期的な視点でプログラミングをする
    • システムの設計を改善する時間を確保する
    • ドキュメントを書くことも必要
  • 設計にはどれだけ時間をかけるか?
    • 継続的に少しずつ時間をかける。開発時間全体のおよそ10%〜20%くらいが良い
    • 戦術的プログラミングのコストと比べて、その初期コストはいずれ回収できる
  • スタートアップにおけるプログラミング方法
    • スタートアップにおいては機能を早くリリースすることが求められるため、戦術的に行っていることがほとんど
    • ある程度資金が確保できた後に良くしようと思っても手遅れ
    • 良いエンジニアを採用するにしてもコードベースがひどいと採用は難しくなる
    • スタートアップにおいても戦略的に行うことが必要

感想

3章はまだイントロ的な内容という印象です。
機能の完成が早い人を評価してしまうというのは自分もそういう風に思ってしまっていたので気付かされました。
長期的に見て、良いアウトプットをしているかを見ないといけないなと感じました。
昨今、アジャイルが注目されていますが、設計を考えずに機能開発を素早くというアジャイルっぽいやり方を一部否定しているのが面白いです。
アジャイルでもTDDのような設計を大事にするプラクティスはあるので、アジャイルのやり方自体を否定しているということではないと思います。
ただプロセスだけに従っていると今回の話に出てくるような罠にハマってしまいそうなので気をつける必要があるかなと思います。
また、具体的に10%~20%くらいは時間をかけようと言っているのも必要十分なコストになっている気がしていて、良いポイントだと思います。
そこまで膨大な時間をかけようとは言っていないので、アジャイル的なやり方とも親和性がありそうな考え方です。
自分もスタートアップに所属しているのでスタートアップの話は耳が痛いところです。
ひどいコードベースで苦労しているのを体験したり、見聞きしたりします。その度に大規模なリプレイスになることもあり、大きくコストがかかるのでうまくやらないといけないなと思います。
この本を学んでうまく改善できたら良いと思います。