ドメイン駆動設計入門

"Beautiful Develpment"(10/27 DevLOVE)の講演資料と原稿

はじめに

本日(10/27)、DevLOVE様主催で、"Beautiful Develoment"と題されたイベントが開催されました。これは「ドメイン駆動設計("DDD:Domain-Driven Design")」を題材に、入門から実践までを語り尽くすというコンセプトのものです。このイベントにおける講演のトップバッターとして、ドメイン駆動設計の根底にある基本的な考え方についてお話しさせて頂きましたので、講演資料と原稿を公開いたします*1


スライドはこちら


アジェンダは以下の通りです。

  • 導入
  • オブジェクトとは?
  • モデルとは?
  • ドメイン駆動設計とは?

まずは、ドメイン駆動設計のベースとなっている、「オブジェクト指向」や「モデル」について整理した上で、実際にドメイン駆動設計とはどういうものかを見ていきます。「言葉」を軸にドメイン駆動設計の読み方について1つの方向性を示すことができたらと思っています。

導入

オブジェクト指向業界では、最重要著作の一冊に位置づけられながらも、500ページ以上という厚さ、そして、決して平易とは言えない文体によって多くの読者を苦しませてきた書籍、それが「ドメイン駆動設計」です。出版されたのは2004年とPofEAAなどとほぼ同時期ですが、Yahoo!グループDDDメーリングリストは現在でもなお活発に活動が続いており、この本の影響力の高さを物語っています。このメーリングリストにおける最近のホットな話題としては、CQRSなどが挙げられるでしょう。また、著者のEric Evans氏は、"Time and Money"ライブラリの開発などを経て、現在Cassandraの開発に携わっています現在も、domainlanguageにて、コンサルティングや教育などを行っています。

オブジェクトとは?

オブジェクト指向」についてご存知の方は多いと思いますが、改めて「オブジェクトとは何か?」と説明を求められると戸惑うこともあるのではないでしょうか。「デザインパターンを使った実装をするための言語」というのは誤解で、デザインパターンとは、累積された問題解決のパターンであり、つまりオブジェクト指向言語を使う中で生まれたものです。もう1つ「現実世界のモノを表現したもの」という説明もあります。入門としては分かりやすいかもしれませんが、実はこれも正確ではありません。それではいったい何が違うのか、古典的ではありますが「虹」を例にして考えたいと思います。


さて、虹はいくつの色からできているでしょうか?


僕が子供の頃には「7色」と習ったような気がします。上から順に「赤・橙・黄・緑・青・藍・紫」で7色ですね。でも本当ですか?色の実体は光の波長ですから、実際には境目のないグラデーションです。そのグラデーションに対して誰かが境界線を引き、大体この辺が「赤」と名前を付けただけです。大げさな表現をすれば、「僕らは言葉によって世界を切り分け、そこに名前を与え、意味に囲まれて生きている」ということですね。あるモノに意味を見出し、他のモノと切り分け、そこに名前を与えることで自分たちの世界を構築しているのが人間だ、ということです。オブジェクト指向において、オブジェクトに表現させようとしたのも、実はモノ自体ではなく、「概念」すなわち「名付けられ、意味を与えられたユニット」なのです。

モデルとは?

これも、よく聞くわりに改めて意味を問われると困るものと言えるでしょう。私がこの業界に入って「モデル」という単語を最初に聞いたのは、MVCの説明においてだったように記憶しています。「モデルは業務処理を書く場所」と覚えて、アプリケーションの実装に入った方がほとんどだと思うのですが、そこで実際に書いているコードは、if/forを駆使してList/Mapを操作するというスタイルが多いのではないでしょうか。


このように、リクエストに対する処理を手続き型に記述するスタイルが、いわゆる「トランザクションスクリプト」です。オブジェクト指向の愛好家にとっては許し難い罪悪に見えるこのスタイルも、実は悪い面ばかりではなく、どういう処理が行われるのか、とにかくメソッドの中を最初から順に読んでいけば分かる安心感や、実装の簡単さ、作業分担の容易さなどからも、ウォーターフォール型大規模開発との相性は悪くありません。しかし、もともとトランザクションスクリプトで書くことを想定していたならば、わざわざMVC(Model-View-Controller)という名前がつけられたでしょうか?SVC(Script-View-Controller)や、PVC(Proceure-View-Controller)の方が良かったのではないでしょうか?


こういう時は、原典に戻りましょう。1979年(30年前!)に書かれたMVCの原典では、モデルは「知識の表象」とされています。ユーザの頭の中にある知識/メンタルモデルを写し取るものだと考えられていたんですね。「メンタルモデル」とは、私たちの世界のとらえ方、言葉によって頭の中に構築された世界の像です。それをコンピュータの中に写し取るために登場するのが、オブジェクト指向というパラダイムです。メンタルモデルを構成する概念をクラスとして表現することで、メンタルモデルを写し取ろうとしたのです。


こうした、概念を表現するオブジェクト指向というパラダイムと、オブジェクト指向を用いてメンタルモデルをコンピュータの中に持ち込もうという発想がドメイン駆動設計の出発点となります。

ドメイン駆動設計とは?

ドメイン("domain")とは、ユーザが知識を持ち、 影響を与え、 活動する領域であると説明されます。"domain"という単語は日本語にしにくいのですが、もともとは「領土」「支配領域」という意味を持つもので、「対象領域」と訳されることもあります。要するに「業務領域」「事業対象」などと考えれば分かりやすいでしょうか。一方、ドメインモデルとは「ドメインについてのモデル」です。こう書いてしまうとそのままなのですが、重要なのは「そのドメインの専門家は、ドメインをとらえるための、適切に抽象化されたモデルを持っている」ということなのです。


それを踏まえて、ドメイン駆動設計の主張は以下の2点です。

  1. ソフトウェアの開発においては、まず、ドメインドメインロジックに焦点を合わせる
  2. 複雑なドメインの設計はモデルをベースにする

1.は「要素技術やアーキテクチャよりもドメインの方が重要だ」ということです。2.は「専門家が持つドメインモデルをベースにしてドメインを設計せよ」ということです。したがって、ドメイン駆動設計の第1歩は、そうしたドメインモデルを専門家と開発者との間で共有することとなります。


前述した通り、私たちのメンタルモデルは「言葉」あるいは「概念」によって構築されているものでした。これは専門家が持つドメインモデルに関しても同じことが言えるため、ドメインモデルを共有する上での武器もやはり言葉ということになります。その時に重要なのが、同じ言葉を使った時に、確実に同じ概念をイメージするということです。言葉は実体を持つものではなく、世界を切り分けるものでした。この境界線の引き方は人によって異なりますから、ある単語を聞いた時に自分が想起するイメージが、その単語を話している人のイメージと同じである保証はどこにもありません。したがって、ある概念は単独で理解することはできず、他の概念との関係において理解する必要があるということになります。


こうしたモデルを構成する言葉は、会話やドキュメントなど、プロジェクト内のあらゆる場所で使われるべきだと考えられています。このプロジェクト内にあまねく行き渡った言葉が、ユビキタス言語("Ubiquitous Language")というパターンとして説明されます。さて、このあらゆる場所という表現には、当然コードも含まれています。ユビキタス言語によって構成されたドメインモデルを、文字通り「反映」させてソフトウェアを作ること、それがモデル駆動開発("Model Driven Development")です。このユビキタス言語とモデル駆動開発ドメイン駆動設計においてもっとも重要な2つのパターンと言えるでしょう。


要約すれば、ドメインの専門家が持つドメインについてのモデルを、ユビキタス言語をベースとしつつ開発者と共有し、さらにその共有されたドメインモデルを反映させてソフトウェアを作るというダイナミズムがドメイン駆動設計の根幹だということになります。


こうした思想をどうやって実現していけば良いのか、ということについて、「アーキテクチャ」と「プロセス」という2つの観点から考えていきましょう。

アーキテクチャ

アーキテクチャとは何か、ということについては諸説ありますが、ここでは「構造を規定しつつ、可変性を支える戦略」と考えることにします。ソフトウェアにおいて、無制限な柔軟性はあり得ません。ほとんど変化することのない安定した構造をベースにしつつ、変化する可能性がある場所に対して、選択的に柔軟性を与えることが必要になるのですが、こうした固定化と柔軟性を決定する戦略こそがアーキテクチャであるということです。


こうしたアーキテクチャについて、ドメイン駆動設計では、レイヤ型アーキテクチャ("Layered Architecture")が提唱されます。これは、以下の4階層から構成されています。

これは単に階層を分けましょうということではなく、ここで重要なのは、ドメインモデルのための空間を「ドメインレイヤ」として他のレイヤから分離するということです。これによってドメインモデルが独立し、柔軟に設計することができるようになります。


さらに、こうして独立したドメインモデルが、どのような要素によって構成されるかということについても、ドメイン駆動設計の中では説明されています。主要な要素としては以下のものが挙げられます。

  • エンティティ("Entity")/バリューオブジェクト("Value Object")
    • データモデルを表現するもの。識別子を持ち状態変化がおこるエンティティと、そうではないバリューオブジェクトが区別される。
  • サービス("Service")
    • データとしてよりも、アクションや処理として表現される方が適切なもの。
プロセス

ドメインモデルの共有と構築を軸としたドメイン駆動設計にとって、その開発プロセスアップフロントなものではなく、イテレーティブなものとなります。まず開発者は、ドメインの専門家が持っているモデルを共有するため、頻繁にコミュニケーションをとる必要がありますし、専門家にしてみても、頭の中に描いているモデル自体が実は完成されたものではなく、フィードバックを受けて変化する可能性があるものなのです。こうしたモデルの変化について、Evansは深さ("deep")という言葉で表現しています。モデルが深みを増していくんですね。


こうしたモデルの深化において主要な役割を果たすのも、やはり言葉です。うまく表現できなかったもの、あいまいだったものが、それを示すある言葉を与えられることで、一気に明確になるということは少なからず経験があるのではないでしょうか。これについて、Evansは「より深い洞察」と表現しています。こうしたモデルの変化は直線的に起こるだけではなく、ある日突然大きく変化することもあります。こうしたブレイクスルーは日々モデルを洗練させていく行為の先に突然訪れるものだとされています。


ドメインモデルとそれを反映させたソフトウェアは、こうした変化を受け入れることができるものでなければなりません。これは、1つには前述のレイヤ型アーキテクチャによって実現されるドメインの独立性によって支えられますが、さらに、ドメインモデル自体もそうした変化に対応できるよう柔軟に設計されている必要があります。こうしたドメインモデル自体の設計手法については、意図が明確なインタフェース("Intention-Revealing Interface")や副作用のない関数("Side-Effect-Free Function")といった、オブジェクト指向のプラクティスとも言えるものが説明されています。

戦略的設計

ここまで、あるドメインモデルをどうやってソフトウェアに組み込むかということについて考えてきましたが、ドメイン駆動設計にはさらに先があります。それが「システムが複雑化/巨大化した際にもモデルとの整合性を保つためにはどうすればよいのか」を考える、戦略的設計("Strategic Design")です。


戦略的設計は、文脈("Context")、抽出("Distillation")、大局的構造("Large-Scale Structure")という3つの観点から説明されます。これらの観点について概要を示します。


文脈
ある言葉は他の言葉との関係において一定の意味を持ちますが、この意味の同一性は無制限に保証されるわけではありません。例えば、「受注」という言葉が示す内容は、業務によって少しずつ異なっているでしょう。これは言葉に意味を与えている文脈が異なることに起因しています。そして、ある文脈には有効範囲が存在します。Evansは境界づけられた文脈("Bounded Context")という概念を用いて、文脈が持つそうした有効範囲を明確にするよう促します。さらに、企業レベルでシステムが統合される場合には、異なる文脈が共存することになりますので、それら文脈間の関係を文脈の地図("Context Map")として描き出すことが重要であるとされています。


抽出
"Distillation"は「抽出」の他、「蒸留」や「精製」とも訳されることがある単語で、つまり、「純粋なもの/本質」("essence")を取り出すことを意味しています。ドメインモデルを作り上げる行為もある意味で専門家の目から見た本質を抽出する行為でしたが、同じことはより広大なコンテキストマップに対しても実施することができます。こうして最も価値のあるコアドメイン("Core Domain")を識別し、それを共有した上で、重要度に適した投資を行うことが必要になるのです。


大局的構造
システムが複雑化・巨大化するに伴い、開発をスムーズに行うためにモジュール("Module")に分解することによる分割統治が行われるようになります。しかし、そうした分割統治はシステムの全体像を見えにくくしてしまいます。そのような全体像を見渡す大局観を失ってはならないということが、大局的構造として語られています。具体的なプラクティスとしては、システムをとらえるメタファー("System Metaphor")をメンバの間で共有し、それをユビキタス言語に吸い上げていくといったことが説明されています。

まとめ

ドメインの専門家が持つドメインモデルを共有すること。それを反映させたソフトウェアを作ること。そのために繰り返される、終わらない営み。さらにそのソフトウェアがスケールアウトしてもモデルとの整合性を保つこと。ドメイン駆動設計で語られるこうした思想について概観してきました。実際の本の中では具体的なプラクティスについても詳細に語られていますが、こうしたプラクティスを実践するのは決して容易ではないとEvans自身も言っています。しかし、本の最後でEvansが送ってくれるのは、言葉を大切にしつつ、常にモデルを意識しながら、つまづくことがあっても、立ち上がって進んでいけ、という力強いメッセージです。

最後に

ドメイン駆動設計を読んでいると、自分が今置かれている環境とのギャップにうんざりすることもあると思います。例えば、ウォーターフォールであったり、トランザクションスクリプトであったり、ということですね。しかし、あきらめる理由を見つけて満足するのではなく、Evansから学んだことを活かす方法を探すことはできるでしょう。


「要件定義の時にどこまで顧客のメンタルモデルに迫れているか」「クラス名、せめてメソッド名や変数名は業務を適切に反映したものになっているか」「トランザクションスクリプトであっても、許された範囲でクリーンなコードが書けているか」- プログラマとして自分の書いたコードに誇りを持てるよう、できることからやっていきましょう。


大きなブレイクスルーを生み出すのは、小さなプラクティスを積み重ねる日々に他ならないのですから。



関連記事



Domain-Driven Design: Tackling Complexity in the Heart of Software

Domain-Driven Design: Tackling Complexity in the Heart of Software

DDDの日本語版が出版されます(2011/03/24追記)
エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

エリック・エヴァンスのドメイン駆動設計 (IT Architects’Archive ソフトウェア開発の実践)

*1:話の内容には一部相違があるかもしれませんが、ご了承下さい