ビジネス活動に起因する複雑さに立ち向かうドメイン駆動設計

増田亨氏(以下、増田):よろしくお願いします。私は2006年ぐらいからドメイン駆動設計に実際に取り組んで、15年ぐらいやっているんですけど、今日はそれを私なりにわかったことというか、けっこう最近振り切ってこうやってますよという内容を、みなさんの参考になればと思って少しお話しします。

ドメイン駆動設計というのはソフトウェアのいろいろな設計スタイルの1つなわけで、私自身は別にドメイン駆動設計だけが唯一の設計スタイルだとは思っていないし、私のキャリアの中で言えばもっといろんなことをやってきたので。ただ、そのドメイン駆動設計というのは、私にとっては非常に新しい境地というんですか、新しい見方・やり方を教えてくれる、とてもある意味愛着のある設計スタイルです。

基本的には、ソフトウェアの複雑さをどう扱うかということに考え方ややり方の焦点を絞っている。複雑さというのは、例えばテクニカルなハイ・パフォーマンスやハイ・アベイラビリティとか、そういうものもありますが、ドメイン駆動設計の観点・焦点の合わせ方というのは、あくまでもソフトウェアが複雑になるのは、ユーザのビジネス活動に起因するんだろうと。

このビジネス活動に起因する複雑さに立ち向かうためのキーワードとして、ドメインモデルを使ってモデル駆動で設計をして、ドメインモデルを使って、設計だけではなくてコミュニケーション、関係者の間の意思疎通も促進する。こういう考え方の設計スタイルなんだというのを理解しています。

まぁ、こんな感じですよね。キーワードをひらめくドメインモデルがあって、それが設計・実装を駆動するという面と、関係者の意思疎通・意図の伝達を促進するという。ここにそのドメインモデルで言うと、関係するので言えば、コアドメインとかもう少し大きな絵を描くコンテキストマップ、それから設計・実装でいうと、値オブジェクトとか集約とかエンティティとかリポジトリとか。

コミュニケーションや意思の疎通で言うと、ドメインエキスパートとか境界づけられたコンテキスト。それから、コミュニケーションと設計をつなぐものとして全体を共通の言語を両方で使おうと。コミュニケーションと設計にも使おうということでユビキタス言語みたいな……。

こういうことがエヴァンス本(エリック・エヴァンス『エリック・エヴァンスのドメイン駆動設計』)には書いてあるんですけれども、正直言って15年前の私がこれを見たときに、わけがわからないし、あまりおもしろいとも思わなかった。ただ、何かドメイン、ビジネスロジックあたりが複雑さの原因だというところはすごく共感はしたんです。

ただ、「じゃあどうするんだ」という方法論のことに関しては、当時はあまりピンときていませんでした。パターン名に振り回されていたりとか、本の内容をかみ砕くこと自体は、けっこう時間が掛かったなぁと……。

ビジネスルール、値オブジェクト、型の3つがキーワード

15年間いろいろやってきて、もちろん失敗もあったし今から思うと「あぁ、そんなことを考えてたな」と思うんですけど、ここ数年はだいぶ自分の中でもある意味、映像やイメージがクリアになってきました。今日は短いのでいきなり結論から言うと、要するにまず複雑さということを考えたときにビジネスルールなんだなと。

ビジネスルールに焦点を合わせて、それをソフトウェアで実現しようとすると、値オブジェクトがイミュータブルな値のロジックを持つオブジェクトが主役なのかなぁ。値オブジェクトと基本的には同じことを言っているんですけど、型ですね。型というものの考え方をきちんと理解して、型というものが持っている性質を活用することによって、ドメイン駆動設計がやりやすいというか、ソフトウェアを作りやすくなる。

品質の高いソフトウェアをわりと楽に作れるようになるなぁというあたりのことが、ここ数年の私の、この3点セット。ビジネスルールと値オブジェクトと型というキーワードが、私なりにだいぶこだわっているところです。

ドメインをビジネスルールという言葉・分野・方向に寄せるとはっきりする

ドメインが最も複雑な側面はビジネスルールである。というのは、エヴァンス本を読む限りでは、ドメインという言葉は、ユーザのビジネス活動の領域とか、アプリケーションが関係する領域とかアプリケーション開発に必要な知識の領域だったり広いんです。ドメインに焦点を合わせるといっても、ドメインという言葉の焦点が合っていない。

非常に広角な捉え方をしないと、どこからどう手を付けていくかということがわかりにくい。これは実際にいろいろなメンバー、一緒にやってくれた仲間たちと話しているときも「ドメインとは何ぞや?」というイメージが共通に持ててなくて、お互いに向かっている方向のベクトルがあまり合ってないな。温度感も違うなと。

その中でいろいろとやってきて、ソフトウェアの複雑さというのは、要するに活動の中のビジネスの決め事、ビジネスルール。とくに私はビジネスアプリケーションばかりやっていますから。

ビジネスルールは、ある程度、包含に定義すると、ビジネス活動を刺激して制約する決め事であるとか、起きている事実の表現・記録・通知の約束事であるとか、そういう事実を使った計算・判断のロジックだったりそういった定義はあることにはあるんですけど、要するにビジネス活動全体というのはそれでもまだ広すぎるので、ビジネス活動を制御するというか刺激したり制約するいろいろな決め事、約束事、ルール。

そういうことに焦点を合わせるということで、ドメインというよりは、よりビジネスルールという言葉、ビジネスの決め事ということに焦点を合わせることで、だいぶ焦点が合ってくるかなと。この図では広すぎてぼんやりしてわからないよねということに対してビジネスルールに焦点を合わせるとこういう感じなんですね。

ドメインモデルというのをもう少し絞り込んで「ビジネスの決め事の整理」に割り切っちゃって、そうすると意思疎通もビジネスの決め事の共通理解にしようよ。それから設計を駆動するという言葉ももう少し狭めてビジネスの決め事、ビジネスルールをどう具体的にソフトウェアで表現するかというかたちで、より具体的な対象が定まってきます。

ドメインエキスパートも広い意味でのエキスパートはいっぱいいると思うんですけど、ビジネスの決め事、ビジネスルールに詳しい人という捉え方をするとけっこう絞られてくると思うんですよね。

境界づけられたコンテキストも、ビジネスルールがある範囲では通用するけどある範囲では通用しない。あるいはある範囲では興味があるけど隣のコンテキストに行くとそのビジネスルールには興味ないです、関係ないですみたいなことが1つの会社の中でも起きたりする。

そんなようなかたちでドメインモデルとかコミュニケーションとか設計というものを、ビジネスルールという言葉に、分野に、方向に、もう少し具体的に絞り込んでアプローチするのがドメイン駆動設計の確信に触れた進め方なのかなと考えます。

ソースコードを中心に品質を上げていく

ここら辺の話をし出すと長くなるんですけど、結局納期とか開発単位のスコープとかがあって、それに対して要件定義、仕様化、実装みたいな活動があって、成果物があって、あるいは開発手順や開発体制みたいなプロセスがあって、技術面としてそのモジュール構造とか要素技術の選択とかそういう問題があります。

これはドメイン駆動設計だからということではないんですけど、私自身が拘っているある意味アジャイルというか、ドメイン駆動設計・アジャイル、・ブジェクト指向設計を合体させたような、今考えているソフトウェア設計のスタイルということで言うと、こういうことを考えているんです。

要件定義と仕様化の継ぎ目をなくさないとダメだろうと。役割分担をしたりとかフェーズを分けたりとかドキュメントで伝言ゲームというのはどう考えてもコストパフォーマンスが悪いよね。そういうことを考えると、成果物はドキュメントの品質をいくら上げてもだめで、おそらくソースコードを中心に、ソースコードの品質を上げることにもっとフォーカスしたほうがいいんじゃないのかなぁ。

あとでも話しますけど、技術面では、モジュール構造でやっぱり一番多いのは、今でも手続き的なモジュール構造だと思うんですね。そこをもうちょっと、とくにビジネスルールに焦点を合わせた場合には、アプリケーション固有のビジネスルールを表現するための型、int型とかstring型、あるいは配列型でビジネスルールを表現するのではなくて、金額とか数量とかあるいはメンバーのグループとか、そういう実際にビジネスのルールを表現するために出てくるようなそのものをちゃんと型として定義した戦略的なアプローチが効果があるんだなという手応えを最近感じています。

三層に加えて、ドメインロジック層を構成する

そしてアーキテクチャ的に言うと、トランザクションスクリプト的なもので言うと、この左側の3層、プレゼンテーション層があって、アプリケーションあるいはビジネスロジック層があって、データソース層がある。こんな感じだと思うんですけど、ここからビジネス運用に関わるような判断ロジックとか計算ロジックを全部引っこ抜いてきてドメインロジック層に独立させてそういうものを集める。

ここは当然ビジネスルールを表現するために独自に定義した型で、このドメインロジック層というのは成り立つというか作り上げていく。

ビジネスルールを整理するRDRA 2.0

形式的ではないんですけど、ビジネスルール駆動のこういうソフトウェア開発の、最近現場で方法論として言語化したり、手法として言語化したりやり始めている内容を、ちょっと紹介します。

まず1つ目はビジネスルールの発見と整理ということで、これはこのあと喋っていただける神崎さんがRDRA 2.0という方法論に非常に従事して取り組んでいます。内容の細かいところは、ぜひRDRA 2.0のハンドブックを参考にしてほしいです。kindle版が無償で手に入ります。

基本的には非常に関係性を重視します。ここに10ちょっとのダイアグラムがあるんですけど、これは独立したドキュメント図ではなくて、全部裏側では関係を取られています。

そこの関係をたどること、あるいは関係を合わそうとすることで、整合性とか網羅性ができてくる非常によくできた方法論です。ここにバリエーション条件図と書いてあるけど、ここがビジネスルールを発見したり整理するためのキーになる視点なんです。

ここのところを具体例で言うと、RDRA 2.0ハンドブックのサンプルで使っているやつにあるんですけど、バリエーションの区分とか種類ですね。こういう本の種類とか会員種別とか。それに対して今度は、貸出日という事実に対して、14日という貸出期限の計算ロジックみたいなものもありますとか……。貸出制限は、遅延日数が3日以内という事実に対して1人5冊までOKだよみたいな、こういう判定条件。

これが遅延日数というバリエーションと会員種別というバリエーションで定義できる、あるいは分析して整理できる。こういうようなアプローチなんです。

ビジネスルールをオブジェクトとして実装する

ここまでRDRAでビジネスルールを発見して整理ができたら、そこから先は、バリエーションは区分オブジェクト……。右側に私の本を紹介させていただいたんですけど、この本の背景で中に書いてあることは、実際にこういうことで、バリエーションとかを区分オブジェクトで表現する。 計算ロジックは単純なものであれば値オブジェクト、あるいは複合した計算であれば集約オブジェクト。判定表みたいなやつは、おそらくMapとかSetをうまく組み合わせたコレクションオブジェクトで表現するかたちになるんだろうなとか。

実際に私自身がやっていることは、こういうかたちでビジネスルールを表現するようなことで、計算とか判断とかに出てくるような〇〇額とか〇〇日、〇〇種類とか○○中とかね。○○ポリシーとか○○プランとかそういう言葉を拾いながら、こういうのを全部独自の型でビジネスルールを表現するために直接的に型として拾い上げて右側のオブジェクトのようにしていく。

独自の型でビジネスルールを明確にする

値オブジェクトは、いわゆるデータ抽出をして型を宣言していることに他ならないので、こういうふうに独自の型をたくさん作ることによってソースコード上にビジネスルールを非常に明確に表現できるんですね。

それから計算判断ロジックというのを、オブジェクトを1ヶ所にカプセル化できるという効果も非常に大きい。これは変更容易性とか何かあったときに非常にやりやすくなるんです。

型の参照関係から変更の影響範囲を正確に把握できるということと、よりよいモデル、型がしっかりしていればしっかりしているほど、正直言って、強い型付けで型チェックがツールで事前にできる言語であればあるほど、そういう環境であるほど、やっぱりリファクタリングが非常にやりやすいなという感じとしてはあります。

RDRA 2.0のハンドブックに載っている図書館のサンプルはあくまでも要件定義モデルなんですけど、あれをインプットし手掛かりにして、実際にアプリケーションとして実装したサンプルが、ここに上げているGitHubのsystem-sekkeiというGitHubアカウントの。libraryという図書館です。libraryというリポジトリに公開していますのでぜひ参考にしてください。

実際は、こんな感じになる

最後に、これ実際にどんな感じになるかというのを少し感じだけ紹介させてください。これが先ほどの図書館モデルみたいなものを、実際に本だとか、それから貸し出し中の本だとか、そういうふうにパッケージでクラスを分けて独自の型を作っているんですね。

こちらの図は何かというと、ちょっとわかりにくいかもしれないんですけど、一番右側にバリエーションをそのままオブジェクトにした区分オブジェクトがあって、そういうバリエーションの条件分岐が、どのクラスから参照されていて、例えば会員クラスから参照されていて、その会員種別を持っている会員クラスというのは、例えば会員の貸出の図書を一覧するとか、そういうサービスから呼んでいるよと。

こういう感じで、そのビジネスルールから実際にそれを使うサービスクラスまで全部つなげられる。これはコードを書いてリバースしているんですね。型がしっかりしているから、型情報を基にして関係性を出すと、こういうかたちでドキュメントができてしまうんです。これだけじゃなくて、例えばこれは画面とユースケースと、それから実際にどんな型をユースケースで使っているか、サービスクラスで使っているか。

ユースケース構造を、そのままそのままソースコードで表現したやつをツールで可視化してみたらこんな感じになりますよという、こういうかたちでRDRAのモデルとソースコードで自分たちで表現した実装を付け合わせに行くとか。あるいはこういうかたちでビジネスを表現している概念などがパッケージ構造として、どういうかたちでソースコードとして実現できているのかというような参照関係とか。

こんな感じでビジネスルールのオブジェクトを型で表現することによって、ソフトウェアの中心にある複雑さであるビジネスルールをソフトウェアとして直接的に表現させる。こうしてソースコードの品質を上げていくことで、ビジネスのニーズにあった変更が、楽で安全なソフトウェアを作ることができるという、最近非常にまた手応えを感じて、チャレンジを続けているところです。