Object-Oriented Conference 2020
DDDはオブジェクト指向を利用して
どのようにメンテナブルなコードを書くか
2020.2.16
松岡 幸一郎 (@little_hand_s)
1
自己紹介
● 松岡 幸一郎 (@little_hand_s)
● DDD community jp主催
● DDD周りの話をするブログ書いてます
● 技術書典8で「ドメイン駆動設計 モデリング/実装ガイド」発売予定
2
質問受け付けます
● app.sli.doにアクセス
● codeに「ooc_matsuoka」を入力
● 質問を追加 or 既存の質問に投票
3
今日お話しすること
4
今日話したいこと
DDDとオブジェクト指向の関係は?
5
今日話したいこと
DDDとオブジェクト指向の関係は?
そもそもDDDって何?
軽量DDDと、そうでないものは何が違うの?
6
DDDとは
● DDDとは
DDDとは
● DDDとは
抽象的にいうと「ソフトウェア開発手法の一つ」である
● そもそも、ソフトウェアはなんのために作るのか?
● ソフトウェアを適用する対象の何らかの問題を解決するため
● この「ソフトウェアで問題解決しようとする対象」を「ドメイン」と呼ぶ
● DDD:
DomainDrivenDesign(ドメイン駆動設計)の略
● DDD Referenceより
"多くのプロジェクトは、モデリングを行っても
最終的に大きな利益を得られないまま終わります。
DDDは、モデリングから劇的な利益を得られたプロジェクトから、
成功するパターンを抽出します。”
(注:DDD Reference)
DomainLanguage.comにあるDDDのエッセンスの要約版
Evans本よりだいぶまとまっているので、定義などに迷ったらまずこちらを参考に
● DDD:
DomainDrivenDesign(ドメイン駆動設計)の略
● DDD Referenceより
"多くのプロジェクトは、モデリングを行っても
最終的に大きな利益を得られないまま終わります。
DDDは、モデリングから劇的な利益を得られたプロジェクトから、
成功するパターンを抽出します。”
● DDDは
「ドメインモデリングによってソフトウェアの価値を高める」
ことを目指す。
あれ?
あれ?
アーキテクチャ、コード品質の話が出てこない?
「コード品質を上げること」を目的としてDDDを導入検討されることが多いですが
DDDの目的はコード品質のさらに先にあるのです
では、コード品質との関係はどうなるのか?
今日はそのつながりも含んだ全体像を示します。
● 「モデル」とはなんでしょうか?
モデルって何?
モデルとは?に対する様々な答え
● DBA
「DBのテーブルのこと」
21
● DBA
「DBのテーブルのこと」
● サーバーサイドエンジニア
「テーブルに対応したオブジェクトのこと」
モデルとは?に対する様々な答え
22
モデルとは?に対する様々な答え
● DBA
「DBのテーブルのこと」
● サーバーサイドエンジニア
「テーブルに対応したオブジェクトのこと」
● 機械学習エンジニア
「数式のこと」
23
モデルとは?
● 「モデル」という言葉は文脈によって大きく違う使われ方をする
● 言葉の定義をしましょう
● model:
A system of abstractions that describes selected aspects of a domain and can
be used to solve problems related to that domain
● モデル:問題解決のために、物事の特定の側面を抽象化したもの
DDD文脈での定義
ざっくり意訳
25
モデルの区別
● ドメインモデル:
● データモデル:
26
モデルの区別
● ドメインモデル:
ドメインの問題を解決するためのモデル
● データモデル:
27
モデルの区別
● ドメインモデル:
ドメインの問題を解決するためのモデル
● データモデル:
データベースに何かを永続化するためのモデル
28
モデルの区別
● ドメインモデル:
ドメインの問題を解決するためのモデル
● データモデル:
データベースに何かを永続化するためのモデル
→ これらは別のものであり、明確に区別する必要がある
29
● モデル:問題解決のために、物事の特定の側面を抽象化したもの
→ 抽象化とは何でしょうか?
DDD文脈での定義
30
例:履歴書
例:履歴書 現実には数多くの要素がある
・名前、経歴、志望理由
・写真
例:履歴書 現実には数多くの要素がある
・名前、経歴、志望理由
・写真
・筆跡、筆圧
・紙質、折れ具合
例:履歴書 現実には数多くの要素がある
・名前、経歴、志望理由
・写真
・筆跡、筆圧
・紙質、折れ具合
・履歴書のメーカー
・履歴書の値段
・履歴書を書いた時の気持ち
・:
現実世界の全ての要素をソフトウェアに落とし込むことは不可能
現実世界の全ての要素をソフトウェアに落とし込むことは不可能
→ 必要な要素はモデルに取り込みたい
→ 不要な要素はモデルに取り込みたくない
現実世界の全ての要素をソフトウェアに落とし込むことは不可能
→ 必要な要素はモデルに取り込みたい
→ 不要な要素はモデルに取り込みたくない
この選択が「抽象化」
● 良いモデルとは何か?
● 良いモデルとは何か?
わかりやすいモデル、現実に即しているモデル、拡張性のあるモデル…
● 良いモデルとは何か?
わかりやすいモデル、現実に即しているモデル、拡張性のあるモデル…
→問題解決ができるモデル
● 良いモデルとは何か?
わかりやすいモデル、現実に即しているモデル、拡張性のあるモデル…
→問題解決ができるモデル
● 良くないモデルとは何か?
● 良いモデルとは何か?
わかりやすいモデル、現実に即しているモデル、拡張性のあるモデル…
→問題解決ができるモデル
● 良くないモデルとは何か?
→問題解決ができないモデル
○ 現実に即していない
○ やりたいことができない
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
書類選考の前に面談
があるのに・・・
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
書類選考の前に面談
があるのに・・・
面接は3次、4次もある
のに・・・
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
書類選考の前に面談
があるのに・・・
面接は3次、4次もある
のに・・・
求人関係ない応募も
許可したい・・・
● 中途採用における「採用進捗」
現実世界(ドメイン) モデル
書類選考の前に面談
があるのに・・・
面接は3次、4次もある
のに・・・
求人関係ない応募も
許可したい・・・
運用で
カバー
技術の敗北感がある
モデルが良くなくて問題解決できない
運用でカバーできればまだマシ、
売れなければプロダクトがなくなる
● もしも、このソフトウェアが
● もしも、このソフトウェアが
● DDDの実装パターンを的確に使っている
● コードの可読性、拡張性が完璧
● テストも完璧で、バグが全くでない
● もしも、このソフトウェアが
● DDDの実装パターンを的確に使っている
● コードの可読性、拡張性が完璧
● テストも完璧で、バグが全くでない
 ものだったとしたら、高い価値を生み出せるか?
● もしも、このソフトウェアが
● DDDの実装パターンを的確に使っている
● コードの可読性、拡張性が完璧
● テストも完璧で、バグが全くでない
 ものだったとしたら、高い価値を生み出せるか?
→ NO!!
● モデルがイケてないと、
その後の実装がどんなに素晴らしくても良いソフトウェアにはならない
● 良いモデルを作るにはどうすれば良いか?
● 良いモデルを作るにはどうすれば良いか?
→ドメインに詳しい人から知識を得る
● 良いモデルを作るにはどうすれば良いか?
→ドメインに詳しい人から知識を得る
→運用した知見をモデルにフィードバックして改善する
● 良いモデルを作るにはどうすれば良いか?
→ドメインに詳しい人から知識を得る
→運用した知見をモデルにフィードバックして改善する
→モデルは最初から完成しない、改善していくもの
 (DDDとして重要なスタンス)
● モデルは最初から完成しない、改善していくもの
モデル コード
● モデルは最初から完成しない、改善していくもの
モデル コード
● コードとモデルが乖離すると…
モデル コード
● コードとモデルが乖離すると…
○ モデルの更新をコードに正しく反映できているかわからなくなる
モデル コード
● コードとモデルが乖離すると…
○ モデルの更新をコードに正しく反映できているかわからなくなる
○ モデルからコードを理解しにくくなる
モデル コード
● モデルの更新をコードに正しく反映できているかわからない
● コードからモデルを理解しにくい
モデルとコードが乖離すると発生する問題
● モデルの更新をコードに正しく反映できているかわからない
→意図していない実装(=バグ)を産みやすくなる
● コードからモデルを理解しにくい
モデルとコードが乖離すると発生する問題
● モデルの更新をコードに正しく反映できているかわからない
→意図していない実装(=バグ)を産みやすくなる
● コードからモデルを理解しにくい
→ドメインに対する理解もできない
→モデルは改善されない
→ソフトウェアの価値を高めにくくなる
モデルとコードが乖離すると発生する問題
● コードとモデルが乖離すると問題が発生する
● モデルは継続的に改善したい
問題と対策
● コードとモデルが乖離すると問題が発生する
→モデルそのまま表現したコードとなるのが望ましい
● モデルは継続的に改善したい
問題と対策
● コードとモデルが乖離すると問題が発生する
→モデルそのまま表現したコードとなるのが望ましい
→「オブジェクト」でモデルを表現する
● モデルは継続的に改善したい
問題と対策
● コードとモデルが乖離すると問題が発生する
→モデルそのまま表現したコードとなるのが望ましい
→「オブジェクト」でモデルを表現する
● モデルは継続的に改善したい
→コードにも継続的に反映しないと行けない
→頻繁な変更に耐えうるには、拡張性の高い設計が必要
問題と対策
● コードとモデルが乖離すると問題が発生する
→モデルそのまま表現したコードとなるのが望ましい
→「オブジェクト」でモデルを表現する
● モデルは継続的に改善したい
→コードにも継続的に反映しないと行けない
→頻繁な変更に耐えうるには、拡張性の高い設計が必要
→これはソフトウェアとしては非常に高い要求
問題と対策
● コードとモデルが乖離すると問題が発生する
→モデルそのまま表現したコードとなるのが望ましい
→「オブジェクト」でモデルを表現する
● モデルは継続的に改善したい
→コードにも継続的に反映しないと行けない
→頻繁な変更に耐えうるには、拡張性の高い設計が必要
→これはソフトウェアとしては非常に高い要求
→そこで生まれたのがEntityやRepositoryなどのデザインパターン
問題と対策
● 軽量DDD:DDDの実装パターンだけ取り入れること
軽量DDDとは
● 軽量DDD:DDDの実装パターンだけ取り入れること
● 拡張性の高いベストプラクティスを取り入れる
→それだけでも十分価値がある
軽量DDDとは
● 軽量DDD:DDDの実装パターンだけ取り入れること
● 拡張性の高いベストプラクティスを取り入れる
→それだけでも十分価値がある
● コード品質をあげると、ようやくモデリングする余地が生まれる
と考えることもできる
軽量DDDとは
● 軽量DDD:DDDの実装パターンだけ取り入れること
● 拡張性の高いベストプラクティスを取り入れる
→それだけでも十分価値がある
● コード品質をあげると、ようやくモデリングする余地が生まれる
と考えることもできる
● 何の問題もない、
そこからモデリングに踏み出しましょう
軽量DDDとは
DDDのアプローチ
DDDのアプローチの全体像
DDDのアプローチ
モデルがイケてないと、
実装がどんなに素晴らしくても良いソフトウェアにはならない
DDDのアプローチ
モデルを継続的にソフトウェアに反映するために拡張性の高い設計をする
どうやってモデリングするのか
82
ドメインモデリングの方法
● 一つに決まった方法はない
○ 体系化された手法の例
■ リレーションシップ駆動要件分析(RDRA)
■ ユースケース駆動分析設計
● シンプルな例をご紹介
ユースケース図 / ドメインモデル図によるモデリング
● タスク管理アプリケーションにおける事例で説明する
83
ユースケース図
● ユーザーとアプリケーションの相互作用を定義する
● 一般的なUMLのものと同じ
84
ユースケース図
● ユーザーとアプリケーションの相互作用を定義する
● 一般的なUMLのものと同じ
85
ユースケース図
● ユーザーとアプリケーションの相互作用を定義する
● 一般的なUMLのものと同じ
● 次に続くドメイン図作成の範囲も決める
今回のモデリングのス
コープ
86
● ユースケースの具体化・言語化
○
● ドメインモデル図作成作業の範囲を狭める
○
ユースケース図を作る必要性
87
● ユースケースの具体化・言語化
○ 具体化しないと、どのようなモデルを作ればいいかわからない
○ 「いち作業者として、自分のタスクを管理したい」のか
「管理者として、複数作業者のタスク状況を管理したい」のか
それによって「タスク」のドメインモデルは違うものになる
● ドメインモデル図作成作業の範囲を狭める
○
ユースケース図を作る必要性
88
● ユースケースの具体化・言語化
○ 具体化しないと、どのようなモデルを作ればいいかわからない
○ 「いち作業者として、自分のタスクを管理したい」のか
「管理者として、複数作業者のタスク状況を管理したい」のか
それによって「タスク」のドメインモデルは違うものになる
● ドメインモデル図作成作業の範囲を狭める
○ ドメインモデル図作成をしていると、いろんな要素が思い浮かんでくる
○ 範囲を限定して、限られた時間でまとまった成果を出せるようにする
ユースケース図を作る必要性
89
ドメインモデル図
● クラス図の簡易版
● メソッド(振る舞い)は不要
● 属性も代表的なものだけでOK
● 業務の「ルール・制約」(=ドメイン知識) を吹き出しで記述する
● 集約の範囲を明記する
90
集約について
● 集約=「必ず守りたい強い整合性を持ったオブジェクトのまとまり」
● 必ずまとめて取得して、まとめて更新する単位
● 今回の発表では集約の検討が必要な事例は示せないが、
「このタイミングで集約設計する」ということを覚えておいてください
91
実際のモデリング
● 最初はホワイトボードに殴り書きでOK
92
ドメインモデル図
93
どうやってコードに落とすか
94
まず、形から入る
● レイヤーを定義して「このレイヤにはこういうクラスを作る」というのを決める
● その決まりの上で、とりあえず動くものを書く
● 参考:新卒にも伝わるドメイン駆動設計のアーキテクチャ説明
95
● 改善余地があるコードから入り、リファクタリングしていきます
説明の流れ
96
● この段階では属性の定義のみ、ドメイン知識は持っていない
Taskクラス
97
TaskApplicationSericeクラス -タスクを登録する
● ApplicationServiceクラスにタスク登録時の処理を書く
98
● 延期時の処理も同様
TaskApplicationSericeクラス -タスクを延期する
99
このコードの問題点
● 不整合なデータをいくらでも作れる
● 仕様を追いかけるのに、複数クラスをコード参照から追っていくしかない
100
ドメインモデル図の見直し
● ドメインモデル図の吹き出しの知識はどのクラスに書かれているか?
101
TaskApplicationSericeクラス -タスクを登録する
タスクは未完了状態で作成
される
102
TaskApplicationSericeクラス -タスクを延期する
タスクは3回だけ、
1日ずつ延期することができる。
103
● ドメインモデル図の知識がApplication層のクラスに書かれている
タスクは未完了状態で作成
される
タスクは3回だけ、
1日ずつ延期することができる。
104
● ドメインモデル図の知識をDomain層のクラス、
特に吹き出しが書かれたオブジェクトに委譲する
タスクは未完了状態で作成
される
タスクは3回だけ、
1日ずつ延期することができる。 105
● 修正前のクラスを再度確認
● このクラスに、吹き出しの知識を委譲する
Taskクラス -Before
106
Taskクラス -After (1/3) コンストラクタ
● コンストラクタにタスク作成時の知識を移譲
タスクは未完了状態で作成
される
107
Taskクラス -After (2/3) 延期メソッド
● 延期メソッドに延期時の知識を移譲
タスクは3回だけ、
1日ずつ延期することができる。
108
Taskクラス -After (3/3) Setter
● Setterがなくなっているので、公開しているメソッド以外で操作できない
109
シンプルになったApplicationServiceクラス
● ユースケース記述レベルの抽象度の高いコードのみ残る
110
この設計のメリット(1/3)
● 不整合なデータを作れないように強制できる
○ Setter非公開にしたので不整合な値をセットできない
コンパイルエラーになる
111
この設計のメリット(2/3)
● 他のルールで生成・更新
されないことが確実になっている
● 1クラスに吹き出しの知識が
凝縮されている
→「このクラスだけ見れば良い」
という大きな安心感を得られる
112
この設計のメリット(3/3)
● レイヤーによって書くべきことが決まっている
→コード規約の様に定めて、
 実装やレビューの時に使える
● 「俺の考えた最強の設計」同士が戦わなくて済む
113
どうやって現場で実践するか
114
● お手本コードを作る
○ ApplicationService、Entity、Repository・・・
● お手本に倣ってコードを書くようにチーム展開する
○ この段階では軽量DDDでも全然OK
● 「あれ、ドメイン層には何を書くべきなんだっけ?」
となったら、ドメインモデリングしてみる
● ドメインモデル図を元にリファクタリングしていく
DDD導入の進め方
115
● 「原理を理解して実践」より、
「お手本を元に展開」の方が圧倒的に難易度が低いため
●
●
なぜお手本コード展開から入るのか
116
● 「原理を理解して実践」より、
「お手本を元に展開」の方が圧倒的に難易度が低いため
● ドメイン層に何を書くべきか?という疑問を持った方が
モデリングの必要性を感じやすいため
●
なぜお手本コード展開から入るのか
117
なぜお手本コード展開から入るのか
● 「原理を理解して実践」より、
「お手本を元に展開」の方が圧倒的に難易度が低いため
● ドメイン層に何を書くべきか?という疑問を持った方が
モデリングの必要性を感じやすいため
● 「どういうコードに落としこまれるのか」が
イメージできてからの方が、ドメインモデリングしやすいため
118
上達のイメージ
● DDDのコーディング、モデリング共に1発では上手くできない
コーディング モデリング
119
上達のイメージ
● DDDのコーディング、モデリング共に1発では上手くできない
● コーディングだけ、モデリングだけ上手くなるということもない
コーディング モデリング
120
上達のイメージ
● DDDのコーディング、モデリング共に1発では上手くできない
● コーディングだけ、モデリングだけ上手くなるということもない
● 両方交互に経験値をためながら上達していくしかない
コーディング モデリング
121
上達のイメージ
● DDDのコーディング、モデリング共に1発では上手くできない
● コーディングだけ、モデリングだけ上手くなるということもない
● 両方交互に経験値をためながら上達していくしかない
● 結局、このサイクルのどちらから入るか、という違いだけ
コーディング モデリング
122
上達のイメージ
● DDDのコーディング、モデリング共に1発では上手くできない
● コーディングだけ、モデリングだけ上手くなるということもない
● 両方交互に経験値をためながら上達していくしかない
● 結局、このサイクルのどちらから入るか、という違いだけ
● コーディングと、モデリングを意識的に両方少しずつやってみるのが良い
コーディング モデリング
123
まとめ
● DDDでは、「モデルを継続的に改善」「モデルの更新をソフトウェアに反映」のアプロー
チでソフトウェアの価値を高める
● モデルの更新を反映しやすいように、モデルをそのまま表現する
その際にオブジェクト指向の手法を利用する
● DDD戦術設計パターンは、保守性の高い設計のベストプラクティス
● 設計パターンの適用(軽量DDD)と、モデリングを両方使うと、
ソフトウェアの価値を高められる
● 実装と、モデリングを少しずつ着手してみよう
124
最後に・・・
125
宣伝になっちゃいますが。。
「ドメイン駆動設計 モデリング/実装ガイド」
(2020.3.1 技術書典8 オンライン版発売予定)
・本日の内容は1,2章の内容
・全部で11章仕立てです、興味お持ちいただけたら
お買い求めくださいm(_ _)m
・boothで予約受付中
126
質問箱で質問募集しています
● 質問いただければ回答します
● https://peing.net/ja/little_hands
● 「質問箱 little_hands」で検索
127
ご静聴ありがとうございました
128
sli.do回答タイム
129
ご静聴ありがとうございました
130

DDDはオブジェクト指向を利用してどのようにメンテナブルなコードを書くか