DoorKeeper
https://jsug.doorkeeper.jp/events/58637
DDDやICONIXの読書会に参加しつつ仕事でSpringを触っている私にとって、このイベントはとてもピンポイントで、とても楽しみでした。
増田さんの講演は何回も聞きに行ってますが、毎回新しい発見があります。
以下、講演中に取った自分復習用のメモ。
講演:ドメインロジックに集中せよ
モデルに基づき設計する
- モデルを使わない開発プロセスの場合、バックログ(機能一覧)に沿って消化していく。木をブレークダウンしていく。
- これはドメインモデルの考え方ではない。
- 開発プロセスにモデリングを1つ入れると、全体の見通しがよくなる。
- モデルが無いと、羅針盤・地図が無い状態で開発することになる。
- モデルを使うことが複雑さに立ち向かうことに効果がある。
- モデルを作ればドキュメントがいらなくなる、ということではない。
インクリメンタルに開発する
- 開発メンバは情報収集から分析、設計、実装、運用まで全部やる。
- day-1のうちからとにかく動かす。Spring Bootを使えばすばやく立ち上げられる。
アンチパターン
- プレゼンテーション層やデータ層にロジックがはいる。
- ドメインロジックは3層にばら撒かれがち。
- これもSpringの1つの使い方ではあるが。。。
ドメインモデル
- ドメインモデルはPoEAA(エンタープライズ アプリケーションアーキテクチャパターン)から来ている。
- ドメインモデルは、振る舞いとデータが一緒にある。
- 巷のOOはgetter/setterだけを持ったデータクラスとか設けるほうが一般的だが、DDDはそうじゃない。
- ドメインモデルの利点は、変更が楽で安全になること。
トランザクションスクリプト
- 機能一覧を作って分担して各自作り込めば、どうしてもロジックが重複しがちになる。
- 変更を考えると、どこに何が書いてあるか探すのが大変。
ドメインロジックの置き場所
- 値オブジェクト
- コレクションオブジェクト
- 区分オブジェクト
値オブジェクト
- 値オブジェクトは「1つ」のオブジェクト。
コレクションオブジェクト
- Listでデータを持って、操作を全部隠す。
区分オブジェクト
- これだけでもJavaを使う価値がある。
- 区分オブジェクトのEnumに振る舞いを持たせちゃう。
ドメインロジックのモジュール化
- トランザクションスクリプトのモジュール分割は、部品化の切り口が不明確になりがち
- 例えば、受注登録の中のロジックをどう切り分けるかが難しい
構造化:記述レベルの階層化
- 記述レベルをレイヤーで構造化する。
- 「ドメイン固有API」を3層の間に入れる。ここを相当考える。
- JavaコアAPIだけでも行けること多いが、1つ上にドメイン固有APIの層を入れる。
- アプリ動かすだけならドメイン固有APIの層は明らかにオーバーヘッドだが、この層を入れることによりドメインを扱いやすくなる。
ドメインロジックの自己文書化
- ドメインロジックの文書化はソースコードでやる。
- ドメインオブジェクトを参照する3層にもドメインの型が入り込んでくる。
- これにより他の層のクラスも、ドメインロジックとどう関係してるか語られるようになる。
- これが変更容易性に直結する
- 業務マニュアルとか利用者ガイドはすごく重要。必ず作る。保守マニュアルになる。
- ドメイン側の知識として非常に重要。可能なら開発と平行で作って欲しい。
ドメインを隔離する
- Springのアノテーション(@Controller、@Service、@Repository)を付けたところにはドメインロジックを入れない。
- ドメインモデルにはSpringのアノテーションは入れない。
- 自然にこうなるはず。
- ドメインモデル以外は、データの入出力。
- 「データの入出力」と「ドメインモデル」と、関心事が大きく2つ分かれる
- 関心事が反対側に埋め込まれないことが、ドメインロジックに集中するということ。
プレゼンテーション層とドメインオブジェクト
- テンプレートにドメインオブジェクトをマッピングする。
- DTOとかFormオブジェクトを別に設けることは原則していない。
- プレゼンテーション層にちょっとしたif文とかも書かない。可能な限り書かない。
- そこまで徹底することで、ドメインオブジェクトにロジックをどんどん入れていく。
- 変更があったときに、どっちが変更の範囲を閉じ込めやすいか、という観点でドメインオブジェクトに徹底的に抜く
- Beanスタイルのバインディングは使わない。
- Thymeleafにドメインオブジェクトをそのまま渡して参照させる。
- ビューにもドメインを語らせたい。
- (PRGパターン、という用語が出てきたのでググってみた: TERASOLUNA:PRG(Post-Redirect-Get)パターンについて)
Direct Field Access
- gette/setter全く関係なく直接フィールドを読む。
- getter/setterをなくすことで、ドメインロジックにすごく集中できる。これはやってみないとわからない。
- @haljik さんが #kanjava でこの件について相当いい資料をあげている。
アプリケーション層とドメインオブジェクト
- 記録/参照はリポジトリパターンを使う。データベースの都合をドメインオブジェクトに持ち込まない。
- プレゼンテーション層とデータソース層の間のやりとりはアプリケーション層が仲介する。
- 業務ロジックはドメイン層が担う。
- サービスクラスに@Validatedを付けておくと、バリデーションロジックが賭けちゃう。「契約による設計」
- Bean Validationを使えると、そうとう細かいところまでチェックできる。
- リポジトリを@AutowiredでDIする。
- データソース層がドメイン層に依存するようになる。
- ドメイン層にsave()とかregister()を持たせるのか、持たせないのかは議論の余地がある。
データソース層とドメインオブジェクト
- オブジェクトとテーブルはまったく別という扱い。
- 異なる世界は手作業で明示的にマッピングする。自動マッピングさせない。そのほうが変更に強い。
- データ保存の概念と業務の分割の概念は必ずしも一致しない。なので手作業で明示的にマッピングする。
- テーブルは徹底的に正規化する。テーブルには参照制約とか一意性制約とかは入れまくる。
- <resultMap>のtype属性にドメインオブジェクトを指定し、明示的にマッピングする。
- SQLがどのドメインに関心があるか、自己文書化させる。
トークセッション「ドメインロジックの実装方法の選択」
モデレータはJSUG会長の長谷川さん。トークは増田さん、Grailsの綿引さん、TERASOLUNAの池谷さんの3名でした。
Q: DDDをやりたいけど、どうしてもトランザクションスクリプトになってしまう・・・どうすれば?
どうしてもトランザクションスクリプトになってしまう原因は、トランザクションスクリプトに実績があるから。
なのでDDDは浸透してない。しかもアジャイルじゃない。どうすれば?
---
増田さん:
- 変える気ありますか?
- トランザクションスクリプトの仕事は受けないくらい気概で行ってる。
綿引さん:
- DDDの案件で増田さんと一緒に仕事をしていたが、増田さんがリードしないと無理だな、と感じた。
- まず変わりたい、という時に、リードする人いないと難しいと思う。
Q: リードする人がいないとDDDできないなら、1000人規模のプロジェクトではDDDできないのでは?
池谷さん:- 数百人にDDDの本を読ませてできるようにするのに、1ヶ月とか掛かってしまう。
- なのでトランザクションスクリプトに落ち着くのが現実。
- 難しい点として、共通化を図ると、それがクリティカルパスになるところが出る。
- 共通化して開発したいところだが、共通化でネックになることがある。
増田さん
- 経験者を作るのは相当ハードル高い。
- でも、トップレベルのエンジニアを作らなくても、1ヶ月DDDを教育することによるメリットは相当ある。
- 消費税計算とかだけドメインオブジェクトを作るとか、段階的にDDDにするのはけっこう出来ると思う。
- if文の巣になってるとこを見つけてそこから直していくとか。
- ヤル気があればできるところってけっこうある。
- 200人規模ならDDDをやる、って責任はとれないけど、10人くらいなら責任もてると思う。
Q: オブジェクトを共通部品化すると配る必要があるが、大規模プロジェクトだと大変・・・・どうすれば?
増田さん:
- ドメインは最初から全部は分からないので、最初に全部を部品化するの無理がある。
Q: ウォーターフォールでDDDは無理か?
増田さん:
- 資料でも、あえて「アジャイル」とうい言葉は使っていない。
- ウォーターフォールでも行けると思っているが、伝言ゲームはダメ。
- ウォーターフォールでフェーズがあっても、同じ人間が最後までやるならDDDできると思う。
- NTTデータさんがすこしDDDに舵を切るだけでも、世界はだいぶ変わる。
池谷さん:
- DDD本を全部やるのではなく、できるところかやるなら行けると思った。
増田さん:
- 現場のリーダーの裁量の範囲くらいで、できる範囲からやっていってほしい。
Q: やったことない分野でドメインオブジェクトをどう抜きだせばよいか?
増田さん:- その業界のオンラインヘルプ見たりとか、あとは書籍とかから抜く。会計なら、初心者向けの会計本とか。
- 最初はぜんぜんわかんないけど、目次とかから拾っていく。
- 最初はぜんぜんわかんないけど、まず触れることが大事。
- さすがにイテレーションのday-1には全部できないけど、1イテレーションの最後にはできてないとダメ。
Q: 言葉の持ち主は誰?
増田さん:- 持ち主はエンジニア。業務用語はお客さんが持ち主。
- 業務用語集とかを作ってお客さんに渡したりはしていない。
- メンテをかけるのはエンジニアなんだから、エンジニアがメンテしてドメインにマッピングする。
Q: 日本語だと、業務用語とプログラム変数名に差異が出てしまう。
綿引さん:- 日本語を英語にすると、変数名がめちゃくちゃ長くなってしまう。
- エリック・エヴァンスににどうすればいいか聞いてみたら、「なんで日本語で書かないんだ?」と言われた。
- 変数名を漢字で書くと、複数形とかが表現できない。あと、メソッドとフィールドが区別できなくなったりする。
増田さん:
- enumの区分名は日本語にしている。
- プロダクトコードで名称を日本語で書くのは一度やったことがあるけど、違和感があった。
池谷さん:
- 英語の変数名から母音を抜いて、子音だけで変数名を作るとかある。
Q: DDDをやる上で何かコツはあるか?
増田さん:- 値オブジェクトがコツ。
- オーバーヘッドでめんどくさいなぁ、と最初は思うけど、やってみると良さを実感する。
- DBってカラムたくさんあるけど、だいたいすべて同じ型だったりする。
- なので、値オブジェクトを組み合わせることできたりする。
Q: ORマッパーは、MyBatis以外でもDDDできるか?
JPAでも出来ると思っている。Q: 実行順序性の制御はどうすれば?
増田さん:オブジェクトが独立して組み合わせてできないかな、と思ってる。
順番に処理することを無くしたい。ばらばらに呼び出しても、辻褄が合うようにしたい。でも難しい。
順序依存性があるときは、アプリケーション層に制御を持ち込んでいる。ドメイン層には持ち込んでいない。
感想
DDDって抽象的な議論になりがちだけど、こーゆうコードありきで説明いただけると大変助かります。Springを使ってる身としては、ピンポイントで参考になりました。
増田さんの「ドメインを隔離する」のスライド、4層を縦に並べず、ドメインモデルを3層から分離してその横に書いてますよね。
ドメインモデルが3層から分離され、3層から呼び出されるような図になってます。
この表現の仕方はとても良いと思いました。
というのも、DDD本の4章でレイヤー化アーキテクチャの図が出てきますが、4層が縦に並んだ図になっていて、ドメイン層が分離されている、というイメージが沸かないんですよね・・・
説明の表も縦に4層並んでるし。最初DDD本読んだ時、4層の関係が掴めずにモヤモヤしたもんでした。
あと、会場提供のPivotalさん、懇親会でピザやビールを無料で振る舞ってくださるのも凄いなぁと。
おいしく戴きました。感謝!
あと、こちらもよかったらどぞー
Spring Framework&DDDに興味を持たれた方、ユースケース駆動開発実践ガイドの読書会いかがっすか~
— makopi23 (@makopi23) 2017年3月28日
https://t.co/iIE8cZubNP
ちなみに今んトコ皆勤賞。環境構築のブログ先日書きましたhttps://t.co/scoIzF7Dlm#JSUG
関係者の皆様、ありがとーございました。