daisuzz.log

A philosophy of software design 7 ~ 9章を読んだメモ

A Philosophy of Software Designを読んだので忘備録としてまとめていきます。

A Philosophy of Software Design

A Philosophy of Software Design

7章 Different Layer, Different Abstraction

Pass through method

AがBのメソッドを呼んでBがCのメソッドを呼んでいる場合に、AからCを直接呼ぶか、Aの中にCの処理を書いてしまえばよいのでは?という話。機能は増えないのにインターフェースが増えるため無駄な複雑さや、クラス間の依存性を生み出してしまう。2つのクラス間の責務が明確になっていないことが原因なので、責務がどちらのクラスにあるのかを考えること。リファクタリングする場合、低レイヤを直接参照するか、クラスを分割するか、クラスをマージするか。

pass through variables

aという変数がA -> B -> Cのメソッドの中で何度も引数として渡されているケース。実際はそのメソッドで使用しないにもかかわらず、引数として変数を意識しなくてはいけないため複雑さが増えてしまったり、変数の修正による影響範囲が増えてしまう。 リファクタリングする場合、共有オブジェクトの中に格納したり、グローバル変数に入れたり、context objectを使う方法がある。

8章 Pull Complexity Downwards

実装をシンプルにするために呼び出し側に負担をかけるのではなく、インターフェースをシンプルにすることの方が重要。

むやみに外部設定値にまとめるのではなくて、ユーザが設定することが適切な値のみを外部設定値としてユーザに公開するべき。 TCPの再送時間をユーザが設定すべきではない。外部設定値を書きたくなったらユーザと開発者どちらが適切な値を設定できるか考える。 ユーザに複雑さを見せるのではなく、少し苦労してでも開発者側で複雑さを処理すべき。

9章 Better Together Or Better Apart

2つの機能を同じメソッド、クラス、サービスに実装するか分離して実装するか?という話。 分離して実装するとモジュール1つ1つはシンプルになるが、モジュールの数が増えてしまうので、開発者に負担をかけてしまうこともある。 情報を共有していたり、インターフェースをシンプルにしたかったり、重複したコードを無くしたいのであれば分離せずに実装すべき。

汎用的に使われるモジュールに特定用途の処理を入れてはいけない。そういう場合は別のモジュールに切り出す。 同じ処理が、いろいろな箇所で出てくる場合、適切な抽象化ができていない。 汎用的な処理を低レイヤに、特定用途の処理を高レイヤに移すことを意識する。

システム全体がシンプルになるのであれば分割すべきだが、読みやすくシンプルなインターフェースになっているならば分割する必要がない。 汎用的なサブタスクをメソッドに切り出したり、関連していないことを複数やろうとしているメソッドは分割する。 ただ、呼び出し元が両方呼び出すのであれば、あまり分割の意味がない。呼び出し元がシンプルになるかどうかを考えればよい。