久しぶりにDDDのイベントいってきました。
スライドとあわせて読むメモ。
ドメインオブジェクト
- どうやって見つけるか
- どうやって作るか
- どうやって育てるか
考え方とやり方
- ThoughtWorksアンソロジー
- リファクタリング
- イヤな匂いと改善策
今回は具体的な話
アジェンダ
- 設計の基本
- 見つけ方
- 作り方
- コード寄りの話
- 育て方
- これもコード寄り
4冊に共通する価値観
複雑なものは変化していかなければいけない、自分たちも変わる必要があるという考え方
完全に予測するのは不可能。
最初に定義してその通りにやるのはツラい
DDDはそれに対するノウハウ集
オブジェクト指向の開発スタイル
アジャイルとオブジェクト指向片方ずつでは成立しないだろう
作る→オブジェクト指向
プロセス→アジャイル
側面としてはデザイン、プロセスの見方だけど、目指してるものはそれぞれ同じはず
言葉大事
Iterative, Incremental, Interactiveの相乗効果
設計の基本
根本はモジュール性
独立性の高い部品を作ることがよいものを作ることに繋がる
機能分割のモジュールとオブジェクト指向のモジュール性を論じると絶対噛み合わない
前提として「オブジェクト指向のモジュール性」というコンテキストで話さないといけない。
モジュール性
「オブジェクト指向入門」 バートランドメイヤー
モジュール性をすげー取り上げてる
モジュール性の評価基準
- 分解しやすい
- 組み合わせやすい
- 分解した後組立直しやすいか
- 最初の通りじゃないと組み立てられないのはアカン
- これがオブジェクト指向と機能分解という意味のモジュール性の分解点
- わかりやすい
- 連続性
- 例えば丸め計算
- 消費税の丸めを四捨五入から切り捨てにする
- 上の一つの変更要求をありとあらゆる機能全てをテストしなきゃいけないのはよくない
- 仕様の変更とコードの変更が同じだけついていけること
- 保護性
簡単に言えば、変更が容易なのがよいモジュール性、大変なのが悪いモジュール性
2つのアプローチ
機能クラスとデータクラスに分けるのがよく使われる(機能分割のコンテキスト)
本で言ってるのは抽象データ型として作ることを言っている(オブジェクト指向のコンテキスト)
機能分割
元々はC言語やCOBOLの設計スタイルをJavaに適用したもの
伝統的なBeanの作り方
Sun自身がこれを推奨していた
オブジェクト指向らしく作ろうとするとこのアプローチは違う
JPAは失敗したEJBの焼き直し
これらのセカイでJava使って作ってると、今回の話は謎に見えるかもしれない
違うパラダイムの話
抽象データ型
外から見たときにどう見えるか、内部で見た場合の違いの話
内部でどういう処理ロジックで書かれてるかは関係ない。
BigDecimal
とか見るといいよ
何をしたいかと内部でやってることを分けるという考え方
モジュール性の比較
機能分割でやると
- 分解しやすい
だけ
オブジェクト指向
- 分解しやすい
- 組み合わせやすい
- わかりやすい
- 連続性
- 保護性
機能分割とは違ったアプローチの仕方
体で覚えてきたもの
- オブジェクト指向エクササイズ 9つのルール
- リファクタリング イヤな匂いとその改善
- ドメイン駆動設計 しなやかな設計の6つのパターン
開発中盤に大きな仕様変更が入っても無駄になる感覚はない
なぜかというと部品でやってるから組み合わせを変えるだけだから
モジュール性に優れたオブジェクト
- オブジェクト指向エクササイズ 9つのルール
- リファクタリング イヤな臭い
ドメインオブジェクトの見つけ方
ドメインを学ぶ→言葉で会話を交わす→コードに落とす→(繰り返し)……
実際にどうやってるか
アソビューさんの例
説明を聞いたときに出てくる言葉が引っかかる→ドメインの学びの始まり
利用規約はドメインモデルそのもの
ビジネスとシステム開発が近い関係でできるのでいい。
ラフスケッチはいきなりこんなキレイにはなってない
コードドリブン
関心事の見つけ方
ヒトというのは複雑で特別な関心事
そのドメインをうまく理解するために、ヒト・モノ・コトを理解する
やってるうちにこういうのをコードで作っちゃう
最初からいい名前見つけるのは大変
ドメインオブジェクトの作り方
基本データ型に対して色々やるというロジックになる
それをどうモジュールにするか
オブジェクト指向エクササイズに沿って書いてれば黙っててもいい感じになる
getterを使わない
小さなクラスになるのでモジュール性が高まる
主役は値オブジェクト
業務ロジックがどんどん値オブジェクトに書かれるようになる
例えば…
1000で割って表示する、みたいなちょっとした式が色んなところに点在しなくなる
nullを渡さない、戻さないなど、オブジェクト全員が守れば、正しくできるはず
約束をハッキリさせようという考え方
育て方
ドメインを隔離する
値オブジェクトはfundamentals
ドメインモデルはmodel
Spring Boot
コントローラ、サービスクラスはほぼスカスカ
ほとんどロジックを書かなくていいはず
コントローラとかサービスが複雑になってくるとそれはドメイン知識が漏れ出してる
if文一個書けば解決するってのはまあわかる
グラフ構造(ドメインのモジュール)とリスト構造(現実)
データをどう扱いたいかだけに関心がある
こっちに引っ張られるとドメインの表現がショボくなる
手っ取り早く書くなら内部の構造にあわせた方が早い。けど…。
良さが失われる。
妥協したところから腐り始める
フレームワークの都合を排除する
MyBatis SQL Mapper
Jsonはpath記法で書けなくはないけど乱雑になっちゃうからやらない
育て方のシナリオ
手っ取り早く動かせるようにするんだけど、ちゃんとやらなきゃいけないんだよというプレッシャーのもとにやる。
野放図に妥協してるわけじゃない。
getterあたりを手がかりに複雑になってる場所を見つける
- コードの重複
- 式
- Value Objectに持たせちゃった方がいいんじゃないか
- 長いメソッド
- 50越えたら大きいクラス
- メソッドが5行越えたら怪しい
- VOにロジックを寄せたらそんな長くならない
- 大きなクラス
- 引数の多さ
- 2コ以上になってくるとドメインオブジェクトの置き方間違ってる説
メソッドの抽出
5行も6行も改行が入らず連続してたら抽出できるかも
メソッドに抽出するときに名前を考えなきゃいけなくなる→ここ頑張りポイント!
ぎこちなくても良いからメソッドに抽出してしまう
怪しい名前は気になるので改善したくなる
改行でグルーピングすることで止めちゃうとそれ以降触られなくなるので絶対ダメ、ダメ絶対
クラス名で名前考えた後にメソッド名考えた方が楽
一時変数を値オブジェクトに
けっこう大変
メソッド名を名刺に変える→その名前のクラスを作る→メソッド毎コピーする
区分オブジェクトのパターンは相当コードがキレイになる,オススメ。
振る舞いを豊かにするメソッド候補
- 文字列で表現する
- 文字列空生成する
- 同一性の判定
- 業務的な意味の同一性
- 比較・順序づけ
- 計算
- 列挙
- 上限・下限
元ネタはHaskellの型クラス
10章 しなやかな設計
ぶっちゃけわかりづらい
チェックリストとして優れているからモジュール改善のチェックリストとして使う
まとめ
- ごちゃごちゃしてきたら整理
- 整理の基本はメソッドの抽出と移動
- 7つの視点で振る舞いを豊かに
まとめ
できない理由
- 今の○○ではムリ
- DDDにしたい意思があるならこのメッセージを
ケントベックのメッセージを思い出す
ドメイン駆動設計への道
ドメインの言葉で話すことで怒られることはない
QA
- リファクタリングがツラい
- IntelliJ IDEA素晴らしい
- クラス多いときにレビューがツラい
- 意外と障害になりそう
- その人がどういう風に考えてるか見えるので興味がある
- コンテキストを越えて使いたい型はどうするか
- コピーして使ってる
- それぞれのコンテキストで成長していくもの
- モジュール間の依存関係が複雑な場合のテストはどうしてるか
- そんな複雑なのは改善できるんじゃないか?
- ドメインオブジェクトにはテストコード書いてない
- ドメインオブジェクトを使ったサービスレベル、E2Eのテストはしてる
- リファクタリングすごいやるからテストコード直していくのがヤダ
- テストを否定してるわけじゃない