sandbox

Scala, Android, Architecture, Management, Service Design あたりを主戦場としております

ドメイン駆動設計の道標

この記事は 2016年 第2のドワンゴアドベントカレンダー、20日目の記事です。

qiita.com

ドメイン駆動設計に関して悩める若者に送るポエムを書いていたら長くなりました。 20日目なはずなのに今日は 12/25 ですが、お察しください。

TL;DR

  • ドメイン駆動設計には3つの顏がある
  • それは「哲学」「戦略」「戦術」である
  • 「戦術」にスポットがあたりがちだが、まず「哲学」とコアの「戦略」から理解する
  • プロダクトにおけるドメインモデルの全体像を描いてから「戦術」を検討しよう
  • ドメイン駆動設計をどの程度取り入れるかの 「ドメイン駆動設計の適用レベル」について

はじめに

ドメイン駆動設計(DDD)、以前と比較して認知が上がってきたのか、よく「DDD やってるんですか?」 「DDD ってどうはじめればいいんですか?」と聞かれることがあります。そしてこの時にまず話に上がるのが、エンティティ、集約、レイヤードアーキテクチャといった設計パターンの内容が多いです。

DDD は学習しはじめに陥る良く罠として、レイヤードアーキテクチャなどの設計パターンのみ、つまりは一部の「戦術」のみを DDD として認識している事が多くある様に思います。 新しく DDD を取り入れるにあたっては、戦術のみではない DDD のアウトラインを認識し、その上で自身のプロダクトでどこまで取り入れるか、「DDD の適用レベル」を考えられると、DDD を現実のプロダクトにより取り入れやすくなります。

この記事では、DDD 本を読んだもののいまいち消化不良を起こしている様な方に向けて、DDD のアウトライン、そして実践における DDD の適用レベルという考え方について紹介します。

尚、この記事の中心はあくまで私の捉えた DDD の実践思想であり、エリック本人の意図とずれている可能性もあります。

対象読者

  • DDD 本を読んだがもやっとしている人
  • DDD を取り入れてはいるものの、実は設計手法としか認識していない人
  • ! DDD そのものについては詳しく説明をしない為、DDD を全く知らない人向けには書いていません

ドメイン駆動設計とは

DDD について簡単に説明します。 ひとことで言うと「ドメイン(問題解決領域)を中心に据えたソフトウェアの設計哲学、手法」です。 ほぼままですが、重要なのはソフトウェア開発の中心とするのは、技術や UI でもなく、ドメインである、ということです。

では、ドメインとはなんでしょうか。

ドメインは、業務領域と表現されているものも多いですが、最近らしい言い方をすれば、「提供するプロダクトが扱う問題解決領域」のことを指します。

とすると、「提供するプロダクトが扱う問題解決領域を中心に据えたソフトウェアの設計哲学、手法」となるのですが、もう少し具体的に説明するとどの様な定義になるのか。今年開催された DDDEU 2016 というブリュッセルで開かれたイベントでは、著書のエリック本人が DDD の明確な定義は難しいと前置きした上で、DDD とは以下4つの原則からなると説明しています。

What is Domain Driven Design?

  • Focus on the core complexity and opportunity in the domain
  • Explore models in a collaboration of domain experts and software experts
  • Write software that expresses those models explicitly
  • Speak ubiquitous language within a bounded context

youtu.be

動画の発言も含め、意訳すると以下の様な意味になるでしょう.

ドメイン駆動設計とは何か?

  • ドメインの中にあるコアとなる複雑さ、クリティカルなパートにフォーカスする
  • ドメインとソフトウェアのエキスパートが協力しモデルを探索する
  • モデルをはっきりと表現するソフトウェアを書く
  • 境界づけられたコンテキストの中でユビキタス言語を話す

この「DDD とは何なのか?」という説明から明確に認識すべきは、DDD = 設計手法ではないという事です。 勿論、設計手法の話も含まれますが、DDD の根幹は、「現実の複雑な問題解決領域をどの様にソフトウェアに落としこむか」というテーマの、組織、開発プロセス、設計論に及ぶソフトウェア開発哲学であり、その探求の過程で生まれたモデリングの戦略、戦術のパターン、思想の集まりです。

DDD のコンセプトを正しく理解し、実践、議論を深めるには、よくスポットがあたりがちなレイヤードアーキテクチャ、エンティティなどの設計手法、つまり戦術だけではない事、そして、言及の対象もソフトウェアそのものについてだけでなく、組織、開発プロセス論まで含む、ソフトウェア開発哲学であるという事をしっかりと認識する必要があります。

ドメイン駆動設計の3つの顏

先程、DDD のことを設計手法だけではない、ソフトウェア哲学でもあると表現しました。 DDD には3つの顏があると考えており、それは「哲学」「戦略」「戦術」としての DDD です。

具体的には、DDD の思想は大きく以下の様に分類できます。

  • 哲学 … 「現実の複雑な問題解決領域をどの様にソフトウェアに落としこむか」というドメインモデリングと、それを取りまく組織論、開発プロセスをテーマとしたソフトウェア開発の哲学としての側面
  • 戦略 … 原典第1部、第4部に代表される、ドメインモデリングに繋げるための戦略レベルのパターン、思想としての側面 (ユビキタス言語/境界づけられたコンテキスト/モデル駆動設計等)
  • 戦術 … 原典第2部に代表される、モデルをソフトウェアとして具体的に表現する戦術レベルのパターン、思想としての側面 (エンティティ/リポジトリ/レイヤードアーキテクチャ等) ※ ここでいう戦略、戦術は軍事用語としての抽象度というよりは、原典における概念の区分けに基づいた意味で使っています

このアウトラインを元に DDD というコンセプトを認識していれば、例えばレイヤードアーキテクチャやエンティティといった戦術的パターン = DDD だという誤解もなくなります。戦術は、オブジェクト指向、関数指向などのパラダイムの変化や、環境によって大いに変わりえる為、それ自体は DDD の本質ではありません。

事実、エリック自身も前述した DDDEU 2016 では関数指向プログラミングの登場により、エンティティなど一部パターンは変わりうると話しています。動画内では具体的な言及が少なかった為、どの様な変化を想定しているかは不明ですが、おそらく Actor モデルで集約が表現できるとかそういった意味だと思います。

まとめると、「哲学」「戦略」としての DDD を理解し、自プロダクトにおけるドメインモデルの全体像を描いてから、はじめて「戦術」を検討すればよいのです。DDDEU などの海外の動向を見ていると、エリックの哲学や戦略を引き継ぎながら、より発展した戦術の議論に進んでいる様に思います。

ドメイン駆動設計の適用レベル

この3つの軸で DDD を捉えると、哲学、戦略面では、思想自体の汎用性は高くあらゆるプロダクトに取り入れる事はできます。

仮に戦術を完全には採用せず隔離されたドメインモデルが構築されていなかったとしても、プロジェクトメンバー内で共通のメンタルモデルが構築されており、そのドメインにおける問題がソフトウェアによって解決できていればそれだけでも大きな意味があります。

勿論、冒頭に紹介した DDD の原則を守っていない状態は厳密には「DDD を実践している」とは言えないでしょう。 が、個人的には、意図的に原則や戦術を捨て「DDD の思想を取り入れる」という考え方でも十分に有用だと考えています。

最後に普段私がプロダクトの設計時に考慮している「DDD の適用レベル」というコンセプトについて紹介します。

レベル1: IA としてのドメイン駆動設計を取り入れる

このレベルでは、幾つかの戦略レベルの思想を取り入れ「ドメインの領域を定め、ユビキタス言語を構築する」までを実施するものです。 大きく以下のパターンを利用してアーキテクチャを考慮します。

これはドメイン駆動設計というよりは、責務の境界線を意識した情報設計(IA)をしましょうというレベルの話です。 毛色は全く異なりますが、こちらの様な本も参考になるかもしれません。

今日からはじめる情報設計 -センスメイキングするための7ステップ

今日からはじめる情報設計 -センスメイキングするための7ステップ

ここで重要なのはユビキタス言語は「用語集」ではないという事も言えます。 言葉は他の言葉との関係性により、意味が決まります。その為、二次元的な用語集ではなく、それらの関係性が分かるダイアグラムもつくるのが望ましいです。

レベル1は、「モデルとコードが一致していること」は重視せず、プロダクトのメンタルモデルの形成と、そのモデルによる一貫性あるユーザー体験の提供を重視し、語彙の統一はしつつも、ソフトウェアは問題解決のソリューションとしてのみ機能させるイメージです。

レベル2: トラディショナルな OOP ベースのドメイン駆動設計を取り入れる

いわば守破離の守。 DDD 原典や、実践ドメイン駆動設計などで触れられている OOP ベースのトラディショナルな DDD を実践するレベルです。 レベル1に加え、大きく以下のパターンを取り入れます。

実践にあたっては DDD 原典だけでは具体性に欠け、コードに落とし込むにはかなりの試行錯誤が予想されます。 実践ドメイン駆動設計など、コードレベルに落としこまれた書籍も参考にすると良いと思います。

実践ドメイン駆動設計 (Object Oriented SELECTION)

実践ドメイン駆動設計 (Object Oriented SELECTION)

またこのレベルの注意としては、コードと切り離せなくなる都合上、技術やフレームワークなどとの相性問題、そして実施する場合のコストがどうしても発生します。 Android/iOS での開発、Ruby on Rails での開発、そのプロダクト、ドメインにおいて、戦術レベルでの DDD の厳密な適用が必要なのかよく考える事も重要です。

レベル3: より発展的なドメイン駆動設計を取り入れる

守破離の破、離の段階です。 ドメイン駆動設計の哲学、一部のコアとなる戦略、思想を引き継ぎ、関数指向のアプローチ、イベント指向のアプローチなど、新しい戦術を適用するレベルです。

Event Sourcing, CQRS, Functional / Reactive Domain Modeling, DCI など、他のコンセプトとドメイン駆動を組み合わせる様な実践方法が多く登場しています。

関数指向やアクターモデルを利用した実践例としては、以下の書籍が参考になります。

Functional and Reactive Domain Modeling

Functional and Reactive Domain Modeling

Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka

Reactive Messaging Patterns with the Actor Model: Applications and Integration in Scala and Akka

境界づけられたコンテキスト、コンテキストマップなどの戦略的設計や、集約、ドメインイベントなどの戦術的設計をどの様にすればよいかを、 戦略、戦術という明確な区分けの中での具体的な手法を知りたければこの書籍が参考になります。

Domain-Driven Design Distilled

Domain-Driven Design Distilled

まとめ

もし今携わっているプロダクトでメンバー間全く共通の概念がつくれていないと思うのであれば、まずレベル1の IA としての DDD をまずやってみましょう。 少なくとも情報、概念のカオスからは離れ、UI やコードで利用される語彙も整えられてくるはずです。

そして、その上でプロダクトが複雑なドメインを扱う場合や、長期的に保守が予想され技術的な外的変化から中心となるコードを守りたい場合は、レベル2を検討しましょう。

最後に OOP を採用していない場合や、旧来のアーキテクチャで対応できないスケーラビリティを要求される場合など、より発展した活用が必要であればレベル3に挑戦しましょう。

いずれにせよ、DDD の根幹は「現実の複雑な問題解決領域をどの様にソフトウェアに落としこむか、変化させていくか」という哲学であり、このテーマに取りかかったのならあなたも智を求める立派なドメイン駆動の哲学者です。 先人達のパターンを参考にしつつも、具体的な実践方法は自ら模索していくというマインドが必要で、その行為も含めて DDD の実践だと捉えています。

この記事が DDD を実践していく上での助けになれば幸いです。

おわり。