lvncerpedia

Domain Driven Design

そもそもドメイン駆動設計(DDD)って何?

「 ソフトウェアで解決したいこと(=ドメイン)を中心に考えて設計するやり方 」。

普通の開発だと、データベースのテーブル構造とか、画面のデザインとか、技術的なことから考え始めちゃうことがあるんだよね。 「 そもそもこのシステムって、誰のどんな問題を解決するんだっけ?*」っていう、ビジネスのルールや課題そのものを一番大事にするんだ。

例え話で考えてみよう!

DDD を理解するために、「カフェの注文管理システム」を作るって想像してみて!

登場人物

  • ドメイン(Domain): ソフトウェアで解決したい問題領域。今回の場合は「カフェの運営」
  • ドメインエキスパート(Domain Expert): その道のプロ。つまり、カフェの店長さんやベテラン店員さんのこと。注文の受け方、割引のルール、在庫管理とか、ビジネスのことに一番詳しい人たち。
  • 開発者: 私たちエンジニアのこと

DDD の重要な考え方

DDD にはいくつか大事な考え方があるんだけど、特にこの 2 つがキモなんだ!

1. ユビキタス言語 (Ubiquitous Language)

「みんなで使う共通言語」

開発者とドメインエキスパート(店長さん)が、会話で使う言葉とコードで使う言葉を完全に一致させるのが大事なの。

ダメな例

店長さん: 「お客さんが商品を注文したら、伝票をキッチンに回して…」

開発者: (ふむふむ、users テーブルのレコードが items を order したら、slips テーブルにデータ作る感じかな…?)

これだと、会話の言葉(商品、注文、伝票)とコードの言葉(user, item, order, slip)が微妙に違ってて、だんだん会話が噛み合わなくなっちゃうリスクがあるんだよね

良い例 👍

みんなで会議して、言葉を統一する。

「注文のことは、これからは必ず『オーダー』と呼びましょう」 「注文された個々の商品のことは『オーダー品目』にしましょう」 「お客さんのことは『顧客』と呼びましょう」

こうやって決めた「ユビキタス言語」を、会話でも、設計書でも、そしてソースコードのクラス名や変数名でも徹底して使うんだ。

ユビキタス言語の「オーダー」をそのままクラス名にする

class Order < ApplicationRecord

「顧客」がいて、「オーダー品目」がたくさんある、というビジネスルールをコードで表現

belongs_to :customer
has_many :order_items

こうすることで、エンジニアじゃない店長さんがコードを見ても、なんとなく何をしてるか想像しやすくなるし、認識のズレが劇的に減るんだよ

2. モデル (Model)

これは、ユビキタス言語を使って表現された「ビジネスルールの塊(かたまり)」のこと。

さっきのカフェの例で言うと、「オーダー」っていう概念には、色々なルールがくっついてくるよね。 合計金額は、オーダー品目の合計である。 テイクアウトの場合、消費税が 8% になる。 セット割引を適用できる。 こういう複雑なルールや知識を、データとロジック(処理)をセットにして表現したものが「モデル」なんだ。

Ruby on Rails と DDD の関係

「あれ?Rails の app/models もモデルって言うよね?」って思った? その通り!

Rails のアーキテクチャは、実は DDD の考え方にすごく影響を受けてるんだ。 でも、Rails のデフォルトのやり方だけだと、ちょっと困ったことが起きやすいの。

Rails でよくある悩み:「Fat Model」問題

Rails は Active Record っていうパターンを採用してるから、app/models にあるモデル(User とか Post とか)が、データベースとのやり取りも、ビジネスロジックも、バリデーションも…って、色々な仕事をやりがち。 アプリが小さいうちはいいんだけど、大きくなってくると、1 つのモデルファイルが数千行にもなって、何が何だか分からなくなる…

これが Fat Model(太ったモデル) 問題!

そこで DDD の出番!

DDD の「関心事の分離(役割ごとにファイルを分ける)」っていう考え方を使って、この Fat Model を解消するんだ! 例えば、app ディレクトリの下に、新しくディレクトリを作って役割を分担させる感じ。

  • app/services/

    複数のモデルをまたぐような、複雑なビジネス処理を担当する専門家を置く場所。 例: UserRegistrationService(ユーザー登録に関わる色々な処理をまとめる)

  • app/forms/

    ユーザーが入力したデータのバリデーションだけを担当する専門家を置く場所。 例: SignUpForm(サインアップ画面の入力チェックだけやる)

こんな風に、Order モデルが全部やるんじゃなくて、「オーダーを登録する専門家」「オーダーの金額を計算する専門家」みたいに、役割分担させてあげるんだ。 こうすることで、一つ一つのクラスはスリムで分かりやすくなるし、変更も楽になるんだよね!

まとめ

DDD は、ビジネスのルール(ドメイン)が主役の設計思想だよ! 「ユビキタス言語」っていう共通言語で、みんなの認識を合わせるのが超大事! Rails の Fat Model 問題を解決するのに、DDD の考え方がすごく役立つよ! DDD は結構奥が深くて難しいんだけど、「ビジネスの関心事をコードの中心に置く」「役割ごとにちゃんとファイルを分ける」っていう意識を持つだけでも、コードの綺麗さが全然違ってくると思う!