「ドメイン駆動設計を始めよう」読書メモ

もっと上手くコードを書けるようになりたいから、ドメイン駆動設計に興味が出る
サブドメイン(業務領域)とは、ビジネスドメイン以外の、業務に必要な知識?
たとえば、スタバはコーヒーの淹れ方の特殊性(事業領域)だけで成功したわけではなく、立地やインテリアなどの部分も卓越しているから成功している。
(この、業務領域の最適化が、市場でビジネスを確立させるために必要だというのはわかるけれども、うちのサービスであんまりイメージできないのは何故だろう)
(中核の業務領域が、アルゴリズムじゃないこともあるみたい。それはそうか。宝飾品の販売はもちろんドメインは宝飾品の品質だし、加工技術だよね。toBのサービスはどうしても営業力が効いてくるからここら辺がまた変わるのか。。。)
(聞きたいな toB領域だとまた変わるのか?)
中核の業務領域(コアサブドメイン)、事業を成長させるためのコアな部分
一般の業務領域、どの会社にも必要な業務領域。簡単とは限らない。例えば認証認可など。
ここは別サービスに頼るのがいいよね
宝飾品の例で言えば、コアドメインである宝飾品の加工技術以外の部分、例えばECなどは、代替が効く。つまり開発をしなくてもSaaSを用いれば良いことになる。8ページ

中核の業務領域が、ソフトウェアと結びついていた場合は、そのソフトウェアの複雑さで考えられる。
単なるCRUDで済むのであれば、それはビジネスの中核ではない。
ビジネスの中核がソフトウェアで表現されてる場合は、他の会社にマネされないように複雑になることになる。
(ソフトウェアSaaSなら、必ずしもコアの業務領域がソフトウェアとも限らないよな。。と思った。)
一般(認証など)複雑だけど、競争優位を産まない。外部ベンダーに任せるべき
補完(検索できるようにするなど)ロジックが単純。しかし一般的ではないので開発が必要→あまり力入れずに作るべき。発展させても業務にプラスにならない
中核(ビジネスの根幹を担うアルゴリズム。広告のマッチングアルゴリズムなど)変わりやすいし、作るのが大変。ここがビジネスの屋台骨になる。
コアな部分を業務委託だったり外注で作るのはなかなかリスキー。ここは一番経験のある開発者に作ってもらうべき
補完の部分は、業務委託のメンバーに作ってもらっても問題ない。できるだけ低コストに作るべき。。なんなら若手開発者の練習場所になる。
とは言え業務領域を判断するのも難しい。例えばヘルプデスクなどの顧客領域は一般的には一般サービスっぽいけど、事業の背景によって、担当者を動的に配置する仕組みが必要であれば、それは中核になる。
業務領域を探すときは、まず、ソフトウェア化されない業務領域を探すことがコツ。
具体例について
ライブチケット社
チケットの販売と流通。顧客のストリーミング情報や、プロフィールを利用して近くで開催されるライブをレコメンドする。
事業領域→チケットの販売
中核の業務領域→顧客に近くのライブをレコメンドする部分。
競争優位性なので、モバイルアプリの使い勝手なども中核の業務領域になる。
(なるほど
補完的な業務領域→チケットを検索できる。アカウントを持てる。行ったライブを記録できる。
よって、設計方針は、認証や会計はSaaSを使う。推薦エンジンなどは自作。ソーシャルネットワークとの連携などは外部委託する。
バスオンデマンド社
路線バスをタクシー感覚で使えるサービスを目指している。
第1章終

ここまでの感想。
ドメイン駆動設計
バリューオブジェクト云々など、そういう手法について述べられがちだけど、DDDの本質は全くそのような設計パターンの話ではないことに気づかせてくれる。
この章で、コアな領域、一般的な領域、補助的な領域について出てきて、目から鱗だった。ソフトウェア作りにおいて、力を入れるべき部分をちゃんと見定めようね、という話が言語化されてまとめられている。

2章始まり
ソフトウェア開発者のやるべきことは、事業活動について少なくとも基本レベルの知識を把握すること。業務エキスパートの考え方を理解して同じ言葉を使うこと。
ソフトウェア開発は学びの副産物。ソフトウェア開発の成功は業務エキスパートと開発者が知識を効果的に共有できるどうかで決まる。
ソフトウェア作りとは伝言ゲームである。事業エキスパートの考えをコードに落とし込むまでにたくさんの人を経由する。その中で誤って伝わり、誰にも嬉しくないサービスになってしまう。
それを防ぐための方法として「同じ言葉」を使うというものがある。
事業エキスパートが使ってる言葉を使って議論をする。「レコードを追加する」など、技術的な単語を理解することを事業エキスパートに強要してはならない。
そして、曖昧な言葉を使うのをやめよう。ポリシーではなく、統制ルールや、保険契約などに変換しよう。
同じ言葉で理解したら、それをモデルに起こそう。
モデルとは、現実のものなどを簡略化して表現したもの。地図などはモデルだね。同じ地図でも文脈や要求によって異なる形が存在する。路線図や標高図などは、それぞれ解決する課題をサポートするように作られている。
モデルを作るにあたって、ドメインエキスパートと認識を改めるのがとても大切。
そのためには同じ言葉を使い続けるのが大切。
曖昧な言葉や同義語を使わずにいると、業務エキスパートと開発者の認識の差を埋めることができる。
二章終わり

三章
一つの言葉が部門ごとに異なる意味として使われる。これはコード上で修飾語をつけて対応するべきかというと、それほ複雑さを生み出すのであまり好ましくない。
同じ場所を表す地図が目的別に複数存在するように、モデルも存在するはずだよね、
だから正しい文脈を与えて、同じ言葉を定義するのがいい。
これはの文脈の分け方は、業務領域の分け方(中核、一般、補完)と同じになる?→そうとは限らない。モデルの分け方は業務領域とは異なり、開発者の都合で変化させていいもの。どのように事業領域を小さく扱いやすく分けるかを考えて分けるべき。
区切られた文脈は別のサービスとして実装されることになる。
チームの境界もそこに合わせるべき。一つの文脈を複数のチームで担当するのはよした方がいい。
Q. 区切られた文脈とは、実世界の何に対応するのか。
例えばトマトは植物学の分類では果実に分類される。しかし料理の文脈でトマトが果実であることは役に立たず、野菜としてのカテゴリの方が役に立つ。
重力についても、ニュートンとアインシュタインでは異なる文脈で論ずることになる。
例えば他にも、引越しの時に冷蔵庫を搬入できるかどうかを考えるのに、ホンモノの3Dモデルは必要なく、高さを持たない同じ寸法の段ボールさえあれば判定できる。これは明らかにモデルであり、このダンボールは搬入路の確保という文脈で特有の実装がされるべきモデルになる。

四章 区切られた文脈同士の連携
区切られた文脈によってモデルの文脈を分割することができる。が、システムを作るにあたっては、それぞれの文脈に登場するモデルを連携させなければならない。
そして、その接合部分を契約とよぶ
(モデル同士を結合する必要がある→わかる。 本来は同じものを指しているものを連携させる頃が必要→どういう具体例だろう?)
違う言葉を使っているので、「契約」という概念で約束する必要がある→なるほど。
この契約は、チームの形状に依存することになる。
(チームトポロジーでも同じような話してたな。出所がそっちかな?)
コンテキストマップの管理は大切。最新の状態にしておくことがいい。しかし簡単な作業ではないので注意。
4章終わり

5章
トランザクションスクリプト
一つのリクエストを一つのトランザクション境界とし、手続き的にDBとやりとりするコードを書く。
簡単そうに見えるが注意するべきところもある。
分散トランザクション(一度の処理で複数のデータベースに対してトランザクションを表現したいこと)などになるととても難しいことになる。
一見分散トランザクション日見えない処理でも分散トランザクションになる時がある。訪問者カウントの処理である。(この例のトランザクションがうまく働かなくなりそうというのはわかるけど、なぜこれが分散トランザクションと呼ばれてるのかはわからない)
(分散トランザクションとは、複数テーブルの生合成云々というより、DBの結果を他コンポーネントにメッセージングで伝えるというものだとすると、今回の例もDBに記録してその成功失敗をクライアントに伝えるという点では分散トランザクションになる。だからクライアントに伝える部分のみ失敗した時のロールバックは難しいよね。確かに)
トランザクシャンスクリプトが向いている領域は、業務ロジックが手続き的なデータ操作だけの場合のみ。データソースから情報を抽出し、変換し、書き込むというフローのみ。これは、主に、保管的な業務領域に向いている。中核の業務領域のような複雑なロジックに対してトランザクションスクリプトを用いると、コードの重複がたくさん出てコードの一貫性が保てなくなり、バグの温床になる。しかし、一番使われているのは、このトランザクションスクリプト。
アクティブレコード
ORMのオブジェクトを生成して、それをトランザクションスクリプト内で取り回すような方法
user = new User()
user.Name = "hogehoge"
user.Email = "huga@piyo.com"
user.Save()
みたいな書き方
メモリ上のオブジェクトと、DBのテーブル構造のマッピングをカプセル化する。業務ロジックを込めることはできる。しかし、これも根本的にはトランザクションスクリプトなので、簡単なCRUDに対して使うのは効果的だが、中核の業務領域に対して使うのはトランザクションスクリプトと同様に難しい。
アクティブレコードを使う方法がアンチパターンとして紹介されることもあるだろうが、適材適所。逆に凝るべきで無いところにドメインモデルを導入することも、同様にアンチパターンである。

第六章 複雑な業務ロジックに立ち向かう
ドメインモデルの初出はファウラーの「エンタープライズアーキテクチャパターン」
その中で、エリックエバンスがドメインモデルについての本を執筆中とある。
エリックエヴァンスのドメイン駆動設計の書籍の中で、値オブジェクトや集約について触れられているが、これはドメインモデリングの部品でしかない。
ドメインモデルは複雑な業務ロジックを扱うための設計手法。
データとその振る舞いを一体化させたパターン
複雑なルールが絡みあうう状況において、アクティブレコードで実装してしまうと、複雑さが増してしまう。業務ルールの実装に間違いが生じてしまう。
業務ルールは複雑なので、DB操作などの技術的なものを極力取り除く
値オブジェクト
オブジェクトのフィールドによって特徴づけられるオブジェクト。値を表現するルールなども一緒にカプセル化することで、ロジックの重複も避けられる。オブジェクトの意図が理解しやすくなる。
値オブジェクトはフィールドの値によって特徴付けられるので、イミュータブルが安全。
エンティティ
IDなどによって特徴づけられるオブジェクト。
集約
エンティティは可変な状態を持つ。状態の不整合が起きないことに、注意をしていないと、エラーになってしまう。そのため、集約が外部とのインターフェースになって、状態変更用のメソッドを公開し、そのメソッドごしにのみ、状態の変更を許可するようにすることが大切。
状態を変更するメソッドをコマンドという。コマンドには二種類あり、コマンドオブジェクトを受け取る方式と、引数で状態の値を受け取る方式。後者の方がメソッドのシグネチャを変更しなくていいのでメリットがある。
業務ルールを集約より下に集めていくことにより、集約より上のレイヤー(アプリケーション層など)の責務をかなり単純なものにできる。
テクい話
A→加工→A'
という処理の、A'が保存される前に
A→加工→A''
という処理が走ることがありうる。
この並行処理を正しく扱わないと、本来はありえない状態変化が発生することがある。
振る舞いだけ見ると
A→加工→A'→加工→A''
に見える。
バージョン番号などを持たせて、ちゃんと保存前にバージョンが一つだけ上がっていることを確認するなどのことが必要だよね。というはなし。(確かに、チケットの文脈で言えば、アクティブ→キャンセル→アクティブという状態変化ができないルールで、バージョンを扱わないと、その状態変化を許しちゃうよね。というのはある。けど、ドメインの話の中にどう保存するかの情報を持ってないといけないのはちょっと悪いことをしている感じがする。)
集約は、変更単位なので、トランザクションの境界になる。
複数のオブジェクトを変更単位として扱う必要があるときに、オブジェクトをまとめて管理するのが集約。集約はできるだけ小さい方がいい。可能ならオブジェクトそのものではなく、整合性が必要な識別子だけを保持するような方法がいい。
業務(ドメイン)イベントのパターン
集約が持つ公開インターフェースの一部。集約が業務イベントを発行して、別プロセスや外部サービスなどで業務イベントの実行を行う。
業務(ドメイン)サービスのパターン
複数集約についての業務ロジックなどが発生したときに使用するパターン。状態を持たないロジック置き場として使う。しかし、集約がトランザクションの境界であることはちゃんと忘れないように!
システムの複雑さは、対象とするシステムの自由度と関係がある。

7章 時間軸でモデルを作る
イベント履歴式ドメインモデリング
イベントソーシングは、分析や、検索においても優位性がある。
中核の業務領域の深い理解をするための情報収集にも使える。
しかし、データ構造を変化させたい、みたいなケースはかなり大変。過去のイベントにおいてもデータ形式を変更させるかどうかを考えなくてはならない。

第8章 技術方式
ちゃんと関心事ごとにカードを分割させようね。
今までドメインモデルを作る話だったけど、今度は既存のフレームワークなど、外部の部分とどのようにくっつけようって話
(インメモリか、外部DBかを抽象化できるのかな。できるか。)
レイヤードを考える。
データアクセスは、DBだけじゃなく、メッセージ通信基盤や、NoSQLを用いるかどうかなどの選択肢を抽象化する
サービス層を導入して、業務ロジック層の扱いを行う層を作る。(業務ロジック層にはアクティブレコードやドメインモデル)
業務ロジック層のファサードになる。
(きれいだね)
トランザクションスクリプトで業務ロジックが実装されている場合は、サービス層は機能しない。(というか、アクティブレコードをゴニョゴニョするそれ自体がサービス層のような役割を担ってるよね)
レイヤードは、トランザクションスクリプトや、アクティブレコードのときにつかうのがいいね
レイヤードアーキテクチャと3層アーキテクチャ、よくごっちゃにされることある。3層アーキテクチャなどは、それぞれの層がリリースを共にしない。つまり物理的に分かれている。こういうのを、Tierと呼び分けている。
パートアダプタ
DIを用いて、ドメインモデルに、アプリケーション、インフラ層を依存させた方式。
(個人的には、最近はプラガブルにすることより、結合してないことの方を意識する方が重要なんじゃないかなと思ってる。結果的にプラガブルになるかもしれないけど)
CQRS
(単に読み込み系と登録系を分けるみたいなものだと思ってたけど、、、ちがう?)
コマンド→そのモデルのルールを完全に表現したモデル。登録時に概念と一対一に割り当てられる。楽観的な排他制御を必要とする。
クエリ→コマンドによって作られたデータから、さまざまな切り口で投影された読み取り専用のデータモデルを作成して、ユースケースごとに使い分けられるようにするイメージ?
マテリアライズドビューに似てる。
(投影とはいうけど、読み取りのクエリによって、読み取り専用オブジェクトが作られるみたいな感じじゃないのかな?DTO的な感じをイメージしてた)
↑というより、DBが更新されたら同期されて作成される別の文脈のデータベースみたいな感じ。
その方法として、コミットされたことをトリガーとして読み取りモデルを作る同期型と、ポーリングする非同期型がある。
(面倒見るデータソース多すぎないか?管理難しそう)
(普通のドメインモデル型で採用するというより、イベントストーミングのときに、読み込み系を抽象化するために使うみたいなイメージかな)
これらは全体のアーキテクチャとして採用するべきという話ではなく、文脈内、さらにはその中のどの業務領域かを考えて適応するべき。
レイヤーを水平に分割するのではなく、業務領域ごとに垂直に分割して管理するのが良い。
例 販売促進の文脈の中の、最適化領域(中核の業務領域)にはポート&アダプタを採用。みたいな感じ。
(行けるかな、、?文脈のさらにはその中の業務領域ごとにディレクトリ区切って運用するイメージなんだろうな。なんとなくそれならイメージつくかも。でもちゃんと考えないと、DBで結合しちゃいそうだなぁ、、)

9章 通信
コンポーネント同士の連携方法についての話
(僕のここまでのイメージ。マイクロサービス化するか、モジュラモノリスにするかみたいなイメージかな。REST APIでやるなら、router, controllerより下を垂直分割するとかもありなのかな、、、?)
(ちょっとモデル変換らへんの言葉がちゃんと理解できてないかもしれない。)
(区切られた文脈内で、概念がモデリングされた状況、しかし、そのモデルを他の概念から使用したいよねということになるときに、どうする?って話だと思ってる。
その他の概念ってのは、同じ中核の概念からのみの話なのか、一般的な業務領域の部分の話なのか。中核の業務領域から使用したいユースケースは存在するはず。
そして、その連携方法は、それぞれの業務領域によって変わるみたいな話だ。)
良きパートナー、モデル共有、利用者と供給者の三つの関係がある。利用者と供給者の関係には技術的に複数の方法が考えられる。
上流(モデルの提供側)と下流(モデルの使用側)に分かれることになる。
上流の提供しているものが、下流に使いにくい場合
- モデル変換装置を使う
- 上流が共用サービスを提供する→下流が公開された言葉を利用する
どちらも同じような変換ロジックになるが、変換に状態が必要な場合と、状態が必要ない場合がある
(変換に状態が必要ない場合は何となく理解できる。下流が不必要な情報を削除したり、下流の文脈に合わせて演算を行ったりして下流に情報を届けるイメージかな。状態が必要な物って何だろう。)
状態なしの場合は、上流から下流に渡る間に変換器を間に挟むことによって実現できる。
技術的にはAPI Gatewayを用いて、複数文脈とのやりとりの腐敗防止層として位置付けて変換などを行うことができる。
(これは、上位の文脈は全てRESTやgRPCなどでサービス提供されている前提なんだな)
(マイクロサービスは前程になる?)
APIGatewayを用いて変換を行い、新しい言語を作る。
(購入処理文脈 + 請求処理文脈 = 購入文脈 にして、下位からは抽象化するみたいなことかな)
(とはいえ、トランザクションを跨がざるを得ない状態だった場合にどうするのかはちょっと気になる。そういう例外出てきそう)
同期的にリクエストを捌くケースもあるが、非同期に複数のサービスから発せられたイベントを下位に伝えなくてはならないこともある。(購入されたことをトリガーとしたいけど、下位のエンドポイントを呼び出したくないみたいな?)
受け取った複数のサービスからの情報をまとめるには、その関連付けのための情報が必要なので、DBなどが必要になる。
技術的にはAWS kinesisやバッチ式であれば、AWS Glueを用いればそれを解決できる。
複数の集約に跨ったトランザクションを実装しなくてはならないケースは発生しうる。それはサーガと呼ばれる仕組みを用いて管理することで、複数集約間のトランザクションを担保することができる。(ここら辺はちゃんと理解できていないので、必要になった時にちゃんと読もう)

10章
区切られた文脈の適切な大きさとは?
→大きさが先に来るものではない。大きすぎる、小さすぎるは全く参考にならない。
おさらい 区切られた文脈→同じ単語が別のものを指すような場合にその文脈は区切られているとみなせる。
できるだけ小さい方がいいのは間違い無いが、業務理解が浅い場合は広めにとって後から区切るのが良い。
どのような業務ルールを複雑と判断するか?
入り組んだ業務ルール、不変条件、最適化アルゴリズムが含まれる。
同じ言葉、業務に関する言葉が、CRUD操作に関する話が多いのであれば、そんなに複雑ではないと判断できる。単純な業務ロジックは、入力データの検証がほとんど。
テストの話
テストピラミッドは、ドメインモデルを使用しているときに使うと効果的
アクティブレコードの場合は、複数のロジックを組み合わせて機能を実現するのでダイヤモンド型を、そしてトランザクションスクリプトの場合はテスト逆ピラミッドにして、E2Eを増やすと良い。
(ここら辺すごく納得がいく。トランザクションスクリプトな感じでテストをかいてても、絶対ピラミッド型にならないよなと思ってた。テストはピラミッド型に!というのは、CAとかの時には、という枕詞付きな概念なんだなぁ、、)
(トランザクションスクリプトとアクティブレコード、アーキテクチャ的にどう違うのかがあやふやかも。もう一回調べる)

11章 事業の状況によって設計を進化させなければならない。その方法
ドメイン駆動設計の基本と変化
ドメイン駆動設計をやるには
- 事業が絶え間なく変化するため、その変化に対応できるシステム設計が必要。
業務領域の変化
-
中核・補完・一般といった業務領域は、事業進行に伴い相互に変化することがある。
- 例えば、中核的な業務領域だったものが、競合他社がSaaSとして提供を始めると一般的な業務領域に変化することがある。
- 中核の業務領域に固執し続けるのはコスト的に問題があり、適宜判断が必要。
一般から中核に変化する例
- パッケージソフトを一般業務領域で利用していたが、特有の事情で自社開発が必要となり中核化する例。
-
Amazonの事例
- 一般業務領域のIT基盤を自作し、提供可能なサービスに成長させた。
補完から一般に変化する例
- 自社開発システムがSaaSの登場で一般化する場合。
俯瞰的な業務領域の変化
- クラット処理だったものが、事業の利益に直結する形で中核化する場合がある。
業務ロジックの対応
- 必要に応じて設計変更を行い、業務領域の変化に適応する。
実装と設計変更
設計変更の必要性
- 過去の判断による複雑さを特定し取り除く。
- 本質的な複雑さには、ドメイン駆動設計の手法を活用して対処。
アクティブレコードからドメインモデルへの移行
- 値オブジェクトとして切り出せるデータ構造を特定し、関連業務ロジックを統合。
- トランザクションの境界を分析し、セッターをプライベート化して業務ロジックを明確化。
- トランザクションの境界をもとに集約とルートオブジェクトを特定。
大規模開発での考慮
開発規模の拡大と設計
- チーム分割時に利用者と供給者の関係を明確化する。
- モデル間の依存性を適切に設計。
業務知識の理解と変化
- 最初は広い文脈を持ち、時間経過と共に分割。
- 複雑化により業務ロジックが不明確になる場合、適切な判断で設計変更を行う。
ソフトウェアの成長とリスク
- 成長による複雑化を防ぐため、設計の再検討を定期的に実施。

12章 イベントストーミングについて
イベントストーミングの概要
イベントストーミングとは
- 業務の振興過程で発生する一連の業務イベントを時系列に並べ、業務プロセスを探求するワークショップ形式の手法。
- エンジニアだけでなく、業務エキスパート、プロダクトマネージャー、テスター、UXデザイナー、サポート担当者など、関係者であれば誰でも参加可能。
- 注意点: 参加者が10人以上になると効果が薄れやすい。
ステップごとの進め方
ステップ1: 業務イベントの探索
- 発散的に業務イベントを洗い出す。
- 例:
- 申請が承認された
- 出荷が完了した
- 申請が拒否された
- 例:
- ポイント: 正常系のシナリオから始める。
ステップ2: 時系列に並べる
- 洗い出したイベントを時系列順に整理。
- エラー発生時や異なるシナリオも追記。
- 不足している業務ルールや曖昧な点を明確化。
ステップ3: 注意点を見つける
- プロセス全体で注意が必要な点を特定。
- 例:
- 自動化できない作業
- 抜けている業務ルール
- 例:
ステップ4: 転換イベントを特定
- 文脈やフェーズの変化を示す重要な業務イベントを探す。
- 例:
- ショッピングカートが初期化された
- 注文処理が開始された
- 例:
ステップ5: コマンドを見つける
- イベントを引き起こすトリガーとなるコマンドを特定。
- 例:
- キャンペーンを公開する
- 注文を送信する
- 例:
- 必要に応じて、アクター(ユーザーや管理者)の情報を追加。
ステップ6: ポリシーを定義
- イベントとコマンドの間に存在するルール(自動化ポリシー)を特定。
- 条件付きの動作をポリシーとして記載。
ステップ7: 読み取りモデルを見つける
- アクターが判断に必要な情報を表現するモデルを特定。
- 例: ショッピングカート(購入候補リスト)
ステップ8: 外部システムを追加
- 業務領域の外側にあるシステムを特定し、関係性を明示。
- 例: CRM、通知システム
ステップ9: 集約の整理
- 関連する概念を集約としてグループ化。
- 集約単位でイベントやコマンドを生成。
ステップ10: 文脈の分割
- 機能的に密接に関係する領域を切り分け、独立した文脈を定義。
イベントストーミングの成果
-
利用目的:
- 業務プロセスのモデル化
- 新しい業務要件の探求
- 既存業務プロセスの改善
- チームメンバーへの知識共有
-
適さない場合:
- 流れ作業のように興味深い業務ロジックがない領域
ファシリテーションのコツ
- 強調型のアプローチ: 全員で業務プロセスをモデル化し、知識共有を進める。
- 合意形成: チーム全体で共通理解を得ることが重要。
- 段階的に進める: 最初はシンプルなステップ(ステップ4まで)に絞る。
これがイベントソーシング形式の設計のもとになる
感想
- イベントストーミングは業務知識を手に入れる手法として非常に有効。
- 業務プロセスが単純な場合には効果が薄いため、適切なケースで使用することが重要。
- イベントソーシング型に作る場合は有効だと思うけど、一般的なドメインモデリングの場合はどうだろう。

第13章 現実世界のドメイン駆動設計
ドメイン駆動設計(DDD)の導入と効果
-
理想的な状況:
- 新規開発案件で、DDDに熟達したメンバーが揃っている場合。
-
実際に効果が大きい状況:
- 既に稼働しているシステムに適用し、技術的負債や設計の混乱を解消する場合。
-
誤解:
- DDDを全て適用しないと価値がないと考えるのは間違い。
- 部分的な適用でも十分に価値を生み出せる。
DDD導入のステップ
1. 事業活動の理解
-
質問例:
- 事業活動の基本目標は?
- 顧客や提供する価値、競合他社は?
-
手掛かり:
- 組織図を参照し、部門間の協力関係を分析。
2. 業務領域の特定
-
中核の業務領域:
- 差別化ポイントや競争優位性がある領域。
- 例: 特許、独自アルゴリズム、優れたデザイン能力。
-
一般的な業務領域:
- パッケージ製品やオープンソースで代替可能な領域。
-
相関的な業務領域:
- 独自性はないが、外部サービスに置き換えられない領域。
3. 既存システムの構造を分析
-
注目点:
- サブシステムのライフサイクル。
- 業務ロジックの実装方法と課題。
-
アプローチ:
- コンポーネント間の関係を図示(コンテキストマップ)。
4. 設計改善の基本方針
- 全システムの全面的な書き直しはリスクが高い。
- 小さく始め、重点的に改善する箇所を戦略的に判断。
- 境界づけられた文脈(Bounded Context)を適切に定義。
実践的なアプローチ
ストラングラー方式
-
概要:
- 新システムを追加し、既存システムの機能を段階的に移行。
-
注意点:
- データベース共有は最小限に。
- 区切られた文脈ごとのデータベース設計を推奨。
リファクタリング
-
適用方法:
- 小規模な変更を積み重ね、業務ロジックや設計を改善。
-
目的:
- 技術的負債の削減と業務知識の復元。
モデリングと実装
-
重要性:
- 業務知識に基づいた設計が必要。
- 関係者との対話を通じて、共通言語を構築。
-
イベントソーシング:
- 時間軸を活用したモデルは、特定の領域で有効。
まとめと感想
-
DDD適用の鍵:
- 全体を一度に変えようとせず、少しずつ改善を進める。
- 事業価値に基づいた設計判断を優先。
-
チーム内での議論:
- 原則や背景を共有し、全員で共通の理解を持つ。
-
課題への対応:
- 技術的負債や業務知識の欠如に注意を払い、段階的に解決。
DDDは全てを一気に変えるものではなく、部分的な適用でも価値を発揮します。チームで共通言語を育てながら進めることで、設計改善の成功に繋がるでしょう。