DDDはなぜ難しいのか / 良いコードの定義と設計能力の壁
by
pospome
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
DDDはなぜ難しいのか 良いコードの定義と設計能力の壁 @pospome
Slide 2
Slide 2 text
登壇者 名前:pospome(ぽすぽめ) 所属:DMMプラットフォーム Twitter:@pospome
Slide 3
Slide 3 text
目次 ● DDDとの出会いと挫折 ● DDDを理解する ● 良いコードの定義 ● 設計能力の壁
Slide 4
Slide 4 text
目次 ● DDDとの出会いと挫折 ● DDDを理解する ● 良いコードの定義 ● 設計能力の壁
Slide 5
Slide 5 text
DDDとの出会い ● 2013年くらいにDDD本を見つけて読んでみた。 ○ ちょうど設計に興味を持っていた。 ○ 頑張って読んだが、よく分からなかった・・・。 ○ レイヤアーキテクチャ = DDD だと思っていた・・・。
Slide 6
Slide 6 text
学習の日々 ● 当時は今ほど情報が充実していなかった。 ○ 勉強会に行って有識者に質問した。 ○ DDD本をもう一度読んでみた。 ● 最初よりは理解度が上がった気がした。 ○ 戦略面、戦術面のプラクティスを覚えた。
Slide 7
Slide 7 text
挫折 ● いまいちピンとこない・・・。 ○ 上手く設計できている気がしない・・・。 ○ 自分が取り組んでいるのはDDDなのだろうか・・・?
Slide 8
Slide 8 text
目次 ● DDDとの出会いと挫折 ● DDDを理解する ● 良いコードの定義 ● 設計能力の壁
Slide 9
Slide 9 text
そもそもDDDってなに? ● 当時のpospomeはDDDを構成するプラクティスばかり気にしていた。 ○ 例:エンティティ、レイヤアーキテクチャ、ドメインモデリング ● DDDそのものを知ろうとしなかった。 ○ DDDという設計手法は何のために生まれたのか? ○ DDDじゃない設計手法は何なのか? ● 挫折の正体に気付けない。
Slide 10
Slide 10 text
そもそもドメインってなに? ● 英語の “Domain” には “領地、領域” という意味がある。 ○ URLにおけるドメインも “領域” を示している。
Slide 11
Slide 11 text
DDD本にも記載がある ● p2 “ユーザーがソフトウェアを適用する、この対象領域がソフトウェアのドメイ ンである。” ○ 当時のpospomeは読み飛ばしていた・・・。 ● ドメイン = ソフトウェアを適用する領域 ○ 例:メルカリ = フリーマーケット、マネーフォワード = 家計簿
Slide 12
Slide 12 text
“駆動” ってなに? ● DDD = ソフトウェアを適用する領域駆動設計 ○ 駆動ってなに・・・? ○ DDDに出会う前のpospomeは何駆動が開発だったのか? ○ 何をすればDDDになるのか?
Slide 13
Slide 13 text
DB駆動設計 ● 当時のpospomeがやっていたのは強いていうと “DB駆動設計” だった。 ○ DBのテーブルと1対1でドメインオブジェクトを用意する。 ■ ORMを利用するので、これが自然だった。 ■ 今も主流だと思う。 ● 今思い返すと設計という設計は不要だった記憶がある。 ○ テーブル設計が実質的な設計作業だった。
Slide 14
Slide 14 text
DB駆動設計の問題点 ● DBのデータ構造はプログラミングに適した構造になっていない。 ○ あくまでデータ管理に適した構造になっている。 ○ プログラミングにはDBにない要素がある。 ■ メソッド、アクセス修飾子、モジュール ● 無理やりプログラミングで利用すると中長期的に辛くなってくる。
Slide 15
Slide 15 text
DB駆動設計の例 ● “商品の価格を計算する” というユースケースを考える。 ● キャンペーン中であれば、割引が適用される。
Slide 16
Slide 16 text
DB駆動設計の例 ● DB駆動設計では、商品テーブル、キャンペーンテーブルに対応した 商品クラスとキャンペーンクラスが存在する。
Slide 17
Slide 17 text
DB駆動設計の例 ● 商品クラスとキャンペーンクラスの データ構造は以下である。
Slide 18
Slide 18 text
DB駆動設計の例 ● 商品の価格を計算する ロジックはこちら。 ● アプリケーションレイヤに ベタ書きしている状態。 ● 割引を考慮する。
Slide 19
Slide 19 text
DB駆動設計の例 ● 単体のクラスが持つ値にのみ 依存するロジックは そのクラスのメソッドとして 実装することができる。 ● トランザクションスクリプトを 回避できる。
Slide 20
Slide 20 text
DB駆動設計の例 ● 割引期間かどうかを 判断するメソッドの実装。 ● アプリケーションレイヤに ベタ書きされていた実装を メソッドに移植しただけ。
Slide 21
Slide 21 text
DB駆動設計の例 ● 商品価格を計算するロジックは 依然として アプリケーションレイヤに ベタ書きされている。 ● ItemとCampaignに 依存する形になっている。
Slide 22
Slide 22 text
DB駆動設計の例 ● Itemに計算ロジックを 寄せている。 ● アプリケーションレイヤから ロジックを排除することが できた。
Slide 23
Slide 23 text
DB駆動設計の例 ● Itemのメソッドはこちら。 ● DB駆動設計でも上手い具合に ロジックをドメインレイヤに 実装できている。 ● 特に困ることなさそうだけど・・・。
Slide 24
Slide 24 text
DB駆動設計の罠 ● サンプルコードだから上手くいっているだけ。 ● 実際に扱う実装はもっと複雑なはず。 ○ テーブルの数が多い。 ○ テーブルが持つ属性の数が多い。 ○ 多くのクラスにまたがるロジックがある。 ● 巨大なクラス同士が複雑に依存し合ってしまい、 中長期的に Fat Model になってしまう。
Slide 25
Slide 25 text
Fat Model ● Item, CampaignもFat Modelに なる可能性がある。 ● Item, Campaignそれぞれが 多くの値を持つので、 それらに関するロジックが Item, Campaignに寄ってしまう。 ● 神クラスが誕生する。
Slide 26
Slide 26 text
ドメインモデル貧血症 ● Fat Modelを回避するために アプリケーションレイヤに 切り出してしまうと、 ドメインモデル貧血症になる。 ● 一時期流行ったサービスレイヤ とかがこれにあたる。
Slide 27
Slide 27 text
どうすべきか? ● プログラミングに適したデータ構造(クラス設計)を採用する。 ● DB構造をそのままプログラミングに利用するのは厳しい。 ○ Fat Model ○ ドメインモデル貧血症
Slide 28
Slide 28 text
Fat Modelを回避する例 ● 商品価格を計算する際に 必要となる値のみを持ったクラスを 用意する。 ● Discountという構造体を用意する。
Slide 29
Slide 29 text
Fat Modelを回避する例 ● Priceという型を用意する。 ● ItemとCampaignの結合から PriceとDiscountの結合に変更することで、 Fat Modelを回避することができる。 ● Discount, Priceという小さいパーツによって コードの再利用性も向上する。
Slide 30
Slide 30 text
DB構造とクラス構造のミスマッチ ● プログラミングとしての 正しさを考慮すると、 DB構造とクラス構造が 一致するとは限らない。
Slide 31
Slide 31 text
Fat Modelを回避する例 その2 ● ItemにDiscountを直接もたせる選択肢も あるかもしれない。 ○ 正しいかどうかは別問題。
Slide 32
Slide 32 text
Fat Modelを回避する例 その3 ● Item, Discountを持つ 新たな構造体を 定義するのがいいかもしれない。
Slide 33
Slide 33 text
DDDはドメインレイヤの実装に自由度を与える ● 設計の自由度を高くすることによって、 多くの手札から最適なものを切ることができる。 ○ ドメインモデル貧血症やFat Modelを回避することができる。 ● DB駆動設計では得られないメリットを得ることができる。
Slide 34
Slide 34 text
DB駆動設計の問題点 ● DBにとって最適なデータ構造をプログラミングで利用すると、 ドメインで設計を駆動することが難しくなる。 ○ サンプルコード微妙だったかもしれないですけど・・・。 ● 大規模なシステムになればなるほど辛くなる。 ○ 逆に小規模であればDB駆動設計でも耐えられる。 ● プログラミングに適したクラス設計を心がける。
Slide 35
Slide 35 text
補足:リポジトリパターンによるデータ差分の吸収 ● DB構造とクラス構造の差分は以下のような形で吸収する必要があるので、 わりと面倒ではある。
Slide 36
Slide 36 text
“ドメイン駆動” の意味 ● ソフトウェアの適用領域に対して適切な設計をする。 ○ “ドメインで設計を駆動” できるように、 ドメインレイヤの設計に自由度を与える。 ○ DBなどのデータ構造をプログラミングに流用しない。 ■ たまたま一致することはある。
Slide 37
Slide 37 text
ドメイン駆動の重要性 ● 競合他社に勝っていくには、 独自の機能や利便性を追求する必要があり、 それに伴う仮説検証もしたい。 ○ システム仕様を担うドメインレイヤを素早く変更する必要がある。 ○ DB構造の都合に合わせてプログラムを書いてられない。
Slide 38
Slide 38 text
ここまでのまとめ:ドメイン駆動設計に対する理解 ● ドメイン = ソフトウェアを適用する領域 ● ドメイン駆動 = ドメインに適した設計をする。 ○ DBなどのデータ構造に依存しないようにする。 ○ 競合他社に勝てるように。 ● 当時のpospomeはDB駆動設計でDDDを実践しようとしていた。 ○ ずっと辛かったのはこれが原因だった。 ○ Fat Modelを避けてドメインモデル貧血症が発生していた。
Slide 39
Slide 39 text
目次 ● DDDとの出会いと挫折 ● DDDを理解する ● 良いコードの定義 ● 設計能力の壁
Slide 40
Slide 40 text
ドメインに対して適切な設計をする ● ドメインに対して適切な設計をしよう。 ○ 設計の自由度を高くしたドメインレイヤを どのように設計するかが腕の見せ所。 ○ 一番楽しく、一番悩む。
Slide 41
Slide 41 text
設計方法が分からない問題 ● DB駆動設計をしていた人ほど適切な設計が分からない。 ○ テーブル設計しかしてこなかったのが原因。
Slide 42
Slide 42 text
ICONIXによるドメインモデリング ● 増田亨さんが「ICONIXいいよ」って言ってた。 ● ドメインモデル図を書いたり、 ユースケース図を書いたり・・・。 ● ドメインを図にすることで、 理解を深めつつ、実装に落とし込む。 *当時増田さんにはめちゃくちゃお世話になりました。
Slide 43
Slide 43 text
例:ドメインモデル図
Slide 44
Slide 44 text
例:ユースケース図
Slide 45
Slide 45 text
例:ロバストネス図
Slide 46
Slide 46 text
例:シーケンス図
Slide 47
Slide 47 text
図を書くだけでは上手く設計できない ● 結論から言うと上手く設計できなかった。 ○ なんとなく書いた図がそのまま良い設計になるわけがない。
Slide 48
Slide 48 text
図を書くだけでは上手く設計できない ● ICONIXも最終的には人による良し悪しの判断が必要になる。
Slide 49
Slide 49 text
ドメインと実装のフィードバックループ ● DDDは設計手法であり、成果物はコードである。 ○ 実装における良し悪しが最重要である。 ○ 実装を最適化する過程で得た知見を 自身の理解に還元する。 ● あくまで実装ファーストで物事を考える。 このフローが重要→
Slide 50
Slide 50 text
図を書くだけでは上手く設計できない ● DDDの各種プラクティスに対する知識があっても 設計できるかどうかは別問題である。 ○ エンティティという概念を知っていても、 どんなエンティティを設計すればいいかが分からない。 ○ DDDのプラクティスを理解していない人は理解しましょう。
Slide 51
Slide 51 text
良いコードとは? ● ドメインモデリングによって生まれた実装を最適化するには、 “良いコード” の定義や要件を明確にしなければいけない。
Slide 52
Slide 52 text
ソフトウェア品質モデル ISO/IEC 25010 というソフトウェア品質モデルがある。 今回の発表における “良いコード” の定義は “保守性” に該当する。
Slide 53
Slide 53 text
ソフトウェア品質モデル 保守性には5つの特性がある。 これらを満たせば良さそう。 ● モジュール性 ● 再利用性 ● 解析性 ● 修正性 ● 試験性
Slide 54
Slide 54 text
モジュール性 ● 変更による影響が最小になっている度合い。 ○ 高凝集、疎結合なモジュールを目指す。 ○ 安定度と依存方向の制御も考慮する。
Slide 55
Slide 55 text
再利用性 ● 他のシステムに資産を利用できる度合い。 ○ “他のシステムに” という話だと、意識する機会は少ないと思う。
Slide 56
Slide 56 text
解析性 ● 故障原因の診断、修正箇所の識別の効率性の度合い。 ○ スタックトレースやエラーログの出力が該当するが、 コード自体の可読性も対象になる。
Slide 57
Slide 57 text
修正性 ● 効率的にシステムを修正することができる度合い。 ○ “競合他社に勝つため” に求められる。 ○ モジュール性と解析性に左右される。
Slide 58
Slide 58 text
試験性 ● 試験を実行する際の効率性の度合い。 ○ テストが可能な設計にする必要がある。 ○ ユニットテストを書いたり、 インテグレーションテストを自動化することも重要。
Slide 59
Slide 59 text
ソフトウェア品質モデルを満たせばよさそう なんらかの形で以下を満たせば良さそう。 ● モジュール性 ● 再利用性 ● 解析性 ● 修正性 ● 試験性
Slide 60
Slide 60 text
目次 ● DDDとの出会いと挫折 ● DDDを理解する ● 良いコードの定義 ● 設計能力の壁
Slide 61
Slide 61 text
ソフトウェア品質モデルを満たせばよさそう どうすれば満たせるのか? ● モジュール性 ● 再利用性 ● 解析性 ● 修正性 ● 試験性
Slide 62
Slide 62 text
定義の抽象度が高い ● モジュール性の定義 ○ 変更による影響が最小になっている度合い。 ↑ これが実現できれば苦労しない・・・。
Slide 63
Slide 63 text
設計の基礎力を固める 必要になる知識を挙げるとキリがない・・・。 ● DRY原則 ● ポリモーフィズム ● SOLID原則 ● 凝集度、結合度 ● パッケージの安定度制御 ● DI戦略 などなど・・・
Slide 64
Slide 64 text
設計の基礎力を固める “ItemにDiscountを持たせる” vs “ItemのメソッドにDiscountを渡す”
Slide 65
Slide 65 text
最適解はケースバイケース ● システム仕様、テクノロジースタック、チームメンバーのスキルによって、最適解が 変わってくる。 ○ 「どの程度xxxするか」を都度考えなければいけない。 ○ “知っていること” と “できること” は別物。
Slide 66
Slide 66 text
設計能力の壁 ● ドメインレイヤをドメイン駆動で設計するには、 プログラミングの基礎力が必要になってしまう。 ○ これがある意味 “壁” として立ちはだかる。 ○ DDD本が与えてくれるのはプラクティスのみ。 ■ 具体的なコードの良し悪しは自身で判断する必要がある。
Slide 67
Slide 67 text
設計能力の壁 ● 設計能力が低い人やチームがDDDを実践すると沼る可能性がある。 ○ ドメインレイヤの設計が上手くできず、 時間を消費する割にコードの品質が低い状態になってしまう。 ○ むしろDB駆動設計の方が開発自体は上手くいくケースが多い。 DB駆動設計はある意味優秀だったりする。
Slide 68
Slide 68 text
設計能力の壁を打ち破るには? ● 自分で頑張って勉強する。 ○ 結構時間がかかりそう。 ● 設計スキルの高い人に教えてもらう。 ○ これが一番いい。 ○ チーム内に強い人がいて、 現場のコードベースでレビューしてもらうのが理想。 ○ 技術支援という形だと効果が微妙かもしれない。
Slide 69
Slide 69 text
pospomeはとにかく勉強した ● 言語や手法に関わらず設計系の書籍を読み漁った。 ○ ざっくりカウントすると30冊以上読んでいた。 ○ SOLID原則などの有名なものはネットの情報で学んだ。
Slide 70
Slide 70 text
アウトプットが重要 ● 現場のコードで試してみた。 ○ 実践してみないと分からない。 ● サンプルコードを書いてみた。 ○ 例:ソシャゲのガチャでStrategyパターンを使ってみる。 ○ TODOアプリみたいな簡単なものだと意味がない。
Slide 71
Slide 71 text
アウトプットが重要 ● 社外イベントへの登壇、ブログ執筆、同人誌の執筆 ○ 自身の知識を体系的に整理できる。 ○ 取り組む過程で新しい気付きがある。 ○ 成果物に対するフィードバックによって新しい気付きがある。 ○ 自身のブランディングになる。 ■ キャリアパスの形成に有利に働くことがある。
Slide 72
Slide 72 text
継続すると設計の引き出しができてくる 例: ● アプリケーションレイヤに if, for, 四則演算があると ドメインモデル貧血症の兆候があるので注意する。 ● 結合度はスタンプ結合と制御結合だけ気にすれば良い。 ● 関数やメソッドの戻り値が配列だった場合は、 配列加工のロジックが散っていないか確認する。 必要に応じてファーストクラスコレクションを提供する。
Slide 73
Slide 73 text
まとめ ● DDDを実践するにはドメインに適した設計をする必要がある。 ○ DBのデータ構造に依存したクラス設計は避ける。 ● 良いコードの定義を明確にすること。 ○ 今回の発表では品質モデルを取り上げた。 ● DDDの難しさは設計の難しさ。 ○ 頑張って勉強するしかない。
Slide 74
Slide 74 text
補足:DMMプラットフォームにおける組織的なサポート pospomeが所属するDMMプラットフォームでは、 コード品質を向上させるための環境構築を進めている。 ● コードランク ● レビューシステム
Slide 75
Slide 75 text
補足:コードランク ● 静的解析によってコード品質をランク付けする。 「最低限これはやってほしい」に対する共通認識を持つ。
Slide 76
Slide 76 text
補足:レビューシステム ● 設計能力の高いエンジニアが各チームのコードをレビューする。 ○ 擬似的に強いエンジニアと一緒に働ける環境を再現する。 ○ 静的解析(コードランク)ではケアできない部分を人間がカバーする。