はじめに
こんにちは。はじめまして。tarokamikazeです。
これは、社内勉強会用に参考資料をまとめたものです。
この資料のゴール
- DDD専門用語について、どんなワードでググったらいいかわかるようになる
- DDDを知らない人が、戦術的DDD(軽量DDD)だけでもやってみようかなという気になる
前段; MVCの限界
余談ですが、凝集度・結合度の観点からするとRailsのMVCがどう問題があるかをコラムで紹介しています。MVCそれぞれの責務を図示すると、低凝集・高結合になっていることがわかります。
— 松岡@技術書典8Day2え28 / DDDブログ書いてます (@little_hand_s) February 2, 2020
とにかく、凝集度、凝集度なのです。 pic.twitter.com/fDWv1ERJA1
あえて過激に言うと。
ある程度の複雑度を持ったアプリケーションにおいて、MVCであるというだけで、 Fat Model
か Fat Controller
は避けられない。
モデルの中を整理できるような設計思想が必要なのだ!
というか、モデルっていうな!!
参考
- お前らがModelと呼ぶアレをなんと呼ぶべきか。近辺の用語(EntityとかVOとかDTOとか)について整理しつつ考える
- MVCのモデルの誤解を解くためにフレームワークを例に挙げようとしたら誤解してもしゃーないなって思った
DDD概観
DDDとは
Domain-driven design (ドメイン駆動設計)
顧客と開発者が業務を戦略的に理解し、共通の言葉を使いながらシステムを発展させる手法
ドメイン駆動設計のメリットと始め方 ~ 1章「DDDへの誘い」
ドメインの中にあるコアとなる複雑さ、クリティカルなパートにフォーカスする
ドメインとソフトウェアのエキスパートが協力しモデルを探索する
モデルをはっきりと表現するソフトウェアを書く
境界づけられたコンテキストの中でユビキタス言語を話す
いつ誰がいいだしたの?
Eric Evans というひとが2011年頃に書籍 「エリック・エヴァンスのドメイン駆動設計」を出版。これが原点とされる。
その後、2015年「実践ドメイン駆動設計(通称 実践本、iDDD本)」が出版。この記事はこちらに依拠してます。
ドメインってなによ?
知識、影響、または活動の領域
問題領域、業務領域とも訳されます。ソフトウェアが表現する対象。例えば、人事評価システムであれば、従業員や業績が知識であり、目標設定や評価が活動に当たります
ふわっとしすぎてよくわからんのですが
DDDの領域は大きく分けて3つに分けられます。
開発思想:
システムの複雑性に取り組むために、業務の専門家と技術の専門家で言語・モデルの認識を合わせ、継続的に進化させていこう、という考え方
戦略的設計:
ドメインモデリングの前提を揃えるための、モデリング対象を定義する原則と手法(コアドメイン/サブドメイン、境界付けられたコンテキスト、コンテキストマップ等)
戦術的設計
モデルを具体的に表現するためのパターン(エンティティ、レポジトリ、レイヤードアーキテクチャ等)
DDDやると、なにがうれしいの?
プロセスやツールよりも個人と対話を、
包括的なドキュメントよりも動くソフトウェアを、
契約交渉よりも顧客との協調を、
計画に従うことよりも変化への対応を、
と言われても、どんなふうに対話するの? どんなふうに変化に対応するの? という疑問は浮かぶでしょう。
DDDはその道標になります。
もうすこし具体的に言うと。
- MVCだとよくおこる「このロジックはどこに書けばいいんだっけ...」という迷いが出ないので、プログラム設計がサクサクできる
- プログラムが高凝集・疎結合になるので、メンテナンスコストが下がるし、バグがおこりづらい。特に致命的なビジネスロジック周りのバグを防ぎやすい
- ドメインエキスパート = 事業領域(ドメイン)に超詳しいひとと、開発者が話しながら実装を進められるので、上流工程がスムーズにいくし、認識齟齬がおきづらい(個人的には、アジャイル開発における上流工程のデファクトスタンダードだと思う)
戦術的DDD
プログラムレベルでは、こういうパターンで設計したらいいですよ、というベストプラクティス。
個人やプロダクト単位で「とりあえずDDDやってみるか!」となったら、戦術的DDDから導入するのが王道。
プログラマーにはとっつきやすい部分。しかし戦略までやらないと、開発の辛さは(減りはすれども)消えないのだ......
ちなみに、戦術的DDDだけを導入している状態/開発方針を「軽量DDD」と呼ぶ。基本的にはアンチパターンと言われているので、はやく戦略も手を出してみよう。
ようするにどういうことよ?
以下のベストプラクティス、デザインパターンの一種
- オブジェクト指向、クラス設計
- 単体アプリケーション設計、モジュールの依存関係
全部これで書き換えなきゃいけないの?
DDDは設計・実装コストが高いので、複雑でつらい更新系処理からやってみよう。以下のようなルールで柔軟に考えるべき。
- 原則、更新系のみに適用すべき。参照系に全然適用しない方がいい。CQRS(コマンドクエリ責任分離).
- 単純な更新系処理ならば、設計・実装コスパがあわないのでやらんでもいい。
- ビジネス的にコアな機能や、複雑な処理から手をつけ始めよう。
MVCでそれできるの?
MVCの考え方から脱却したほうが、すんなり理解できる。
iDDD本ではヘキサゴナルアーキテクチャを推していたが、正直ふわっとしすぎてイメージできなかった。
個人的には DDD + クリーンアーキテクチャ が最強。
下図でいう、Entitiesの部分がまるごとDDDの担当領域。
なおここ数年では、 Ruby On Rails でDDDを導入した例もちらほら。
代表的なパターン
以下は、名前だけでも覚えていってください!
- 集約(Aggregate)
- 値オブジェクト(Value Object)
- エンティティ(Entity)
- リポジトリ(Repository)
- ドメインサービス(Domain Service)
集約 / 値オブジェクト / エンティティ
実践DDD本 第10章「集約」~トランザクション整合性を保つ境界~
値オブジェクト: 開発言語依存のプリミティブな型(stringとか)をラップしたもの。値依存のビジネスロジックはここに書く。不変(イミュータブル)で、IDをもたない。密結合なら、値をいくつか持っていい。(価格オブジェクトなら、金額とか通貨単位など)
エンティティ: IDで判別される値のかたまり。ユーザーとか。不変ではない。
集約: エンティティや値オブジェクトをまとめた塊。トランザクション境界(たとえば、どれかのエンティティの更新がコケたら全部コケてほしい)の単位でセットにしていく。
リポジトリ
- 定義としては、集約を取得したり保存したりする入り口。
- 実装的には、DBとか外部APIを叩くやつ。
- ドメイン層(domain package)にinterfaceとして定義し、他の層から利用する場合はこのinterfaceに依存させる。実装はインフラ層に書く。
ドメインサービス
- 単一の集約 / 値オブジェクト / エンティティ に依存させられないビジネスロジックをここに書く。
- 例) ユーザーIDはユニークじゃなきゃいけないよ、というロジック
- これがいっぱいできるのは設計がイケてない証拠。苦肉の策として使おう。
エンティティやリポジトリって、ORMのあれ?
特にエンティティは、DTO的オブジェクト<-->DDD的エンティティへの値の詰替が推奨される。
詰替はだるいが、それが戦術的DDDなのだ。がまんしよう。
この値詰め替え実装コストが、戦術的DDDの実装コストの代表例といってもいいくらい。
DDDの開発思想
ユビキタス言語
ユビキタス言語とは、開発者とドメインエキスパートなどシステムの開発に関わる人達全体のコミュニケーションを円滑に、曖昧さをなくすために厳格に定義された共有言語
ドメインエキスパート = 事業領域(ドメイン)に超詳しいひとと、開発者の用語と、クラス名やメソッド名をそろえよう。そうすれば上流工程もすんなりいくし、改修もかんたん。
ドメインエキスパートと開発者が言語 = 認識を合わせていけば、齟齬も生まれにくいものだ。
ドメインエキスパートが社内にいない? ならば君がドメインエキスパートになるしかないのだ!!
ユーザーインタビューに行きまくるしかない。
余談; UI/UXの世界でも
デザイナーの世界でも、概念モデルベースで設計しようぜ!的なことをが語られていますね。
戦略的DDD
戦術の失敗は戦略で補うことが可能だが、戦略の失敗は戦術で補うことはできない
戦術的DDDに慣れてきたら、戦略的DDDにもトライしてみよう。
そもそものアプリの建付けからメスをいれるのだ!
ドメイン? コンテキスト???
実践DDD本 第2章「ドメイン」「サブドメイン」「境界づけられたコンテキスト」を読み解く
境界づけられたコンテキスト = マイクロサービスの境界
システムが大規模になると、関係者すべてで統一したモデルを作ることは難しくなる
大きなシステムを「境界づけられたコンテキスト」に分割し、それぞれの中でモデル、言語の統一を目指す
境界づけられたコンテキスト 概念編 - ドメイン駆動設計用語解説 [DDD]
マイクロサービスをやりたいんだったら、戦略的DDDもきちんとやりましょう。
どんな単位で切ればいいのさ?
エンジニアリング組織論への招待でも、two pizza rule で分けろと言われている。
いろいろ話をきいた結果、逆コンウェイの法則(組織にあわせてシステム設計する)のが正解っぽい。
つまり、1コンテキスト = 1マイクロサービス = 6~12名。
ユーザー部門で切ればいいの?
そういうわけではない。とにかくシステムが高凝縮になるように、いいかんじに切れればいい。
ECシステムだったら、以下みたいに切っている例もあるらしい。
- カート
- 決済
- 商品(一覧とか更新とか)
- 配送
まとめ
戦術的DDD(軽量DDD)から、雑にトライすればいいんじゃないかな。
勇気を持って学習棄却していこう。知的蛮勇を持っていこうぜ!!