🦉

DDDでの要件定義〜実装までの流れについて解説します

2023/10/12に公開

本記事では、ソフトウェア開発手法の一つであるDDD(domain-driven design)を使って要件定義〜実装を行う際のプロセスやポイントについてまとめていきます。
(書籍「ドメイン駆動設計モデリング/実装ガイド」の内容を大いに参考にさせていただいていますが、独自の内容・考察も記載しているつもりです。)

DDD とは?

DDD(domain-driven design)は日本語に訳すとドメイン駆動設計で、ソフトウェア開発手法の一つです。
ドメイン駆動という言葉から、ドメインというものが重要そうだということは伝わってくると思いますが、そもそもドメインという言葉が抽象的でわかりにくいですよね。
ドメインは直訳すると「領域」ですが、DDD で指している「領域」とは「ソフトウェアで問題解決しようとする対象領域」です。
そして、① ドメインについての理解を深めてモデルを作成し(DDD では、後ほど説明するドメインモデル図というものを作成します)、② モデルの内容をそのままコードに落とし込んでいく手法が DDD です。
(この時点だと分かりにくいかもしれませんが、後半まで読むとイメージを掴んでいただけるはずです。)

DDDで開発する際のポイントは大きく 2 つあります。

1 つ目は、あくまでドメインの都合で(ドメイン駆動で)モデルを決めるという点です。
システムを開発していく中で、システム都合でモデルの構造を決めてしまうことはよくあると思いますが、それは NG です。

2 つ目は、モデリングした内容をそのままコードに落とし込むことです。
せっかくモデリングを行っても、実装する過程で、徐々にモデルとコードのギャップが広がっていき、結果としてモデルがメンテナンスされなくなる、といったケースはよくあると思います。
DDD では、ドメイン層というレイヤを用意し、このレイヤに用意したオブジェクトに、モデルで定義した内容を記載します。
(モデリングした内容がいろんなところに散らばらず、一箇所に集約されるためギャップが生まれにくい、そのためモデルをメンテナンスするモチベーションが続くというロジックです。)

この記事の後半では、上記 2 つのポイント、すなわちモデリングの部分と実装の部分のやり方について解説します。

良いソフトウェアと DDD の関係

では、DDD でソフトウェアを開発すると、何が嬉しいのでしょうか。

国際規格 ISO/IEC 9126(JIS X 0129)において、ソフトウェア品質特性モデルというものが定義されています。

このモデルには6つの特性が定義されており、これらの特性とDDDが持つ特徴の関係を示すと以下のようになります(少し強引に関連づけている箇所もありますが)。

これら6つの特性が優れているソフトウェアを、「良いソフトウェア」と考えるなら、DDDは4つの特性に寄与しているので、DDDでソフトウェアを設計・実装することには大きなメリットがあると言えると思います。

逆に、必要な機能が実装されていない機能性の低いソフトウェアや、機能追加・変更が困難になっている保守性の低いソフトウェアに対して、DDDで設計・実装し直すことでソフトウェアの価値を高めることもできます。

DDD で開発するメリットがわかったところで、実際にプロセスを進めていく上でのポイントを、モデリングと実装それぞれ分けて説明していきます。

モデリング

どういう時に DDD のモデリングを行うか?

DDDのモデリングは、要件定義時、つまり、サービス開発の初期段階で実施しますが、これらのフェーズでは、UXデザインの手法である、ペルソナ定義やカスタマージャーニーマップの作成から実施するケースもあると思います。

これらの使い分けとしては、作成するサービスのイメージが既にある程度明確な場合、例えば既存の業務を電子化するシステムを構築するといった場合は、DDD でモデリングをしながらお客様から要件や現状の業務の状況を聞き出していきます。
一方で、新規ビジネス創出などの場合は、UX デザインから始めて、サービスの内容が固まってきた段階で、DDD 等を使ったモデリング、システムの設計に入っていきます。

また、システム設計をする際に全てのケースでDDDによるモデリングを行うわけではなく、ある程度ビジネス要件が複雑であることが想定される場合に使用するケースが多いです。
DDDでのモデリングは、システムを開発するエンジニアだけでなくドメインに詳しい現場の人と行っていくことで、双方の理解を深め認識齟齬を防げるというメリットがあるため、ある程度ビジネス要件が複雑な場合に効果を発揮します。
逆に言うと、データベースからデータを取ってくるだけ、といったシンプルなケースだと予想される場合はわざわざDDDによるモデリング等は行いません。

モデリング時に作成するもの

DDD におけるモデリングの方法・作成するものについて明確に定義されているわけではありませんが、以下を作成するケースが多いです。
例として、商品の生産を行う企業で日々の生産実績入力をシステム化するケースの図も記載します。

業務フロー図

まずは既存の業務の流れを図示した、業務フロー図です。DDD以外の場合も作成することが多いですが、DDDで進めていく場合も役立ちます。
こちらを作成することで、全体を俯瞰した上でシステム化する対象範囲を決めることができます。
逆に作成しなかった場合、システム化する範囲が広かったり狭かったりすることが後になってわかり、結果的に費用対効果の低いシステムになってしまいます。
以下の例だと、生産の計画・実績はこれから構築するシステムで管理したいけど、勤怠の管理は既に別のシステムがあるから考えなくて良いよね、といった議論を行うことができます。

ユースケース図

続いてユースケース図です。上記の業務フロー図で明確になったシステムの対象範囲について、もう少しブレークダウンして誰がどのような使い方をするシステムなのかを「ユーザ目線で」記載していきます。
ユースケース図を作成するメリットは、「開発者目線ではなく、ユーザー目線の視点を得られる」、「お客様との認識の共有ができる」といった点があります。
業務フロー図は若干堅苦しい図になってしまうため、具体的にシステムに対してどのような操作をするのかが見えてこず、関係者間で認識の齟齬が生じてしまう懸念があります。
一方で、ユースケース図はユーザ目線で記述するため、システムに対する操作がイメージしやすく、認識の齟齬を防いでくれます。

ドメインモデル図

次はDDDの核となる、ドメインモデル図です。ドメインモデル図には以下の内容を書いていきます。

  • オブジェクトと代表的な属性
  • ルール・制約
  • 集約

最後に「集約」という新しい言葉が出てきましたが、こちらは今はスルーしてもらっても問題ありません。(まとめてデータベースに保存したいオブジェクトのまとまりです。)
重要なのは、2つ目に記載した「ルール・制約」で、こちらにどれだけ重要な事項を記載できるかがポイントとなります。
下記の図はまだ不十分で、例えば「人員」オブジェクトの役割にはどういったものがあるの?という疑問が浮かんだら、議論してどんどん追記していくようにしましょう。
こちらに記載したオブジェクトがDDDではそのままクラスとなり、このクラスにどれだけ現実に沿ったルール・制約を詰め込めるかが重要となります。

ユビキタス言語

最後にユビキタス言語で、こちらはいわゆる用語集です。
お客様と話をしている中で、そもそも業界専門用語で全然理解できなかったり、伝わっているつもりでもそれぞれがイメージしている内容が異なっていて、認識ずれが発生するケースは多々あると思います。
また、複数ドキュメントがあった時に、ドキュメント間でも微妙に違う言葉が使われていて混乱するケースもあると思います。
ユビキタス言語の策定はそれらを防いでくれます。

以下のようにマークダウンで記述しておいて、辞書的に参照するケースが多いです。

DDDとマイクロサービスの関係

実装の話に入る前に、DDDでのモデリングはマイクロサービスとも相性が良いと言われているので、ここで簡単に説明します。

これまでの例は、商品の生産という1つのコンテキストを考えていました。(コンテキストは直訳すると文脈・環境という意味で、DDDではドメインモデルが有効な範囲と考えてください。)
これに加えて、商品の販売や物流を管理したいという要求がそれぞれ異なる部門からあがり、同じドメインモデルで表現しようとするとどうなるでしょうか?
これまで商品オブジェクトには、生産管理に必要な「在庫」という属性のみを持っていましたが、これに加えて「価格」や「発送地」など、生産管理には不要な属性が増えていきます。

こうなると、ドメインモデルやユビキタス言語を整理していく中で会話が噛み合わなくなったり、実装面でも商品クラスが肥大化して保守性が下がっていきます。
こうした状況を防ぐために、DDDではモデルが適用される範囲を明治的に定義し、それぞれの中でモデルの統一を目指します。そして、この範囲を「境界づけられたコンテキスト」と呼びます。

一方で、マイクロサービスの考え方は、モノリシック(一枚岩)のサービスを作るのではなく、マイクロ(小さな)サービスに分割しようというものですが、
どういった単位で分割すれば良いのか?という点がよく課題となります。

ここで使えるのが、DDDの「境界づけられたコンテキスト」です。DDDで決めた、1つのコンテキストで1つのアプリケーションを構成するようにすることで、マイクロサービスを実現することができます。

したがって、マイクロサービスを実現するにはドメインモデルの粒度を適切に保つことが重要となります。
そのためには、議論を行っている中で話が噛み合わなくなってきた場合に、「これは異なるドメインの問題ではないか?」という視点を持つことが重要で、そうした場合は別のドメインモデルとして表現していく決断が必要となります。

実装

ここからは、モデルの内容をどうやってコードに落とし込んでいくか、という内容です。
こちらについては、先日、zenn に「DDD で開発する際におさえておきたい 4 つの基本事項」という記事を投稿したところ、そこそこ反応をいただけたので、詳細はこちらを参照ください。

https://zenn.dev/hisamitsu/articles/2937fc4dd9bd4c

記事の抜粋となりますが、ポイントは以下です。

DDD で実装を行うメリット

  • ロジックを書く場所に悩まない・チームで統一できる
  • テストが書きやすい
  • ユースケース(処理の流れ)が理解しやすい

DDD での実装のポイント

  • ORM のエンティティとは別にドメイン層にエンティティを用意する
  • リポジトリの取得メソッドはドメインオブジェクトに詰め替えて値を返す
  • ドメインオブジェクトとリポジトリは 1 対 1 の関係ではない
  • ドメインオブジェクトの生成メソッドと DB の値から再構築するメソッドは分ける

まとめ

DDDでソフトウェアを開発する際にポイントとなる、モデリングと実装のうち、本記事では主にモデリングの部分について記載しました。
教科書的には上記の通りなのですが、実際に、業務的な知識が薄い状態でお客様から重要なルールを聞き出しながらモデルを作っていく作業は、結構難しいなと感じていて、こちらに記載した内容を自分がしっかり遂行できるかというと正直かなり怪しいです。
そういう意味でも、なかなか難易度の高い開発方法だと思いますが、ばちっとハマれば高品質なものを開発して、継続的に育成していくことができる手法だと思うので、引き続き勉強していきたいと思います。

Discussion