Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
DDDはなぜ難しいのか / 良いコードの定義と設計能力の壁
Search
pospome
March 24, 2024
Programming
33
15k
DDDはなぜ難しいのか / 良いコードの定義と設計能力の壁
"Object-Oriented Conference 2024" の登壇資料です。
https://ooc.connpass.com/event/305241/
pospome
March 24, 2024
Tweet
Share
More Decks by pospome
See All by pospome
DMMプラットフォームにおけるTiDBの導入から運用まで
pospome
8
3.7k
DMMプラットフォームがTiDB Cloudを採用した背景
pospome
10
5.6k
マイクロサービス環境におけるDB戦略 in DMMプラットフォーム
pospome
12
4.1k
組織全体で開発生産性に取り組むために 専門チームを作った話
pospome
2
1.8k
DMMプラットフォームにおける GKE を利用した プラットフォームエンジニアリングへの 取り組み
pospome
1
710
DMMプラットフォームにおけるコード品質を改善する取り組みの理想と現実
pospome
3
2.6k
(再アップロード)Microservices & APIs
pospome
0
120
(再アップロード)Datastore/Go のデータ設計と struct の振る舞いについて
pospome
0
140
マイクロサービス環境におけるToilを削減するTerraformの活用 in DMMプラットフォーム
pospome
3
1.5k
Other Decks in Programming
See All in Programming
あれやってみてー駆動から成長を加速させる / areyattemite-driven
nashiusagi
1
200
Итераторы в Go 1.23: зачем они нужны, как использовать, и насколько они быстрые?
lamodatech
0
740
PSR-15 はあなたのための ものではない? - phpcon2024
myamagishi
0
110
KubeCon + CloudNativeCon NA 2024 Overviewat Kubernetes Meetup Tokyo #68 / amsy810_k8sjp68
masayaaoyama
0
250
Cloudflare MCP ServerでClaude Desktop からWeb APIを構築
kutakutat
1
540
見えないメモリを観測する: PHP 8.4 `pg_result_memory_size()` とSQL結果のメモリ管理
kentaroutakeda
0
330
採用事例の少ないSvelteを選んだ理由と それを正解にするためにやっていること
oekazuma
2
1k
testcontainers のススメ
sgash708
1
120
range over funcの使い道と非同期N+1リゾルバーの夢 / about a range over func
mackee
0
110
開発者とQAの越境で自動テストが増える開発プロセスを実現する
92thunder
1
180
テストケースの名前はどうつけるべきか?
orgachem
PRO
0
130
menu基盤チームによるGoogle Cloudの活用事例~Application Integration, Cloud Tasks編~
yoshifumi_ishikura
0
110
Featured
See All Featured
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Optimizing for Happiness
mojombo
376
70k
4 Signs Your Business is Dying
shpigford
181
21k
Being A Developer After 40
akosma
87
590k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Site-Speed That Sticks
csswizardry
2
190
Become a Pro
speakerdeck
PRO
26
5k
Why Our Code Smells
bkeepers
PRO
335
57k
GraphQLの誤解/rethinking-graphql
sonatard
67
10k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
229
52k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Designing for Performance
lara
604
68k
Transcript
DDDはなぜ難しいのか 良いコードの定義と設計能力の壁 @pospome
登壇者 名前:pospome(ぽすぽめ) 所属:DMMプラットフォーム Twitter:@pospome
目次 • DDDとの出会いと挫折 • DDDを理解する • 良いコードの定義 • 設計能力の壁
目次 • DDDとの出会いと挫折 • DDDを理解する • 良いコードの定義 • 設計能力の壁
DDDとの出会い • 2013年くらいにDDD本を見つけて読んでみた。 ◦ ちょうど設計に興味を持っていた。 ◦ 頑張って読んだが、よく分からなかった・・・。 ◦ レイヤアーキテクチャ =
DDD だと思っていた・・・。
学習の日々 • 当時は今ほど情報が充実していなかった。 ◦ 勉強会に行って有識者に質問した。 ◦ DDD本をもう一度読んでみた。 • 最初よりは理解度が上がった気がした。 ◦
戦略面、戦術面のプラクティスを覚えた。
挫折 • いまいちピンとこない・・・。 ◦ 上手く設計できている気がしない・・・。 ◦ 自分が取り組んでいるのはDDDなのだろうか・・・?
目次 • DDDとの出会いと挫折 • DDDを理解する • 良いコードの定義 • 設計能力の壁
そもそもDDDってなに? • 当時のpospomeはDDDを構成するプラクティスばかり気にしていた。 ◦ 例:エンティティ、レイヤアーキテクチャ、ドメインモデリング • DDDそのものを知ろうとしなかった。 ◦ DDDという設計手法は何のために生まれたのか? ◦
DDDじゃない設計手法は何なのか? • 挫折の正体に気付けない。
そもそもドメインってなに? • 英語の “Domain” には “領地、領域” という意味がある。 ◦ URLにおけるドメインも “領域”
を示している。
DDD本にも記載がある • p2 “ユーザーがソフトウェアを適用する、この対象領域がソフトウェアのドメイ ンである。” ◦ 当時のpospomeは読み飛ばしていた・・・。 • ドメイン =
ソフトウェアを適用する領域 ◦ 例:メルカリ = フリーマーケット、マネーフォワード = 家計簿
“駆動” ってなに? • DDD = ソフトウェアを適用する領域駆動設計 ◦ 駆動ってなに・・・? ◦ DDDに出会う前のpospomeは何駆動が開発だったのか?
◦ 何をすればDDDになるのか?
DB駆動設計 • 当時のpospomeがやっていたのは強いていうと “DB駆動設計” だった。 ◦ DBのテーブルと1対1でドメインオブジェクトを用意する。 ▪ ORMを利用するので、これが自然だった。 ▪
今も主流だと思う。 • 今思い返すと設計という設計は不要だった記憶がある。 ◦ テーブル設計が実質的な設計作業だった。
DB駆動設計の問題点 • DBのデータ構造はプログラミングに適した構造になっていない。 ◦ あくまでデータ管理に適した構造になっている。 ◦ プログラミングにはDBにない要素がある。 ▪ メソッド、アクセス修飾子、モジュール •
無理やりプログラミングで利用すると中長期的に辛くなってくる。
DB駆動設計の例 • “商品の価格を計算する” というユースケースを考える。 • キャンペーン中であれば、割引が適用される。
DB駆動設計の例 • DB駆動設計では、商品テーブル、キャンペーンテーブルに対応した 商品クラスとキャンペーンクラスが存在する。
DB駆動設計の例 • 商品クラスとキャンペーンクラスの データ構造は以下である。
DB駆動設計の例 • 商品の価格を計算する ロジックはこちら。 • アプリケーションレイヤに ベタ書きしている状態。 • 割引を考慮する。
DB駆動設計の例 • 単体のクラスが持つ値にのみ 依存するロジックは そのクラスのメソッドとして 実装することができる。 • トランザクションスクリプトを 回避できる。
DB駆動設計の例 • 割引期間かどうかを 判断するメソッドの実装。 • アプリケーションレイヤに ベタ書きされていた実装を メソッドに移植しただけ。
DB駆動設計の例 • 商品価格を計算するロジックは 依然として アプリケーションレイヤに ベタ書きされている。 • ItemとCampaignに 依存する形になっている。
DB駆動設計の例 • Itemに計算ロジックを 寄せている。 • アプリケーションレイヤから ロジックを排除することが できた。
DB駆動設計の例 • Itemのメソッドはこちら。 • DB駆動設計でも上手い具合に ロジックをドメインレイヤに 実装できている。 • 特に困ることなさそうだけど・・・。
DB駆動設計の罠 • サンプルコードだから上手くいっているだけ。 • 実際に扱う実装はもっと複雑なはず。 ◦ テーブルの数が多い。 ◦ テーブルが持つ属性の数が多い。 ◦
多くのクラスにまたがるロジックがある。 • 巨大なクラス同士が複雑に依存し合ってしまい、 中長期的に Fat Model になってしまう。
Fat Model • Item, CampaignもFat Modelに なる可能性がある。 • Item, Campaignそれぞれが
多くの値を持つので、 それらに関するロジックが Item, Campaignに寄ってしまう。 • 神クラスが誕生する。
ドメインモデル貧血症 • Fat Modelを回避するために アプリケーションレイヤに 切り出してしまうと、 ドメインモデル貧血症になる。 • 一時期流行ったサービスレイヤ とかがこれにあたる。
どうすべきか? • プログラミングに適したデータ構造(クラス設計)を採用する。 • DB構造をそのままプログラミングに利用するのは厳しい。 ◦ Fat Model ◦ ドメインモデル貧血症
Fat Modelを回避する例 • 商品価格を計算する際に 必要となる値のみを持ったクラスを 用意する。 • Discountという構造体を用意する。
Fat Modelを回避する例 • Priceという型を用意する。 • ItemとCampaignの結合から PriceとDiscountの結合に変更することで、 Fat Modelを回避することができる。 •
Discount, Priceという小さいパーツによって コードの再利用性も向上する。
DB構造とクラス構造のミスマッチ • プログラミングとしての 正しさを考慮すると、 DB構造とクラス構造が 一致するとは限らない。
Fat Modelを回避する例 その2 • ItemにDiscountを直接もたせる選択肢も あるかもしれない。 ◦ 正しいかどうかは別問題。
Fat Modelを回避する例 その3 • Item, Discountを持つ 新たな構造体を 定義するのがいいかもしれない。
DDDはドメインレイヤの実装に自由度を与える • 設計の自由度を高くすることによって、 多くの手札から最適なものを切ることができる。 ◦ ドメインモデル貧血症やFat Modelを回避することができる。 • DB駆動設計では得られないメリットを得ることができる。
DB駆動設計の問題点 • DBにとって最適なデータ構造をプログラミングで利用すると、 ドメインで設計を駆動することが難しくなる。 ◦ サンプルコード微妙だったかもしれないですけど・・・。 • 大規模なシステムになればなるほど辛くなる。 ◦ 逆に小規模であればDB駆動設計でも耐えられる。
• プログラミングに適したクラス設計を心がける。
補足:リポジトリパターンによるデータ差分の吸収 • DB構造とクラス構造の差分は以下のような形で吸収する必要があるので、 わりと面倒ではある。
“ドメイン駆動” の意味 • ソフトウェアの適用領域に対して適切な設計をする。 ◦ “ドメインで設計を駆動” できるように、 ドメインレイヤの設計に自由度を与える。 ◦ DBなどのデータ構造をプログラミングに流用しない。
▪ たまたま一致することはある。
ドメイン駆動の重要性 • 競合他社に勝っていくには、 独自の機能や利便性を追求する必要があり、 それに伴う仮説検証もしたい。 ◦ システム仕様を担うドメインレイヤを素早く変更する必要がある。 ◦ DB構造の都合に合わせてプログラムを書いてられない。
ここまでのまとめ:ドメイン駆動設計に対する理解 • ドメイン = ソフトウェアを適用する領域 • ドメイン駆動 = ドメインに適した設計をする。 ◦
DBなどのデータ構造に依存しないようにする。 ◦ 競合他社に勝てるように。 • 当時のpospomeはDB駆動設計でDDDを実践しようとしていた。 ◦ ずっと辛かったのはこれが原因だった。 ◦ Fat Modelを避けてドメインモデル貧血症が発生していた。
目次 • DDDとの出会いと挫折 • DDDを理解する • 良いコードの定義 • 設計能力の壁
ドメインに対して適切な設計をする • ドメインに対して適切な設計をしよう。 ◦ 設計の自由度を高くしたドメインレイヤを どのように設計するかが腕の見せ所。 ◦ 一番楽しく、一番悩む。
設計方法が分からない問題 • DB駆動設計をしていた人ほど適切な設計が分からない。 ◦ テーブル設計しかしてこなかったのが原因。
ICONIXによるドメインモデリング • 増田亨さんが「ICONIXいいよ」って言ってた。 • ドメインモデル図を書いたり、 ユースケース図を書いたり・・・。 • ドメインを図にすることで、 理解を深めつつ、実装に落とし込む。 *当時増田さんにはめちゃくちゃお世話になりました。
例:ドメインモデル図
例:ユースケース図
例:ロバストネス図
例:シーケンス図
図を書くだけでは上手く設計できない • 結論から言うと上手く設計できなかった。 ◦ なんとなく書いた図がそのまま良い設計になるわけがない。
図を書くだけでは上手く設計できない • ICONIXも最終的には人による良し悪しの判断が必要になる。
ドメインと実装のフィードバックループ • DDDは設計手法であり、成果物はコードである。 ◦ 実装における良し悪しが最重要である。 ◦ 実装を最適化する過程で得た知見を 自身の理解に還元する。 • あくまで実装ファーストで物事を考える。
このフローが重要→
図を書くだけでは上手く設計できない • DDDの各種プラクティスに対する知識があっても 設計できるかどうかは別問題である。 ◦ エンティティという概念を知っていても、 どんなエンティティを設計すればいいかが分からない。 ◦ DDDのプラクティスを理解していない人は理解しましょう。
良いコードとは? • ドメインモデリングによって生まれた実装を最適化するには、 “良いコード” の定義や要件を明確にしなければいけない。
ソフトウェア品質モデル ISO/IEC 25010 というソフトウェア品質モデルがある。 今回の発表における “良いコード” の定義は “保守性” に該当する。
ソフトウェア品質モデル 保守性には5つの特性がある。 これらを満たせば良さそう。 • モジュール性 • 再利用性 • 解析性 •
修正性 • 試験性
モジュール性 • 変更による影響が最小になっている度合い。 ◦ 高凝集、疎結合なモジュールを目指す。 ◦ 安定度と依存方向の制御も考慮する。
再利用性 • 他のシステムに資産を利用できる度合い。 ◦ “他のシステムに” という話だと、意識する機会は少ないと思う。
解析性 • 故障原因の診断、修正箇所の識別の効率性の度合い。 ◦ スタックトレースやエラーログの出力が該当するが、 コード自体の可読性も対象になる。
修正性 • 効率的にシステムを修正することができる度合い。 ◦ “競合他社に勝つため” に求められる。 ◦ モジュール性と解析性に左右される。
試験性 • 試験を実行する際の効率性の度合い。 ◦ テストが可能な設計にする必要がある。 ◦ ユニットテストを書いたり、 インテグレーションテストを自動化することも重要。
ソフトウェア品質モデルを満たせばよさそう なんらかの形で以下を満たせば良さそう。 • モジュール性 • 再利用性 • 解析性 • 修正性
• 試験性
目次 • DDDとの出会いと挫折 • DDDを理解する • 良いコードの定義 • 設計能力の壁
ソフトウェア品質モデルを満たせばよさそう どうすれば満たせるのか? • モジュール性 • 再利用性 • 解析性 • 修正性
• 試験性
定義の抽象度が高い • モジュール性の定義 ◦ 変更による影響が最小になっている度合い。 ↑ これが実現できれば苦労しない・・・。
設計の基礎力を固める 必要になる知識を挙げるとキリがない・・・。 • DRY原則 • ポリモーフィズム • SOLID原則 • 凝集度、結合度
• パッケージの安定度制御 • DI戦略 などなど・・・
設計の基礎力を固める “ItemにDiscountを持たせる” vs “ItemのメソッドにDiscountを渡す”
最適解はケースバイケース • システム仕様、テクノロジースタック、チームメンバーのスキルによって、最適解が 変わってくる。 ◦ 「どの程度xxxするか」を都度考えなければいけない。 ◦ “知っていること” と “できること”
は別物。
設計能力の壁 • ドメインレイヤをドメイン駆動で設計するには、 プログラミングの基礎力が必要になってしまう。 ◦ これがある意味 “壁” として立ちはだかる。 ◦ DDD本が与えてくれるのはプラクティスのみ。
▪ 具体的なコードの良し悪しは自身で判断する必要がある。
設計能力の壁 • 設計能力が低い人やチームがDDDを実践すると沼る可能性がある。 ◦ ドメインレイヤの設計が上手くできず、 時間を消費する割にコードの品質が低い状態になってしまう。 ◦ むしろDB駆動設計の方が開発自体は上手くいくケースが多い。 DB駆動設計はある意味優秀だったりする。
設計能力の壁を打ち破るには? • 自分で頑張って勉強する。 ◦ 結構時間がかかりそう。 • 設計スキルの高い人に教えてもらう。 ◦ これが一番いい。 ◦
チーム内に強い人がいて、 現場のコードベースでレビューしてもらうのが理想。 ◦ 技術支援という形だと効果が微妙かもしれない。
pospomeはとにかく勉強した • 言語や手法に関わらず設計系の書籍を読み漁った。 ◦ ざっくりカウントすると30冊以上読んでいた。 ◦ SOLID原則などの有名なものはネットの情報で学んだ。
アウトプットが重要 • 現場のコードで試してみた。 ◦ 実践してみないと分からない。 • サンプルコードを書いてみた。 ◦ 例:ソシャゲのガチャでStrategyパターンを使ってみる。 ◦
TODOアプリみたいな簡単なものだと意味がない。
アウトプットが重要 • 社外イベントへの登壇、ブログ執筆、同人誌の執筆 ◦ 自身の知識を体系的に整理できる。 ◦ 取り組む過程で新しい気付きがある。 ◦ 成果物に対するフィードバックによって新しい気付きがある。 ◦
自身のブランディングになる。 ▪ キャリアパスの形成に有利に働くことがある。
継続すると設計の引き出しができてくる 例: • アプリケーションレイヤに if, for, 四則演算があると ドメインモデル貧血症の兆候があるので注意する。 • 結合度はスタンプ結合と制御結合だけ気にすれば良い。
• 関数やメソッドの戻り値が配列だった場合は、 配列加工のロジックが散っていないか確認する。 必要に応じてファーストクラスコレクションを提供する。
まとめ • DDDを実践するにはドメインに適した設計をする必要がある。 ◦ DBのデータ構造に依存したクラス設計は避ける。 • 良いコードの定義を明確にすること。 ◦ 今回の発表では品質モデルを取り上げた。 •
DDDの難しさは設計の難しさ。 ◦ 頑張って勉強するしかない。
補足:DMMプラットフォームにおける組織的なサポート pospomeが所属するDMMプラットフォームでは、 コード品質を向上させるための環境構築を進めている。 • コードランク • レビューシステム
補足:コードランク • 静的解析によってコード品質をランク付けする。 「最低限これはやってほしい」に対する共通認識を持つ。
補足:レビューシステム • 設計能力の高いエンジニアが各チームのコードをレビューする。 ◦ 擬似的に強いエンジニアと一緒に働ける環境を再現する。 ◦ 静的解析(コードランク)ではケアできない部分を人間がカバーする。