ドメイン駆動設計を理解する3つのキーワード

ドメイン駆動設計との出会い

10年前に、エヴァンスのドメイン駆動設計を初めて読んだ時は、書いてある内容がほとんど理解できなかった。 あまり、面白いとも思わなかった。

当時は、現場でバグだらけのコードと格闘していた。障害が報告されるたびに、リファクタリング本を参考に、該当個所の長いメソッドや大きなクラスを片端からリファクタリング。その結果、コードがわかりやすくなり、やっかいなバグが単純な修正で解消できてしまうことの効果に驚き、設計の重要性を再認識していた。

それ以前は、UNIXC言語OraclePL/SQLという、オブジェクト指向ではない世界で技術を身に着けてきた。 どちらかというとオブジェクト指向には、ネガティブな印象を持っていた。現場では役に立たんだろうと。

バグとの格闘の中で、リファクタリング(設計改善)の威力を肌で感じ、その考え方とやり方がオブジェクト指向に由来するということを知るにつけ、オブジェクト指向も食わず嫌いではなくもう少し学んでみようと思った。

ワーフスブラックの「オブジェクトデザイン」とバートランドメイヤーの「オブジェクト指向入門」を買い込んで読み始めてみた。 両方とも面白いと思うところもあったが、何を書いてあるのか、よくわからないところも多かった。

実践的なオブジェクト指向との出会い

大きな転換点は、ケントベックの「実装パターン」を読んでからだった。

オブジェクト指向とは何か、という説明ではなく、「変更の影響の局所化」「コードの重複の除去」「ロジックとデータの一体化」「宣言型の表現」などの設計原則を、なぜそうするのか、具体的にどうやるのかが、わかりやすいサンプルコードで説明されていた。

特に「実装パターン」の中の「Value Object」は、大きな転機になった。 この転機については、こちらの記事でも書いた。 masuda220.jugem.jp

「実装パターン」を何度も読み直し、いろいろ実践した後で、改めて「ドメイン駆動設計」、「リファクタリング」、「オブジェクト指向入門」、「オブジェクトデザイン」を読み直してみたら、それぞれの本の内容がだいぶわかるようになってきた。 特に「ドメイン駆動設計」の現場でのエヴァンスの設計に奮闘するさまざまなエピソードが、生きた事例として理解できるようになってきた。

その後、Value Object 以外にも、「ドメインを隔離する」「アグリゲート」「リポジトリー」「境界づけられたコンテキストとモデルの整合性パターン」などに関心を広げ、現場での設計に取り入れるようになった。

その結果、コードが整理され、エヴァンス本が目指す「進化と成長を続けるソフトウェア」というものがどういうものか、ある程度、理解できるようになった。ドメイン駆動設計は、ソフトウェアの変更を楽で安全する技法として実践的で効果的だという手ごたえを感じるようになった。

もやもや感

そういう手ごたえもあって、現場で実践するだけではなく、ドメイン駆動設計について、ブログを書いたり、イベントで登壇したり、他の現場に出かけて意見交換や助言をしたり、本を書いたり、いろいろアウトプットをしてきた。

アウトプットしながら、新たな気づきがあり、また次の実践とアウトプットということを繰り返してきた。

しかし、どうもすっきりしないもやもや感も抱えていた。 簡単に言えば、表面的形式的には実践できているかもしれないが、本質をとらえ切れていない、あるいは、本質を言語化できていない、という違和感。

現場でのソフトウェア開発の中で、エヴァンス本にでてくるブレークスルー的な手ごたえをいくども経験できたが、偶然感がつよく、もっと意図的にそこに近づく道があるのでは、という漠然とした予感めいたものもあった。

三つのキーワード

去年の夏に、あるイベントのワークショップ用に資料を作っている時に、その違和感を解消する手がかりをつかんだ。 ドメイン駆動設計と他の設計方法を比較して説明するスライドを作っていた時だった。

その資料と作った時点では、まだうまく言語化できていなかったが、それから数カ月、自分なりに手がかりを、なんとか言語化しようと試みてきた。 イベントやワークショップで、実際にいろいろなキーワード(の候補)を使って説明し、その反応を受けとめる中で、三つのキーワードが中核の概念として明らかになってきた。

それが次の三つのキーワード

  • ビジネスルール
  • 計算モデル
  • 型指向のプログラミング
ビジネスルール

エヴァンス本に繰り返しでてくる「ドメインロジック」「ドメインの知識」「ドメインの理解」などの言葉は、具体性に欠ける。 対象が広くぼんやりとしている。

ドメインロジック」をビジネスアプリケーションの分野に限定すれば、ビジネスロジックとなる。 そして、ビジネスロジックはビジネスルールとほぼ同じ意味になる。

ビジネスルールとビジネスロジックを区別するとすれば、ビジネスルールは、プログラムで表現するかしないかとは無関係な、実際のビジネスの活動の中の取り決めや約束事。ビジネスロジックは、ビジネスルールのある部分をプログラムで表現したもの。

いずれにしても「ドメインロジックに焦点を合わせる」は「ビジネスルールに焦点を合わせる」と捉えることができる。 実際のところ、エヴァンス本にも「ルール」という言葉は300回近く登場する。「ポリシー」や「制約」という言葉も含めれば、ドメイン駆動設計の重要な関心事の一つが「ビジネスルール」にあることはまちがいない。

ドメインロジック」を「ビジネスルール」と置き換えてみると、エヴァンスの意図するところが、より具体的に理解できるようになる。

ドメインの知識とは「ビジネスルールの知識」であり、ドメインエキスパートとは「ビジネスルールについての知識と経験が豊かな人」であり、「ドメイン層」はビジネスルールを記述する場所、というわけだ。

ドメイン駆動設計の考え方を理解し実践するカギは、「ドメインロジック」を「ビジネスルール」という、より具体的な対象としてとらえることだ。

計算モデル

ドメインモデル」も、あいまいでわかりにくい言葉だ。

エヴァンス自身が書いているように、ドメイン駆動設計でいうところの「ドメインモデル」はオブジェクト指向のコミュニティで生まれた設計の考え方の一部である。 オブジェクト指向も、いろいろな解釈がある。私は、データモデルへの対比という意味も含めて、オブジェクト指向のモデルとは「計算モデル」だと思っている。

実際に、エヴァンス本に登場するドメインモデルの例は、次のような計算モデルである。

  • 投資シンジゲートの配分比率計算(シェアパイ)
  • コンテナへの荷物の格納ルール
  • 輸送経路を自社に有利にするための経路選択のバイアスポリシー
  • プリント基板の配置ルールを基にした部品配置と配線の妥当性の判定

ドメインモデル」は、なんらかのルールに基づいた「計算と判定のモデル」ととらえると、だいぶすっきりする。

アプリケーション全体としては、データを永続化したり参照したりする仕組みが必要になる。しかし、「ドメインモデル」だけに注目すれば、データの記録と参照からは隔離した、純粋な「計算モデル」という理解がしっくりくる。

「計算モデル」を実行するには、計算の準備としてデータの参照が必要だし、計算結果を記録することも必要だろう。しかし「計算モデル」を、データの参照と記録から意図的に分離することで、「計算モデル」はプログラミングの対象として、よりわかりやすく、扱いやすくなる。

エヴァンス本では、リポジトリや集約の説明のところで、データの永続化の問題が登場するために、この「ドメインモデル=計算モデル」という図式が、ぼやけてしまっている。しかし、全体を読めば、ドメインモデルは「計算と判定のモデル」であり、「データの記録と参照」からは隔離されたものとして扱われていることがわかる。

リポジトリは計算モデルを入出力の関心事から分離する仕組みであり、集約(アグリゲート)はデータの集約ではなく、「計算の集約」を表現する手段だということだ。集約が維持するのは、データベース上のデータの整合性ではなく、計算の整合性であり一貫性ということだ。

型指向のプログラミング

計算モデルをプログラミング言語で表現する場合、例えばFORTRANのような手続き型の言語でももちろんできるが、エヴァンス本が採用している実装技法は、オブジェクト指向である。 エヴァンス本人が、あるイベントで述べているように、本を書いた当時は "I loved Object Oriented." 、 現在は "I still like it" と続けている。温度感は変わっているが、オブジェクト指向が基本であることは変わっていない。

問題は「オブジェクト指向」といってもいろいろなとらえ方があること。 ここらへんの詳しい話は、以下の説明が必読。

jp.quora.com

簡単に言えば「メッセージパッシング」で代表されるオブジェクト指向と、「型」で代表されるオブジェクト指向があり、両者は本質的に異なるアプローチであるということ。 エヴァンス本を読むと、若干の混乱があるが、基本的には「型」を基本とするオブジェクト指向と理解してまちがいないだろう。

ビジネスルールを「計算モデル」ととらえ、計算モデルをコードで表現するには、「型」に基づくオブジェクト指向プログラミングが役に立つ。

「型」とは、計算の対象となる「値の種類」であり、有効な値の範囲と、その値を使った計算を定義したもの。 計算モデルの表現技法として、「型」中心のプログラミングがぴったりというわけだ。

ビジネスアプリケーションであれば、金額、数量、日付、日数、期間などの値の種類を、それぞれ独自の型として定義し、型ごとに、有効な値の範囲と、必要な計算を定義する。

BigDecimal型やLocalDate型は、有効は値の範囲がとてつもなく広く、可能な計算も多岐にわたる。ビジネスの計算モデルを記述するには、焦点がぼやけてしまう。また、ちょっとした記述のミスでバグが混入する可能性が大きくなる。

その問題領域の計算モデルにあわせて、厳密に値の範囲を制限し、必要最小限の計算だけを定義した独自の型を用意することで、プログラムがみちがえるようにわかりやすく安全になる。

エヴァンス本の、配分比率の計算、コンテナの格納条件の判定、経路選定のバイアス計算などは、型指向でプログラミングする具体例になっている。暗黙の概念を明示したり、制約を表現したり、設計の意図を明確にし、変更を楽に安全にする技法として、クラスを使って型を定義するプログラミングスタイルを採用しているわけだ。

実際、価格計算とか日付計算がともなうビジネスルールでは、型指向のプログラミングで記述することで、ロジックを一か所にまとめてわかりやすく整理できる。

値を「型」として扱う設計パターンの代表であるValue Object パターンは、ビジネスルールの計算モデルを実装するための、基本であり最強の道具といってよいだろう。

実験は続く

「ビジネスルール」「計算モデル」「型指向のプログラミング」

この三つのキーワードでドメイン駆動設計を解釈し、実践してみる実験は、まだはじめたばかり。

自分としては、そうとう手ごたえを感じているけど、実際のコードでもっともっと実験し小さな失敗を繰り返しながら、知見を増やし、こうやってブログで書いたりイベントで登壇したり、いろいろな現場で設計に関心とエネルギーを持つ技術者たちと意見交換をすることで、さらに多くの学びができそうな予感にわくわくしている。

参考情報

ビジネスルール・計算モデル・型指向のプログラミングで作ってみたサンプルアプリケーション github.com

このサンプルアプリケーションを解説したときに使った資料

www.slideshare.net

型指向のプログラミングの設計ガイド: 設計ガイドライン · masuda220/business-logic-patterns Wiki · GitHub

参考書籍: gihyo.jp