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

補足:レビューシステム ● 設計能力の高いエンジニアが各チームのコードをレビューする。 ○ 擬似的に強いエンジニアと一緒に働ける環境を再現する。 ○ 静的解析(コードランク)ではケアできない部分を人間がカバーする。