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.6k
DMMプラットフォームがTiDB Cloudを採用した背景
pospome
10
5.5k
マイクロサービス環境におけるDB戦略 in DMMプラットフォーム
pospome
12
4k
組織全体で開発生産性に取り組むために 専門チームを作った話
pospome
2
1.8k
DMMプラットフォームにおける GKE を利用した プラットフォームエンジニアリングへの 取り組み
pospome
1
690
DMMプラットフォームにおけるコード品質を改善する取り組みの理想と現実
pospome
3
2.5k
(再アップロード)Microservices & APIs
pospome
0
120
(再アップロード)Datastore/Go のデータ設計と struct の振る舞いについて
pospome
0
130
マイクロサービス環境におけるToilを削減するTerraformの活用 in DMMプラットフォーム
pospome
3
1.5k
Other Decks in Programming
See All in Programming
Better Code Design in PHP
afilina
PRO
0
130
[Do iOS '24] Ship your app on a Friday...and enjoy your weekend!
polpielladev
0
110
Quine, Polyglot, 良いコード
qnighy
4
640
ローコードSaaSのUXを向上させるためのTypeScript
taro28
1
620
Nurturing OpenJDK distribution: Eclipse Temurin Success History and plan
ivargrimstad
0
930
What’s New in Compose Multiplatform - A Live Tour (droidcon London 2024)
zsmb
1
470
AWS Lambdaから始まった Serverlessの「熱」とキャリアパス / It started with AWS Lambda Serverless “fever” and career path
seike460
PRO
1
260
CSC509 Lecture 09
javiergs
PRO
0
140
subpath importsで始めるモック生活
10tera
0
310
ピラミッド、アイスクリームコーン、SMURF: 自動テストの最適バランスを求めて / Pyramid Ice-Cream-Cone and SMURF
twada
PRO
10
1.3k
ふかぼれ!CSSセレクターモジュール / Fukabore! CSS Selectors Module
petamoriken
0
150
Streams APIとTCPフロー制御 / Web Streams API and TCP flow control
tasshi
2
350
Featured
See All Featured
Designing the Hi-DPI Web
ddemaree
280
34k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
28
2k
A better future with KSS
kneath
238
17k
Raft: Consensus for Rubyists
vanstee
136
6.6k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
159
15k
Docker and Python
trallard
40
3.1k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
Reflections from 52 weeks, 52 projects
jeffersonlam
346
20k
Designing for humans not robots
tammielis
250
25k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
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プラットフォームでは、 コード品質を向上させるための環境構築を進めている。 • コードランク • レビューシステム
補足:コードランク • 静的解析によってコード品質をランク付けする。 「最低限これはやってほしい」に対する共通認識を持つ。
補足:レビューシステム • 設計能力の高いエンジニアが各チームのコードをレビューする。 ◦ 擬似的に強いエンジニアと一緒に働ける環境を再現する。 ◦ 静的解析(コードランク)ではケアできない部分を人間がカバーする。