ちょうぜつソフトウェア設計入門 ――PHPで理解するオブジェクト指向の活用:書籍案内|技術評論社
を読んだ。
感想
とても良い本だった。
オブジェクト指向は何でないか、というところを核にして、SOLID原則、デザインパターンやTDDといった広く知れ渡っている概念を時系列や要求に沿って説明してくれる本だった。
今まで、設計に悩んでいて手当たり次第に本を読み、何となく分かっているつもり、書けているつもりのところを改めて整理してもらったので、他人と話すときもある程度自信を持って話せるようになりそう。
読んでいたときのメモ
p26. 最初はちょっと分けすぎぐらいで十分
完全初心者から脱却すべくDRYを意識して…でコードを書くと、どれぐらい似たようなコードをまとめられるか、というところに目線を置いてしまいがちだったなということを思い出した。
最近はとりあえず分割して書いておいて、後から共通点が見つかればモジュールとかにまとめようとしているところだったので、その方針が間違っていなかったのかも、という自信を与えてくれる記述だった。
p.44 メソッドチェーンそのものに罪はない
デメテルの法則を知ったときに、メソッドチェーンそのものが悪なのかと思ってしまうこともあるかもしれないが、そうではないという話。
抽象度が同じオブジェクトを返すメソッドをつなげて書く、という便利に使えるようデザインされたものもあるので、あくまで隠蔽されている詳細を深掘りするようなコードを書くなということ
p.68 パッケージ
機能をパッケージに分割してアクセス制限するっていうの、普通にRails書いてたらやれないよなぁと思ったが、調べたところpackwerkというものがあるみたいだった。あとで読む
週刊Railsウォッチ: Packwerkの詳しい解説書『Gradual Modularization for Ruby and Rails』ほか(20221101前編)|TechRacho by BPS株式会社
Railsプロジェクトをモジュール分割して見通しをよくする|こんぴゅ|note
Packwerk でスパゲッティな Rails のコードをソーメンぐらいにさっぱりさせる
p.70 集約とコンポジションの違い
集約は所有者が既存のオブジェクトへの参照を保持する、コンポジションは所有者がオブジェクトを専有する。
集約では2つのオブジェクトはそれぞれ存在できるが、コンポジションは所有者が消えれば意味をなさなくなる、という形で覚えておけば良さそう。
dependent: :destroy
はコンポジションのサインのような気がする
DDDとUMLで同じ集約というワードが使われているが、意味が異なるので気をつける
p.87 FizzBuzzの抽象化
あんまり見たことない形のFizzBuzzのリファクタリング例で面白かった。
特定の条件に合致すれば文字を置き換える、という部分をコアとして、ルールを生成しそれらを回すクラスを作るみたいな感じ。
何が業務のコアで、将来どのような機能が追加される可能性があるのか、を意識して設計するのが大事だというのは実感としてあったけど、FizzBuzzでそれをやるというところが良かった。
p.94 派生クラスは基底クラスの条件を逸脱してはいけない
リスコフの置換原則の話。
派生クラス側で条件を増やす形で定義してしまうと、基底クラスとして呼ばれたときに条件から外れる形で実行されてしまう。
置き換え可能、という説明をよくされるけど単に呼び出しができるだけじゃなくて、実行時の事後条件、事前条件が一致してないと駄目だということ。
p.114 依存関係逆転原則の意味
普通にプログラム書いてると依存構造と制御構造が一致するのだけれど、どちらが安定しているかはその時々だから、インターフェースを使ってそれに制御構造に縛られず、安定したものに依存するようしましょうね、という話。
p.146, 170 TDDは設計のための技法
TDDをBDD(振る舞い駆動設計)を対比させて説明するときに出てきた。
TDDが実動作とは軸の異なる設計のメカニズムを作るのに役立つという話。BDDのテストが実動作を担保するのに役立つのと対比して、TDDはアーキテクチャが成立していることを確認する。
フレームワークを使っているときに、過剰に単体テストを積み上げることにも言及していて良かった。
このへん、話はわかるんだけどじゃあ実際にTDDで進めていくときにどうアーキテクチャを見出していくのか、というのは完全には理解できてないので読み返すなどしたい。
p.187 サービスロケータはアンチパターン
サービスロケータはDIコンテナと一見似てるけど、実質グローバル変数だから単体テストのやりやすさとか、依存が手続きの中に埋もれてしまうとかデメリットあるアンチパターンだよという話
p.192 オートワイヤリングの意義
オートワイヤリングを使って記述を省略することで、DIをするときにクラス側ではコンストラクタに引数を設けるだけで良くなる。
DI、大事なのは分かるけど記述量増えて面倒なんだよな~って思ってたのでなるほどという感じ
p.206 Templateパターンを使うときにもInterfaceに依存する
利用者側がAbstractTemplateに依存していると、Template側の変更が利用側に影響するのを避けられない。
また、Template側で吸収できない差分が必要になったときに結局呼び出し側も変更することになってしまうので、Interfaceに依存する形にしておく
p.207 Bridge
多重継承を避けたい、言語的にできないときにis-a
の関係をhas-a
の関係と捉え直す
p.230 Facadeの裏口に注意
複雑な処理を利用者側にシンプルに公開する、というのはソフトウェアの色々なところで行われているが、ちゃんと利用がそこで集中しているか、裏口(詳細)に立ち入っていないかをチェックする
p.235 連携に関する複雑さをMdiatorに移す
循環依存構造を回避するために、仲立ちとなるクラスを設けるようなイメージ
p.221 Factoryが抽象を生成するとき、Factory自体も抽象にする
分かるような分からないような部分。
ナイーブに書くと利用側のパッケージが具象クラス、具象ファクトリに依存する。そこでファクトリから生成されるクラスだけを抽象にしても具象ファクトリに依存していたら意味は無いので、どちらも抽象にして依存関係を安定方向に向けるようにしましょうねという話かなと理解している。
どうしてもパッケージという考え方が身についてない感じがするのでこの辺課題感ある。
p.255 Strategyは外部から振る舞いを与える、Strategyは引数として受け取った情報しか使えない
Temlateとの対比がわかりやすかったのでメモ。
p.256 State自身がNextStateメソッドを持つ
パターンの話ではないが、良い設計だなと思った
p.260 StateとStrategyの違い
Strategyは振る舞いを表すオブジェクトの切り替えが外部トリガー、Stateは内部でいつの間にか起きている
p.265 Commandオブジェクトを変数に保持できることのメリット
コマンドをキューイングして実行を遅らせたり、キャンセルできるような余地が生まれる
あとCQSを単にSQLのInsert, UpdateとSELECTを分離するだけのものと誤解していたのがわかった。
同期的に応答を待つような処理を分離するスケーリングのための手法ということね。
p.271 VisitorとIteratorの違い
Iteratorはループを書く、Visitorは各要素に関数を適用する。
Visitor側はrubyのブロック引数みたいなものかなという理解
こういう記事があった
Visiterパターンとブロック - Journal InTime(2006-09-22)
p.281 サービスとしてのファクトリ
このあたりちょっと分かりそうで分からなかった
p.284 MDD(モデル駆動設計)
MDDでは実機能をモックしたモデルコードを実際に書いてみることでモデリングを進めていく
これができたらたしかに良さそう。ActiveRecordでテーブルがちゃがちゃする前にPOROで書いてみて整理するみたいな感じかな。
p.299 ウォーターフォール開発は史実らしいフィクションとして生まれてきた言葉
問題点を強調するために作られた架空の方法論がなぜか現場で採用されていった経緯が書かれていて面白かった
踏まえて読みたい本
エリック・エヴァンスのDDDの本が途中で投げられているので、それを読みたい。
あとTDDは単にテスト先に書く、だけでなくてもっとそれが必要とされるようになった経緯みたいなところから、設計に活かす部分まで知りたい。