はじめに
「オブジェクト設計スタイルガイド」を読んでみたので感想を書きます。
対象者
この記事は下記のような人を対象にしています。
- 中級エンジニア
- 言われたコードは書けるようになったが、設計がさっぱりなエンジニア
- エンティティとかバリューオブジェクトについて知りたい人
結論
下記の2つの図に全てが要約されています。
そして、この本は10章から読むのがおすすめです!
-
marmaidのコード
flowchart TD subgraph outer["<div style='font-size:6px'><br><b>【インフラストラクチャ】</b><br>- コントローラ<br>- ライトとリードモデルリポジトリの実装</div>"] style outer fill:#FFFEBA,stroke:#333,stroke-width:3px,rx:2000,ry:2000 subgraph middle["<div style='font-size:6px'><br>【アプリケーション】<br>- アプリケーションサービス / - リードモデル<br>- リードモデルリポジトリのインターフェース / - イベントリスナ</div>"] style middle fill:#BCFFBA,stroke:#333,stroke-width:2px,rx:1000,ry:1000 subgraph inner["<div style='font-size:6px'>【ドメイン】<br>- エンティティ<br>- バリューオブジェクト<br>- ライトモデルリポジトリのインターフェース</div>"] style inner fill:#FF98FE,stroke:#333,stroke-width:1px,rx:500,ry:300 end end end -
marmaidのコード
flowchart TD A["フロントコントローラ"] -- リクエスト転送 --> B["コントローラ"] B -- 情報取得・表示 --> C["リードモデル"] B -- タスク実行 --> D["アプリケーション<br>サービス"] C -- 管理される --> n2["リードモデル<br>リポジトリ"] D -- 情報取得・意思決定 --> C D -- 作成・変更 --> n1["エンティティ<br>or<br>ライトモデル"] C -- 参照 --> n1 n1 -- 管理される --> n3["ライトモデル<br>リポジトリ"] n1 -- 記録 --> n4["ドメインイベント"] D -- ディスパッチ --> n4 n5["イベント<br>サブスクライバ"] -- リッスン --> n4 classDef controller fill:#f9f,stroke:#333,stroke-width:1px; classDef read fill:#bbf,stroke:#333,stroke-width:1px; classDef write fill:#bfb,stroke:#333,stroke-width:1px; classDef event fill:#ffb,stroke:#333,stroke-width:1px; class A,B controller; class C,n2 read; class D,n1,n3 write; class n4,n5 event;
わかったこと
この本は後半になればなるほど具体的な説明が増えます。
前半は概念やルールの話が多く、あまり頭に入ってきませんでした...
したがって、結論ファーストな人は後半の章のまとめから読み始めるのがおすすめです。
章ごとに感想や、理解した内容を書きます。
1. オブジェクトを使ったプログラミング入門
- あんまりオブジェクト指向のメリットとかは説明してくれない
- すでに「オブジェクト使いたい!」ってなってる人向けなんだな、って感じ
2. サービスの作成
- いわゆるコントローラやリポジトリのこと
- インスタンス化
- 依存関係の注入
- コンストラクタ
- コンストラクタ引数とメソッド引数
- イミュータブルにする方法
- あやふやな概念を難しい専門用語で説明されるので、正直、半分くらいしかわからん
3. ほかのオブジェクトの作成
- いわゆるバリューオブジェクトとエンティティのこと
- DTOもあるよ
- 正直、上記3種のオブジェクトの違いが分からなかった
- 名前つきコンストラクタ
4. オブジェクトの操作
- 前章の疑問が解決。説明下手くそか。
- エンティティ:変更を追跡し、イベントを記録する
- ミュータブル
- 戻り値はvoid
- メソッド名は命令形
- 内部情報は公開されない(その代わり、変更履歴を残す)
- バリューオブジェクト:置き換え可能、匿名、イミュータブルな値
- エンティティの一部
- プリミティブ型の値をラップしたイミュータブルなオブジェクト
- DTO:データの整合性を保持したい時に使う
5. オブジェクトの使用
- メソッド実装の5つのコツ
- 事前条件のチェック
- 失敗のシナリオ
- ハッピーパス
- 事後条件のチェック
- voidもしくは特定の方の値を返却
6. 情報の取得
- コマンドメソッド:タスクを実行する。返り値がvoid+副作用がある(DB書き込みする、など)
- クエリメソッド:情報を取得する。返り値がvoid以外+副作用がない(DBから取得するだけ、など)
- コマンドクエリ分離原則(CQS)
- 極力nullを返さないようにする
7. タスクの実行
8. 責務の分割
- ライトモデル:コマンドモデルとも。
- リードモデル:クエリモデル、クエリサービスとも。
- 情報の取得のみを扱う。
- DBへの書き込みが必要ない場合はVO使うのは過剰なので、クエリサービス使いましょうってこと?
- 特定のユースケース向けのクエリサービスがあっても良い
9. サービスの振る舞いの変更
- インターフェースの導入による依存関係の注入
- 基本的にクラスはfinal、メソッドはprivateが好ましい
10. オブジェクトフィールドガイド
- ぶっちゃけ、この本の価値はこの章に詰まっている。
- 最初にこの章を読むのがおすすめ。
- コントローラ(具象的)
- リクエストを受け取る場所
- インフラストラクチャコード(SQLやファイル書き込み)が含まれる
- アプリケーションサービス、リードモデルを呼び出している
- アプリケーションサービス(具象的)
- 単一のタスクを実行する
- インフラストラクチャコードを含まない
- ユースケースを記述している
- ライトモデルリポジトリ(抽象的)
- インターフェースとも
- データの取得や保存を提供する抽象
- エンティティ(具象的)
- idなどで識別できる
- ライフサイクルがある
- ライトモデルリポジトリにより永続化され、後から取得できる
- インスタンス化できる
- バリューオブジェクト(具象的)
- イミュータブル
- プリミティブ型のデータをラップしている
- ドメイン固有の型をもっている
- イベントリスナ
- イミュータブルなサービス
- ドメインイベントを引数として持つメソッドを含む
- リードモデル
- クエリサービスとも
- ユースケースに特化したクエリメソッドを含む
- リードモデルリポジトリ(抽象的)
- イミュータブル
- クエリメソッドのみを持つ
おわりに
「オブジェクト設計スタイルガイド」の感想をまとめました。

