以前、オブジェクト指向の基礎について話したよね? クラスとかオブジェクトとか、ちょっとはイメージできたかな。
クラスとオブジェクトの概念 – オブジェクト指向の入り口 – Hello Java World
今回はその考え方をもう一歩進めて、**ドメイン駆動設計(DDD: Domain-Driven Design)**っていう開発手法の考え方をざっくりと説明していくよ。
「ドメイン駆動」って聞くと、なんか難しそうって思うかもしれないけど、要は「ソフトウェアを作る時に、一番大事なのは現実世界の『ドメイン』(領域)をしっかり理解して、それをプログラムに落とし込むことだよ!」ってことなんだ。
ドメインって何?
ドメインってのは、簡単に言うと「そのシステムが扱う業務や領域のこと」だよ。
例えば、ECサイトを作るなら、ドメインは「商品」「注文」「顧客」「決済」とかになるし、 銀行システムなら「口座」「預金」「引き出し」「送金」とかがドメインになる。
つまり、システムが解決したい問題が起きている現実世界のことだと思ってくれればOK。
ドメイン駆動設計ってなんで必要なの?
じゃあ、なんでわざわざ「ドメイン駆動」なんて考え方が出てきたんだろう? 昔ながらの開発だと、データベースのテーブル設計を先に決めたり、画面の見た目から作り始めたりすることが多かったんだ。でもそれだと、こんな問題が起きやすかった。
- 業務知識がプログラムに反映されにくい: 開発者が業務をちゃんと理解してないままコードを書き始めると、業務とズレたシステムができちゃう。
- 変更に弱い: 業務のルールが変わると、いろんなところに影響が出て、修正が大変になる。
- コードが複雑になる: 業務ロジックがあちこちに散らばって、どこに何が書いてあるか分かりにくくなる。
ドメイン駆動設計は、これらの問題を解決するために、「まずドメインを徹底的に理解して、それを中心に設計を進めよう!」っていうアプローチなんだ。
ドメイン駆動の登場人物たち
ドメイン駆動設計には、いくつかの重要な概念があるんだ。全部をいきなり理解する必要はないけど、主要なものをいくつか紹介するね。
1. ユビキタス言語
ユビキタス言語ってのは、「開発者と業務の専門家(ドメインエキスパート)が共通で使う言葉」のこと。例えば、ECサイトで「商品をカートに入れる」という操作があるとして、開発者は「addItemToCart」、業務の人は「カートに入れる」と別々の言い方をしてたら、認識のズレが生まれるよね。
DDDでは、このズレをなくすために、お互いが完全に理解し合える言葉を作り上げて、それを会話でもコードでもドキュメントでも徹底的に使うんだ。この共通言語があることで、コミュニケーションがスムーズになり、認識のズレによる手戻りを減らすことができるんだよ。
2. エンティティ
前回の記事で、オブジェクト指向では「モノ」をクラスとして表現するって話をしたよね。エンティティもまさにそれ。ドメインの中で「識別子(ID)によって一意に識別される、状態を持つオブジェクト」のことだよ。
例を挙げると、
- ECサイトの商品:商品IDで区別できるよね。商品の名前や価格が変わっても、同じ商品と認識できる。
- 銀行の口座:口座番号で区別できる。残高が増えたり減ったりしても、同じ口座だよね。
エンティティは、その状態が変わってもIDが同じであれば同じものとみなされるのが特徴だよ。
3. 値オブジェクト(Value Object)
エンティティとよく比較されるのが、値オブジェクト。値オブジェクトは「属性の集合で、それ自体に識別子を持たず、その値によって等価性が判断されるオブジェクト」のこと。ちょっと難しいね。
簡単に言うと、「その値が変わったら、それはもう別のものとみなす」ってやつ。
例えば、
- 住所:「東京都新宿区」っていう住所があったとして、「東京都渋谷区」になったら、それはもう別の住所だよね。住所自体にIDはない。
- 金額:500円と1000円は全く別の金額だよね。金額もそれ自体にIDはない。
- 色:赤と青は違う色だよね。
値オブジェクトは、それ自体が変更されることはなく、変更される場合は新しい値オブジェクトが作られるイメージだよ。これを使うと、コードの安全性が高まったり、意図しない変更を防いだりできるメリットがあるんだ。
4. 集約(Aggregate)
ドメインの中には、複数のエンティティや値オブジェクトが組み合わさって、一つのまとまりとして扱われるものがあるんだ。それが「集約」。
集約は「一貫性を保つために、一緒に変更されるべきオブジェクトのまとまり」のこと。そして、その集約の代表となるオブジェクトを**集約ルート(Aggregate Root)**と呼ぶんだ。集約の中のオブジェクトは、必ず集約ルートを通して操作されるのがルールだよ。
例で見てみよう。
ECサイトの「注文」を考えてみる。 注文は、たくさんの「注文商品」(どの商品が、いくつ、いくらで)で構成されてるよね。 この場合、「注文」が集約ルート、「注文商品」は集約の中に含まれるエンティティになることが多い。
注文をキャンセルするなら、注文全体としてキャンセルするよね? 注文の中の個別の注文商品だけを勝手に削除したりはしない。つまり、注文が集約ルートとして、その下の注文商品を一貫性を持って管理しているってことなんだ。
こうすることで、複雑な業務ロジックも、この集約の単位で考えることができるから、見通しが良くなるんだよ。
5. ドメインサービス
エンティティや値オブジェクトだけでは表現しきれない、複数のオブジェクトにまたがるような業務ロジックがある場合に登場するのが「ドメインサービス」。
例えば、
- 銀行の「送金」処理:Aさんの口座からお金を減らして、Bさんの口座にお金を増やす。これは「口座」というエンティティだけでは完結しない、複数の口座を扱う業務だよね。
- ECサイトの「在庫引き当て」:注文が入ったときに、複数の商品の在庫を確認して、足りなければエラーにする。これも複数の商品にまたがる処理だよね。
このように、特定のエンティティや値オブジェクトの責任範囲を超えた、ドメイン固有の処理を行うのがドメインサービスの役割なんだ。
ドメイン駆動設計のメリット
ドメイン駆動設計で開発を進めることには、こんなメリットがあるんだ。
- 業務に強いシステムが作れる: 業務の知識がしっかりプログラムに反映されるから、本当に欲しかったシステムができあがる。
- 変更に強い: 業務の変化に合わせて、システムも柔軟に修正しやすくなる。
- コードが分かりやすい: 業務の言葉がそのままコードに出てくるから、他の人が見ても理解しやすい。
- 開発者と業務担当者のコミュニケーションが密になる: ユビキタス言語を使うことで、お互いの理解が深まる。
もちろん、最初から完璧にDDDを使いこなすのは難しい。でも、これらの考え方を知っておくだけで、日々のコーディングや設計に対する意識が変わるはずだよ。
まとめ
今回はドメイン駆動設計の基本的な考え方についてざっと説明したよ。
- ドメイン:システムが扱う業務や領域のこと。
- ユビキタス言語:開発者と業務担当者が共通で使う言葉。
- エンティティ:識別子で区別されるオブジェクト(商品、口座など)。
- 値オブジェクト:値で等価性が判断されるオブジェクト(住所、金額など)。
- 集約:一貫性を保つために、一緒に変更されるべきオブジェクトのまとまり。
- ドメインサービス:複数のオブジェクトにまたがる業務ロジックを扱う。
これらの概念は、現実世界の問題をどうプログラムに落とし込むか、そのヒントになるはずだ。
次回は、今回話したドメイン駆動の概念を、より具体的なコードにどう落とし込んでいくか、もう少し踏み込んで話していこうと思うよ! 楽しみにしててね。


コメント