目的
アーキテクチャの話に振り回される前に普遍的な設計指針を持つべきと考えるようになり、DDDをベースに考えていくのが良さそう、という結論に至ったのが2月くらい。それから徐々にDDD本を読み進めている。
一冊目がドメイン駆動設計入門、今読み終わった二冊目が実践ドメイン駆動設計。
重複する内容も合ったがその分深い部分まで理解が進んだ。また、2冊目で新しく学んだ内容もハードルが下がった分わかりやすかった。少し遠回りしたかもしれないが、自分の中で咀嚼する余裕があったため普通に読むよりも定着していると思う。
読み進め方としては、以下のような感じ。
- 各要素(ドメインモデル、サービスなど)の概要を理解したら過去の自分の経験と比較し、適用できそうなケースを探す
- 適用したことで何が良くなるのか、良くならないのか、別の課題が発生しないか?を考える
- 設計が変わったことで他のコンポーネントも影響を受けるはずなので、その部分はDDDでどれに対応するのか考え、1に戻る
今担当しているプロダクトの改善案をいくつか思いつき、実践で適用していくモチベーションがアップしている。また、新機能開発では既にいくつかエッセンスを取り入れていて、見通しがよくなっている。レビューでも説得力がある指摘をできるようになった。
もっと早く学んでおけばよかったという後悔がある一方で、過去の自分だと理解は難しかったとも思っている。30代半ばに近づいてきてようやく理解できるスキルに到達できた、とポジティブに捉えている。
ドメインと境界づけられたコンテキスト
ドメイン
は事業を取り巻く世界、区分けの事。
一口に世界と言っても曖昧で広いので、関心の範囲を線引して境界づけられたコンテキスト
内で要件を検討する。
現代の業務で扱うドメインは複雑で、複数のドメインが絡み合って一つのドメインとなっていることが多い。その場合、コアドメイン
とサブドメイン
に切り分け、それらが一つのドメインを作り上げているという風に見る。
境界づけられたコンテキストの範囲は各ドメインの領域と同じになっていることが理想だが、システムとしてそうなっていないことも多い(巨大なモノリシック、不適切な範囲で分割されたモジュール、外部システムとの連携など)。そのため、既存システムを扱うときはドメインと境界づけられたコンテキストの範囲を正しく把握することが重要。
エンティティ・値オブジェクト・ドメインサービス
エンティティは一意のもの。必要なフィールドが全て同じであっても区別すべきオブジェクト。DDDのコンテキストにおいて、単なるテーブルオブジェクトではない。
値オブジェクトはその逆で、フィールドが同じ場合は区別しなくてよいオブジェクト。値の入れ物。
会社というドメインの中では、社員はエンティティ、社員が持っている名刺は値オブジェクト。PCは、ドメイン仕様に応じてエンティティとして扱う場合も、値オブジェクトとして扱う場合もあるかもしれない(会社はほとんどの資産をIDを付与して管理しているので、会社ドメインの値オブジェクトは探しづらい)。
ドメインサービスは、ドメインに特化したステートレスな処理を行うもの。staticなMethodで実現したくなるもの。
ドメインイベントはドメイン内で発生したドメインエキスパートが気にかける出来事
。ただの仕様というものにとどまらず、〇〇になったら
〇〇のときに
の様に名前をつけて表現すべき状態やアクションを指すことが多い。pub-subで通知したいイベントとして理解した。
モジュールと集約・ファクトリ・リポジトリ
不変的なルールや維持すべき整合性を表現する方法として集約がある。集約の単位を大きくしすぎるとドメインルールを見落とすリスクが高そうなので、極力小さくすることを心がけたい。集約同士が連携しあってそれぞれのレイヤーのルールを実現していくイメージ。
モジュールは、コンポーネントを集約して依存関係を整理することで、クラス間の適切な結合を表現する。実際の開発では、モジュール単位でビルドできたり切り替えがしやすくなるため、そっち方面でも活用することが多い。もちろん、設計意図の表現方法として活用されているケースもよく見かける。
ファクトリは複雑なインスタンス化を集約・表現するための手段だと思っている。カプセル化の一種。※実際にそう書かれていたわけではない。
リポジトリはインスタンスの永続化機能を提供し、かつそれに関する操作を集約したコンポーネント。
アプリケーションサービス
アプリケーションサービスは、ドメインやドメインサービスのクライアントとして動作するもの。ドメインロジックではなく、ユースケースを表現するための手段。
アーキテクチャに関する情報はたくさん見てきたが、エンタープライズ向けシステムのスケールに耐えられるサービスを表現しようとした場合はヘキサゴナルアーキテクチャを活用するのが一番バランスが良いのではと考えている。
一時期堅牢なアーキテクチャとして紹介されることが多かったCleanArchtechtureやOnionArchtechtureも結局はヘキサゴナルアーキテクチャと同様にレイヤを意識したもの(多分の話。CleanArchtechture自体ふわっとしか理解していない)なので、これをベースに組み立てて行くことでほとんどのケースで困ることはなくなりそう。モジュールのIFを定義してアダプタ経由で外部とメッセージを送受信できる、というのは一度仕組みを理解すれば応用が効きそうで、テストコードの実装パターンとも相性が良い。
経験が浅い頃はアーキテクチャの話がかっこいいと思っていたので、自分の主戦場であるモバイルアプリのアーキテクチャを色々考えては落ち着き、ということを繰り返してきた。一方でそういう話の中ではモデル層はModel
としてざっくりと紹介されることが多く、いつまで経っても理解が進んでいなかった。
そのモデル層というのがいわゆるpresentation層
以外の部分で、DDDの領域の話と相性も良かった。今回DDD本を読みながら過去の開発経験と照らし合わせて妄想してかなり整理できたので、オレオレ設計になりかけている担当プロダクトを徐々にオーソドックスな設計に寄せていこうと思っている