ドメイン駆動設計で貧乏を爆殺する

本記事は [ドメイン駆動設計#1 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/ddd-1) 19日目の記事です。

こんにちは、レガシーコードを ~~爆殺~~ リファクタリングするのが大好きな[ミノ駆動](https://twitter.com/MinoDriven)です。

<img width=200, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/c50ddcbc-f630-d937-af13-797853eb1a5d.png">

今回はドメイン駆動設計導入上避けては通れない、大事な大事な**お金の話**を致します。

# 「ドメイン駆動設計を導入してみたいんです！」

<img width=300, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/57a3fbb3-f0a6-6823-61a8-66a60bc1ab86.png">

部下「ドメイン駆動設計を導入してみたいんです！」
上司「**それって何？なんのために導入するの？**」
部下「…………」

はい、僕にもそんな時代がありました。
**何のためにドメイン駆動設計を導入したいのか、簡潔に説明できますでしょうか。**

「ドメイン駆動設計」のタイトルにあるように、本書は設計に関する書籍です。
ソフトウェア全体の設計手法や思想に関して言及している書籍です。
まずはソフトウェアの価値とは何か、設計とは何か、それぞれ何かを整理してみます。

# ソフトウェアの価値

ソフトウェアが満たすべき要件は大きく分けて2つあります。
それは機能要件と非機能要件です。

- 機能要件：顧客が望んでいる機能があり、その機能が満たすべき要件。
- 非機能要件：可用性や拡張性、保守性など、機能以外の品質特性。

書籍[Clean Architecture](https://www.amazon.co.jp/dp/4048930656)でも、ソフトウェアの2大価値について語られています。
ひとつはソフトウェアそのものの振る舞い。ビジネス的な価値です。これは機能要件の側面です。
もうひとつは変更容易性。「ソフト」と名のつくように、ハードウェアと比べてすぐに変更できることが価値です。非機能要件的な側面です。

# 何のために設計するか

<img width=300, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/bd4d5d04-3c95-979e-7543-597bf713cd8a.png">

設計とは、**何らか課題の解決を意図して、仕組みや構造を作り上げること**です。

書籍[技術の創造と設計](https://www.amazon.co.jp/dp/4000052446)では、過去の大事故と失敗学を取り上げた上で「設計能力を高めるには、課題設定を早くせよ」とあります。

解決を要する課題があれば設計が必要ですし、逆にそもそも課題が存在しないか、もしくは無視できるほど軽微であれば設計不要です。

# ソフトウェア開発の課題

ソフトウェアには機能要件と非機能要件があります。これら要件を正しく満たすことで価値が向上します。ただし、要件を満たすには様々な課題があります。
ここでは書籍「Clean Architecture」で言及されている2大価値、ビジネス価値と変更容易性を向上させる上での課題を考えてみましょう。

## ビジネス価値の課題

<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/ed40695c-ef69-eae8-7ace-9609977b3a4b.png">

顧客が本当に望んでいるものを見抜き、システム化することで、顧客の役に立つ、売れるソフトウェアになります。
しかし顧客の要望を上手く汲み取れなかったり、よく分からないままシステム化すると、**折角作ったものが売れなくなってしまいます。収益が入らなくなります。**

## 変更容易性の課題

低コストでバカ売れするものが作れれば願ったり叶ったりでです。
開発コストが低いほど、トータルの収益が伸びます。
ソフトウェア開発では、簡単に素早く正確にコード変更できるほど開発コストが低減します。

<img width=300, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/f7fa51e5-0568-de2c-1113-b4061d333fb1.png">

しかし巨大で複雑でスパゲッティなコードは理解が難しく、少し変更しただけでバグ化してしまい、変更が困難です。
いつまで経っても変更できず、無駄にリリースが先延ばしになる…。そうこうしている間にも会社側は従業員に給料を払い、オフィスの賃料を払い、その他各種経費を支払わなければならず、開発コストが増大してしまいます。

仮にサービスが収益を上げたとしても、**莫大な開発コストにより儲けが出なくなってしまいます**。バケツの底に穴が空いているようなものです。

### 国家規模の巨大経済損失

メンテナンスや変更が困難なコードをレガシーコードと呼びます。
[老朽化ソフトウェアの技術的な負債、毎年１２兆円の衝撃](https://comemo.nikkei.com/n/n1ce83fa154e5) によると、レガシーコードによる経済的損失は、毎年オリンピック数回規模になるとの衝撃的な予測が述べられています。
多くのソフトウェアで変更容易性が低下し、国家規模での損失が問題視されています。
本件に伴う課題分析については広木大地氏の ["技術的負債"論の道案内 - アーキテクチャの資本コストと情報の非対称性](https://qiita.com/hirokidaichi/items/c66682a64ac2fc59cdf3) をご参照下さい。


# ドメイン駆動設計が解決したい課題とは

ドメイン駆動設計が解決したいのはビジネス価値と変更容易性の向上を妨げる課題。
これらの課題を解決するための設計手法や設計思想に関して大半の記述が割かれています。

<img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/41bac059-0bbd-d389-99c4-4b51a2330134.png"><img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/2e8399c5-1b96-183d-785a-38e89ee72ec6.png">

ビジネス価値と変更容易性。これら2つは**お金に直結する要素**です。
つまりドメイン駆動設計は**貧乏を脱し、利益を最大化するための設計**であると私は考えます。

以下は、DDD本書記載内容の内一部に関して、**お金を観点とした効果**で解説します。
設計方法等詳細はDDD本書や他のDDD関連の記事をご覧下さい。

# 変更容易性

変更容易性向上による変更コストの低減、即ちマイナスを減らす効果を説明します。

## 【注意】すぐに効果は現れない　-ソフトウェアの寿命を考慮する-

変更容易性の向上は、保守や仕様変更時に素早くコードを理解できる、素早く変更できる形で保守コスト、変更コスト低減効果が現れます。
つまり**経時変化があるほど効果がある一方、瞬間的な効果はほとんど現れません**。むしろ設計コストがかさむ点に留意しなければなりません。

これは極めて重大な事柄なのですが、アーキテクチャは「なんらかの品質特性を意図して促進するための設計構造」です。殊に変更容易性を促進するアーキテクチャの目的は、「**ソフトウェアのライフサイクル全体を通じて開発生産性を最大化する**」と言い替えられます。

<img width=300, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/f860c8bd-14ff-cf58-edbe-06ce2dfeafe7.png">

つまり、**寿命が長く、頻繁に変更されるソフトウェア**ほど変更容易性向上の設計が効果を発揮し、逆にプロトタイプ品のような作ってすぐ捨てられるものは設計しても意味がないばかりか逆に設計コストが高くつきます。DDD導入の際はソフトウェアの寿命がどれぐらいか、コストをかけるのに見合ったリターンが得られるかどうかを考慮する必要があります。

## ユビキタス言語

【解決したい課題】
同じ内容の話なのに、ビジネス側とエンジニア側とで使う言葉が違うことがよくあります。

<img width=200, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/f01f23c7-14ce-f62b-3647-95eb81982a9e.png">

特にエンジニアさんは技術寄りの言葉で話すことが多いです。
ビジネス側「今開発されている予約機能についてですが…」
エンジニア側「ああ、▲▲モジュールのことですね」
ビジネス側「…？？」

ソースコード上のクラスやメソッドの名前も技術寄りの名前になり、ビジネス側の言葉と乖離してしまいます。意思伝達効率や正確性が低下し、開発成果物が正しく作られなかったり、開発速度そのものが低下します。つまり**開発コストが増えます**。

【効果】
全員が意思共有可能な同じ言葉を用い、更にソースコード上の名前もその言葉に揃えることで、ビジネス側とエンジニア側とで意思伝達効率や正確性が向上します。ビジネス側が変更したい機能を、ソースコード上ですぐ追跡できるため、開発の速度や正確性が向上します。即ち**開発コストダウンを狙えます**。
下記に示す設計パターンのクラスも、ユビキタス言語で命名します。

## ValueObject

【解決したい課題】
値に関連のあるロジックの低凝集。
保守や仕様変更時に関連コードを探し回る時間が増えます。つまり**開発コストが増えます**。

【効果】
税込金額、氏名、身長など、各値それぞれをクラスで表現します。例えば消費税計算ロジックを税込金額クラスにカプセル化するなど、関連ロジックを凝集することでコードを探し回る時間が低減し、**開発コストダウンを狙えます**。

## Repository

【解決したい課題】
業務ロジックと永続化ロジックの密結合。
SQLなどDBアクセスロジックが業務ロジックと絡み合ってしまうと、アプリとして何をやりたいのか混乱し、理解容易性低下します。正確な理解に時間がかかり、つまり**開発コストが増えます**。

【効果】
永続化ロジックをRepository内にカプセル化し他と隔離することで、混乱を低減できます。理解容易性が向上します。**開発コストダウンを狙えます**。(※トランザクション設計の効率向上、正確性向上も)


## 境界付けられたコンテキスト

【解決したい課題】
似て非なる様々なモデルをたったひとつのクラスで実装してしまう弊害。
アプリが大きくなってくると、ひとつのクラスが様々な意味を持ち始め、巨大化します。様々な意味を持っているために、開発者は混乱します。開発者同士の意思疎通効率、正確性が低下したり、バグを生み出したりします。正確にコード変更できるまでの**開発コストが増大します**。

【効果】
例えば同じ商品でも、出品時、注文時、配送時それぞれで付いて回るロジックや情報が異なります。状況(コンテキスト)ごとに商品を別々のモデルで表現し、別々のクラスで実装することで、似て非なるもの同士を隔離できます。
理解容易性が向上し、コード変更の正確性も向上します。即ち**開発コストダウンを狙えます**。(※更にマイクロサービス化への検討も可能になる)

# ビジネス価値

ビジネス価値向上、即ち顧客に訴求し、収益を上げる、プラスの効果について説明します。

## ユビキタス言語

【解決したい課題】
折角開発したシステムが、ビジネス側の想定したものになっていないことがあります。商売の狙い所として間違いないはずが、システムの作りが良くないために、顧客にサービスを使って貰えず、**利益が出なくなります**。

【効果】
エンジニア側、殊にアーキテクトは、ビジネス要求を適切にシステムに落とし込む責務があります。つまり、ビジネスを理解してないと良いシステムは作れません。ビジネスとして何を達成したいのかユビキタス言語を使ってビジネス側とよく議論を重ね、ビジネス要求を達成するシステムを作り込むことで**利益が最大化します**。

## コアドメイン

【解決したい課題】
コストをかけて開発した機能なのに、ほとんどあまり顧客に訴求しないことがあります。サービスを使って貰えず、**利益が出ません**。

【効果】
一節によると、ソフトウェアの機能の内、よく使われるものは1/3ほどで、残り2/3はほとんどあまり使われないそうです。あまり使われない機能を頑張って作っても利益は出ません。開発予算には限りがあります。ソフトウェアの価値や魅力を高めるには、コアとなる機能に開発リソースを集中することが肝要です。
ビジネス側とエンジニア側とでユビキタス言語で議論し、本当に集中すべき課題領域、即ちコアドメインを分析します。コアドメインを解決するようシステム化することで魅力的なサービスになり、**利益が出るようになります**。

【補足（※だけどとても重要）】
勘の良い方は既にお気づきかも知れませんが、このコアドメインをシステム化した部分に関して変更容易性を高める設計を施すことにより、一層変更コスト低減効果が現れます。コア以外の設計が多少悪くても、コアに集中的に設計投資して利益を最大化することが肝要です。

# ドメイン駆動設計の導入に必要なこと

では改めて、お金を軸として、ドメイン駆動設計の導入に必要な事柄について、私の意見を述べます。

## DDDを学ぶ

まずは導入のモチベーションのある方がDDDを理解する必要があります。

### お金を意識してDDDを読む

まだDDDを読んだことがない方、または読んだけど良く分からなかった方は、本記事で挙げたようにお金を意識して読むと良いでしょう。「この設計パターンは変更コスト低減にどのように作用するのか」「ビジネス価値向上にはどの考え方が役立ちそうか」など意識して読みましょう。

### 【重要】実際手を動かしてみる

そうは言ってもDDDは難解で、読んだだけで設計実装力は向上しません。読んだ内容を咀嚼し試行錯誤しながら、実際に設計実装してみて初めて**変更コスト低減を肌感覚で体感できます**。インプット：アウトプット＝３：７ぐらいの意識で手を動かしましょう。

何を題材に設計実装していいか分からない場合は、仕事で扱っているプロダクトコードで試してみるのをオススメします。プログラミング入門書に記載されているようなコードはシンプルすぎて練習になりません。実際のプロダクトコードこそ複雑で泥臭くて、DDDの設計実装練習には最適です。
ちなみに私は**製品コードのリポジトリに練習用のブランチを作り、裏でコソコソ練習をしていました**。

まずはValueObjectパターンから練習してみるのが良いでしょう。
[私が執筆したValueObject記事](https://qiita.com/MinoDriven/items/5e69d9bd028aa350e2c4)をご参考にどうぞ。

また、増田亨氏の[現場で役立つシステム設計の原則](https://www.amazon.co.jp/dp/B073GSDBGT)もオススメです。ValueObjectを筆頭とする設計パターンについて極めて平易な言葉で解説しており、DDD入門にはうってつけです。

## DDD導入の価値があるか検討する

冒頭でも述べたように、設計とは課題を解決するためにあります。そもそも課題がなければ導入する意味がありません。導入価値があるかどうか評価してみましょう。

- コードを読むのがしんどい、時間がかかる
- 今作ってるのが何の役に立つのか分からない
- コード修正するとしょっちゅうバグる
- この先何年もバージョンアップや保守の計画がある

…などを満たすようであれば導入の価値ありと考えて良いでしょう。

## DDD導入の話を切り出す

ある程度DDDの理解が深まったならば、チームに導入の話をしてみましょう。

### コスト面の課題を相談してみる

チームメンバーや上司とコストについて相談してみましょう。
まずは上記「DDD導入の価値があるか検討する」で列挙した事柄、コードを読むのが辛いかどうかや、何を作ってるのかよく分からないなど課題感を感じてるかどうか尋ねてみましょう。
開発費が高騰してないか上司に思い切って聞いてみるのもいいでしょう。

### お金を解決する設計手法が存在することを切り出す

<img width=250, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/83a48d15-4a14-0c4e-c63b-329fd68a0c65.png">

もしチームで課題感を共有できたならば、DDD導入の話を切り出してみましょう。
そして本記事のように、変更コストを低減し、ビジネス価値を高め、利益を最大化する設計手法があることを話してみましょう。

ちなみに**いきなり「ドメイン駆動設計」の単語を出すと拒絶反応される可能性が高いためオススメしません。**
私自身痛い目に遭ったことがあるので、「ドメイン駆動設計」の単語を出さず、変更コストとそれを解決する設計だけに注力して説明し、コソッと導入した経験があります。

### コストを正直に話す

ドメイン駆動設計に限ったことではないですが、設計は全般的にコストがかかります(学習コスト、設計業務そのもののコスト)。特にドメイン駆動設計は学習コストが高いです。

「こんなはずではなかった」「コストがかかるなんて聞いてなかった」
**合意なき期待**は双方の不信感を生み、チーム瓦解の引き金になりかねません。
コストのメリット、デメリットを正直に相談しましょう。

### 効果が出るまで時間がかかることを話す

変更容易性の項目でも書きましたが、設計は保守や仕様変更時に初めて効果を現し始め、経時変化による持続的効果をもたらすものです。
サービスのEOLはいつ頃か、コスト的にペイできるか、トータルコストのバランスをチームや上司と話し合ってみましょう。

### 巨大経済損失の記事で脅す

<img width=300, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/59cc7d25-9fe1-d5fa-78cf-1d6a5ec9aca2.png">

チームメンバーがイマイチ納得してないようでしたら、冒頭で挙げた [老朽化ソフトウェアの技術的な負債、毎年１２兆円の衝撃](https://comemo.nikkei.com/n/n1ce83fa154e5) や、 ["技術的負債"論の道案内 - アーキテクチャの資本コストと情報の非対称性](https://qiita.com/hirokidaichi/items/c66682a64ac2fc59cdf3) を見せて脅してみましょう。

## それでもダメなら…

<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/46fa89c7-31d0-ab38-ab44-4480dda45f6b.png">
<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/93b8c410-b753-4d91-369c-9a60b39ca9ae.png">
<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/7212087d-5bd6-3448-1701-476bda2730d9.png">
<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/ebe12c1c-2bf8-5037-878e-b47debdf0cda.png">
<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/b69d0741-45bd-9b3e-d4fc-677e85259721.png">
<img width=500, src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/393000/c9d4ab8f-b1c1-3075-3658-2dff742daf30.png">

おしまい★

(素材：BIT/O氏 [リニューアルぶらっくかんぱにー](https://bit-orchard.hatenablog.com/entry/sozai/blackcompany2019))