😸

【DDD】1年やってみてわかったドメインモデリングの型

2022/12/14に公開

こんにちは。株式会社InnoScouter CTOの大西(Twitter: @monarisa_masa)です。

InnoScouterでは、DDD(ドメイン駆動設計)を用いて開発を行っています。(ちなみに、技術スタックとしては、Ruby製WebフレームワークであるHanamiを採用しています。Hanamiについての話が気になる方はこちらからどうぞ。)
https://zenn.dev/monarisa_masa/articles/5fa1522a258add

今回は、弊社のDDDの活動の中でも、ドメインモデリングの取り組みについて紹介していきたいと思います。
実際に1年ほど運用してみて、ある程度、弊社の中で型が決まってきたので、その型を共有したいと思います。
本記事を読んで、「ユビキタス言語ってこういう風に作っているのか」「ビジネスサイドをこういう風に巻き込んでいくのか」ってところを感じとっていただけると嬉しいです。

※ そもそもドメインモデリングという言葉を聞いたことがない、という方にもわかるように説明したいと思います。

この記事の対象読者

  • ドメインモデリングが何かを知りたいと思っている方
  • ドメインモデリングをやってみたいと思っている方
  • ドメインモデリングを実践してはいるが、ビジネスサイドを巻き込めずに悩んでいる方
  • ユビキタス言語をスプレッドシート等で単語帳的に管理しているが、保守困難になっている方

※ ユビキタス言語とは、ビジネスサイドとエンジニアの間の共通言語で、会話、ドキュメント、コードに至るまで統一的に使用される言葉のことです。ユビキタス言語の意義については後述します。

ここからの話の流れ

ここからは、下記の順に話していきます。

  • ドメインモデリングとは?
  • ドメインモデリング導入前の課題感
  • そもそもドメインモデリングをして何が嬉しいの?
  • 実際どのように運用してる?
  • Q&A
  • まとめ

ドメインモデリングとは?

ドメインモデリングとは、簡単に言うと、DDDにおいて、「作ろうとしているシステムに出てくる登場人物(人に限らない)を洗い出し、それらの関係性を整理すること」です。

例えば、看護師のタスク管理を題材にしてみると、患者や、患者に対して行うタスクが存在するとします。その場合、「患者」「タスク」「その2つの関係性」を図示することは、れっきとしたドメインモデリングです。

そして、ドメインモデリングは、基本的に、ドメインエキスパートとエンジニアが一緒に行うことを前提としています。
ドメインエキスパートとは、問題解決をしようとしている領域に詳しい人のことで、ビジネスサイドがその役割を担うことが多いです。

※ エンジニアが、ドメインエキスパートである現場もなくはないのですが、大半はビジネスサイドがその役割を担うことが多いので、今回はその前提(ビジネスサイド=ドメインエキスパート)で話します。

また、こちらの記事は、今回の話のベースになっているので是非ご一読いただければと思います。
https://little-hands.hatenablog.com/entry/2022/06/01/ddd-modeling

ドメインモデリング導入前の課題感

弊社では、DDDを始めたての頃、以下のような悩みを持っていました。

  • DDDの活動において、ビジネスサイドを、どうやってどの程度巻き込んでいいのかわからない。
  • エンジニアがどうすれば主体的に、機能実装のwhyの部分にまで関与できるのかわからない。
  • ユビキタス言語を生み出す方法が場当たり的で、属人化してしまっている。
  • ユビキタス言語をスプレッドシートに単語帳的にまとめても、更新を忘れてしまい形骸化する。

そんなとき、先程の記事に出会い、上記の課題を解決するには、ドメインモデリングが有用そうだという結論に至り、導入を決めました。

そもそもドメインモデリングをして何が嬉しいの?

ドメインモデリングをすることによって、「作ろうとしているシステムについて、ビジネスサイドとエンジニアが、共通認識を持ち、意思疎通する」ことが可能になります。

具体的にドメインモデリングを実施する利点としては、下記のようなものが挙げられます。

1. ビジネスサイドとエンジニアの共通言語である、ユビキタス言語が決まる。

  • ビジネスサイドとエンジニアの専門用語の違いによる、コミュニケーション上の翻訳作業が消える。
    • ex. 看護師のタスク管理システムにおけるタスクを「tasksテーブルのtaskのこと」などと読み替えなくて良くなる。
  • エンジニアは命名で悩まなくなる。
    • ex. 看護師のタスク管理システムにおけるタスクについて、「todo」と命名すべきなのか、「task」と命名すべきなのかを迷うことがなくなる。

2. 設計に、ビジネスサイド(ドメインエキスパート)の持つ業務知識を反映することができる。

  • ドメインモデリングでは、ビジネスサイドを交えた上で、システムのユーザーのメンタルモデルをドメインモデル図に反映していくため、ビジネスサイドから、ドメインモデル図からかけ離れた突飛な要求が来ることが大幅に減る。
    • ex. 看護師のタスク管理システムにおいて、「ある病床ごとにタスクを作成できる」という仕様があったとする。そのとき、まず「病床」を登録し、その子要素として「タスク」を定義する仕組みが適当だとドメインモデル図に落とし込まれたとする。そうなった場合、「病床がなくても無くてもタスクを登録できるようにしてほしい」といった要望が来ることは基本的にはなくなる。
  • 業務知識に明るくないエンジニアが即席で設計を考えるよりも、ビジネスサイドの意見を取り入れることで、より業務に適した設計を生み出せることがある。
    • ex. タスク管理システムにおいて、タスクの「担当者」として、個人を指定するのではなく、グループも指定したいという仕様があったとする。そのとき、「担当者」という1つの概念によって個人もグループも制御することが考えられるが、ドメインモデリング中にビジネスサイドに聞いてみると、ユーザーとしては、「担当者」という1つの概念で制御しきるのではなく、「担当者」と「担当グループ」という2つの別概念で管理したいということが分かったとする。この場合、結果としてタスクに紐づく個人とグループを分けて管理できるようになり、より業務に適した構成になる。

3. ビジネスサイドがドメインモデルを通して、プロダクトの技術面を理解することができる。

  • 初期に最適だと判断したドメインモデルが、システムの成長や、ユーザー理解が進んだ末、最適ではなくなり技術負債となることがある。そんなとき、ドメインモデルを通して、ビジネスサイドとの共通認識が醸成できているため、負債解消にコストを割くことに対して、容易に理解を得ることができる。
    • ex. 2では来ないと言った「病床がなくても無くてもタスクを登録できるようにしてほしい」というような要望が、何かしらの要因で実際に来たとしても、システムの前提が変わったということが、ドメインモデル図上でも明確に意思統一できるため、その改修にかかるコストの説明がしやすくなる。

実際どのように運用してる?

では、理念の話はこれくらいにしておいて、実際の運用法について話していきます。
弊社では、下記のような手順でドメインモデリングを行っています。

①ユースケース図を作成する
②取り扱うユースケースを決める
③ユースケース記述を作成する
④ユビキタス言語を見つける
⑤ドメインモデル図を作成する
⑥実装する(おまけ)

①ユースケース図を作成する

ユースケースとは、「ユーザーを主語としたときに、システムを通して、どういったアクションを起こせるか」を表したものです。
まずは、機能開発において取り組みたいユースケースを羅列していきます。

(タスク管理システムの場合)

CRUDのようになることが多いと思います。

②取り扱うユースケースを決める

次に取り扱うユースケースを選択します。
一度に複数のユースケースの検討を進めると、情報量を整理しきれなくなるので、1つに絞るのが良いです。

どれに絞るかは悩むとは思いますが、私のこれまでの経験上、新規機能を開発するときには、まず作成ユースケースを見るのが良いと思います。
理由としては、削除や編集のユースケースを考えようとしても、作られていることが前提になるので、最初はとにかく対象が生成されるタイミングにフォーカスするのがおすすめです。

(タスク管理システムの場合)

③ユースケース記述を作成する

次にユースケース記述を書いていきます。
ユースケース記述とは「ユースケースについて、ユーザーとシステムを主語にして、それらの相互作用の詳細を文章にまとめたもの」です。

ユースケース記述についてより詳細な説明を知りたい方は、このスライドが非常にわかりやすいので是非ご覧になって下さい。
https://speakerdeck.com/j5ik2o/ddd-with-rdra-iconix?slide=36

(タスク管理システムの場合)

- ユーザーはタスク一覧ページへのリンクをクリックする。
- システムはタスク一覧を取得し、それらを表示する。
- ユーザーはタスク作成ボタンをクリックする。
- システムはタスク作成モーダルを開く。
- ユーザーはタイトルと詳細を入力して登録ボタンをクリックする。
- システムはタスクを保存する。

ユーザーとシステムを主語にして、目的語・述語を明確に示すことがポイントです。

「システムを主語にした部分まで本当に必要なのか?」と思うかもしれませんが、下記のような場合には、それがないとソフトウェアの重要な振る舞いが隠されてしまいます。

- ユーザーはタスク一覧ページへのリンクをクリックする。
- システムはタスク一覧を取得し、それらを表示する。
- ユーザーはタスク作成ボタンをクリックする。
- システムはタスク作成モーダルを開く。
- ユーザーはタイトルと詳細を入力して登録ボタンをクリックする。
- システムはタスクを保存する。
- その後、システムは検索システムへの保存処理を開始し、同期状態を処理中にする。
- システムはタスク一覧を取得し、それらを表示する。
- システムは検索システムへの保存処理が完了すれば、同期状態を処理済にする。

例えば、タスクを登録した後、全文検索を可能にするため、検索システムに非同期でインデックス処理を行うケースを想定してみます。
また、ユーザーに見える画面上で、同期状態を「処理中」・「処理済」といった具合で示すこともあるでしょう。(「処理済」になると、そのタスクが全文検索できるようになるイメージです。)
その場合、同期状態というものはシステムの重要な登場人物といえますが、もし、システムを主語にした書き方をしていないと、この部分がすっぽり抜け落ちてしまいます。

④ユビキタス言語を見つける

ユースケース記述を眺めてみると、システム特有の概念を含んだ単語がいくつか出てきているのが分かると思います。
それらをユビキタス言語候補として抽出します。

- ユーザーはタスク一覧ページへのリンクをクリックする。
- システムはタスク一覧を取得し、それらを表示する。
- ユーザーはタスク作成ボタンをクリックする。
- システムはタスク作成モーダルを開く。
- ユーザーはタイトルと詳細を入力して登録ボタンをクリックする。
- システムはタスクを保存する。
- システムは検索システムへの保存処理を開始し、同期状態を処理中にする。
- システムはタスク一覧を取得し、それらを表示する。
- システムは検索システムへの保存処理が完了すれば、同期状態を処理済にする。

このユースケース記述を例にとるとユビキタス言語候補は、下記のようになると思います。

  • タスク
  • 同期状態

ここからユビキタス言語候補を正式にユビキタス言語にしていくのですが、このフェーズでは、ビジネスサイドとエンジニアが積極的に意見を出し合って決めていきます。
そこで出てきたいくつかの言葉を、実際にユースケース記述の中に入れて、声に出して使ってみることで、違和感がないかを確かめていきます。
(いきなりユビキタス言語を決めにかかるより、ユースケース記述を使いながら決めていくことで、良いか悪いかの判断がやりやすくなります。)

その話し合いの結果が、次のようなものになります。

  • タスク
    →タスク(Task)としましょう。
  • 同期状態
    →同期状態(SearchableStatus)としましょう。

ここで同期状態という言葉を取り出しておかないと、ビジネスサイドとエンジニアの間で、「取り込み中の状況」とか「検索可能フラグ」とか、各々の理解に基づく言葉が飛び交い、認識のずれが起きやすくなります。

⑤ドメインモデル図を作成する

いざ、ドメインモデル図づくりです。
今でてきたユビキタス言語を○囲みして、クラス図のように、属性を書いて、線で結んでいきます。

ポイントをかいつまんで説明していきます。

  • ユビキタス言語の属性を書く

    • ユースケース記述を見ながら属性を埋めていきます。
    • 今回の場合はタイトル詳細がそれにあたります。
  • 関連性を表す線を結ぶ

    • クラス図を参考に、基本的には下記の2パターンと使って関係性を表していきます。
      • コンポジション

        • 例えば、Aが車でBがタイヤのような場合がこれに当てはまります。
      • 関連

        • 例えば、Aが社員でBが社員証のような場合がこれに当てはまります。
        • 関連は本来双方向性を持つが、矢印をつけることで、AからBに対して単方向に限定することができる。(この方向性のことを誘導可能性という。)
  • 吹き出しに仕様を書く

    • タスクの初期状態や、バリデーションなど、タスクにまつわるビジネスロジックを、存分に書いていきます。
    • ここで意思決定できない事柄は赤字などでメモしておきます。
    • あまり綺麗にまとめようなどとは思わず、気づいたことを積極的に書くのがコツです。
  • 多重度を書く

    • ドメインモデル間の関係として1対1なのか、1対多なのかなどを記載しておきます。

⑥実装する(おまけ)

⑤までがドメインモデリングの全貌です。

最後に、実際のサンプルコードのイメージを書いてみました。
パット見た感じ、ドメインモデル図と同じようなクラス構成になっていると思います。
(説明の簡素化のため、バリデーションなどは一切加えていません。)

class Task
  attr_reader :title, :description, :searchable_status

  def initialize(title, description, searchable_status=SearchableStatus::PROCESSING)
    @title = title
    @description = description
    @searchable_status = searchable_status
  end
end

class SearchableStatus
  PROCESSING = "processing"
  PROCESSED = "processed"
end

Q&A

ユビキタス言語がなかなか決まらず、毎度議論が難航します。どうすればよいか?

ユビキタス言語の策定は、時間をかけても意味がないことが多いということを念頭に置いたほうが良いと思います。
「ユビキタス言語が数案出たが、どうも決め手にかけるな」というときは、とりあえず、1つ決めて次に進むのがポイントです。
というのも、実際そのユビキタス言語を使ってコードを書いたり、コミュニケーションしてみたりして、違和感を探るほうがよっぽど効率的だからです。そこで違和感が出たら変えればいいのです。

ドメインモデリングの中で一貫して重要なのが、「このドメインモデリングで決めたすべての事柄は、あとから反証可能」というスタンスです。
実装途中に開発目線で見ると、どうしてもこのモデル図通りに実装すると、パフォーマンスが激重になるとか、技術的に不可能なことも実際出てきたりします。
はじめに決めたドメインモデルを厳格に維持しようとしすぎて、適切な判断ができないのは良くありません。そこは柔軟に考えましょう。

ユビキタス言語をスプレッドシート等で単語帳的に管理しているが、保守困難になっています。どうすればよいか?

スプレッドシートやエクセルで、単語帳的に管理するのではなく、ドメインモデル図を管理するのが良いかと思います。
僕も経験したのですが、単語帳的に管理している場合は、ユビキタス言語の変更や追加を行う必要があっても、実装時には後回しになってしまい、結果として修正漏れが頻発していました。
一方でドメインモデル図で管理している場合には、実装前にドメインモデル図上でエンジニア同士が実装の検討をやっているため、先にモデル図を更新した後、実装に移るという流れにできています。

またドメインモデル図を管理するツールとしては、diagrams.net(旧draw.io)を利用しています。

ドメインモデリングを実践してはいるが、ビジネスサイドを巻き込めていません。どうすればよいか?

よく質問いただくのですが、エンジニアの中で完結して集まることはできるのだが、ビジネスサイドは呼びづらいなという話ですね。
これについては、DDDといった言葉を全面に出すのではなく、まずは、エンジニアとビジネスサイドの間で起こるコミュニケーション上の翻訳作業や行き違いについて、解消していかないか?と持ち出すのが建設的かなと思います。

結局はDDDやドメインモデリングも手段でしかないので、それをやること自体が目的ではないということを念頭に置くと良いかと思います。

ドメインモデリングにビジネスサイドも参加してくれているが、ビジネスサイドが多忙になり、参加する時間が限られています。どうすればよいか?

弊社でもこういう場合はよくあります。
ただ時間が許す限り、はじめから最後までビジネスサイドにも参加してもらったほうが良いと思います。
というのも、ドメインモデリングは、参加メンバーがユーザーのメンタルモデルに触れ、製品理解を深める非常に良い機会であり、ここにユーザー理解の深いビジネスサイドが入ることで、その理解がより濃密なものとなるからです。

そうはいっても、時間が足りなかったり、予定が合わない場合は起こるので、そんなときは、全部参加してもらうのではなく一部だけ参加してもらうことで対処しています。

たとえば、弊社では、下記のような工夫をしています。
ビジネスサイドのドメインモデリングに対する理解度に合わせて、対応を変えていくのが良いかと思います。(下に行くほど、理解度が高い方向けになります。)

  • ユースケース記述は事前に用意しておく。
  • ユースケース記述と、ユビキタス言語の案までつくって、その使い心地を確認するところから入ってもらう。
  • ドメインモデル図まで書いてしまい、ドメインモデル図に吹き出しを付けて、ビジネスサイドに確認したいことを赤字でメモしておき、まとめて確認する。

現状の運用で何か課題に感じているところはあるか?

今ちょうど議論しているところは、デザイナーとの連携についてです。
現在の開発ワークフローは以下のようになっています。

先日、デザイナーにもドメインモデリングに参加してもらったら、「ドメインモデリングにおけるユースケース記述は、デザイナーも考えていることだから、連携できるといいね」というコメントをもらいました。

振り返ってみると、デザインはすでに固まっていたが、ドメインモデリングをしてドメインモデル図まで落とした結果(エンジニア目線も加わり)、ユースケース記述が変更され、デザインに手戻りが生じるということが過去にありました。

このことから、ユースケース記述の作成が終われば、ドメインモデリングを行い、ユースケース記述が適切だと判断された後に、デザインや実装のプロセスに移ることができれば良いのかもしれないと感じました。

ただ、まだまだ妄想段階なので、もしこのあたりはアップデートがあれば、別途記事にしていきたいと思います!

まとめ

ドメインモデリングに関しては、あまりまとまった情報も少なく、会社ごとに独自のやり方を構築しているところが多いのではないかと思います。
そんな中で、今回は、1年やってみてわかったドメインモデリングの型と題して、弊社の例を紹介しました。
(いろんな方のお話を聞かせていただいたり、議論させていただいてこの記事を書くことができました。本当にありがとうございます。)

ドメインモデリングをやっていると、毎回どうも再現性がないなという感覚があり、「どうにか型にまとめたい」とずっと感じていました。
最近は、本記事のように型化することによって、「社内で誰もがドメインモデリングができる」という状況を徐々に作れていると感じています。

もしこの記事を読んで、ドメインモデリングについて気になった方は是非気軽に聞きに来て下さい。お互いの課題や、やり方をシェアし合うことで私自身の解像度も上がるので!
https://hackermeshi.com/talk-themes/399

僕のTwitter(DM解放されています)や、Facebook Messengerに直接ご連絡いただくのもウェルカムです!🙌✨

InnoScouter(イノスカウター)Tech Blog

Discussion