Upgrade to Pro — share decks privately, control downloads, hide ads and more …

破壊せよ!データ破壊駆動で考えるドメインモデリング / data-destroy-driven

MinoDriven
October 25, 2024

破壊せよ!データ破壊駆動で考えるドメインモデリング / data-destroy-driven

このイベントの登壇資料です。

ミノ駆動さんが今伝えたいドメインモデリングの勘所 〜“想定外”を排するデータ破壊駆動設計とは?〜
https://findy.connpass.com/event/332976/

MinoDriven

October 25, 2024
Tweet

More Decks by MinoDriven

Other Decks in Programming

Transcript

  1. © DMM 自己紹介 ミノ駆動 ( @MinoDriven ) 合同会社DMM.com プラットフォーム開発本部 第3開発部

    DeveloperProductivityGroup DMMプラットフォームの設計を改善し開 発生産性向上を図るのがミッション 2
  2. © DMM もうちょっと具体的な仕事の内訳 サービス全体で共通利用されるDMMプラットフォーム(アカウント管理、不 正対策、決済、DMMポイント etc..)の設計品質改善 • 設計ガイドライン策定 • チームへの設計指導

    • プラットフォーム所属のエンジニア(約120人!)に対する設計勉強会 ミノ駆動本を使ったワークショップ形式の実践講習 • リファクタリング体制整備 3
  3. © DMM 壊れたデータによるバグ バグの原因はさまざま。 その中でも、不正なデータ、壊れたデータによるバグが多くを占めます。 • 外部から不正な値を入力される • ロジックが正しくないために、壊れたデータが内部的に作られてしまう だから本日はセキュリティの話ではありません。

    データ全般の異常系に関する設計の話なのです。 また、壊れたデータがDBに保存されてしまうことがマズいので、POSTや PATCHといった更新系リクエストを対象とします。参照系は対象外です。 14
  4. © DMM 異常系は後手に回りがち こういうの多くないですか?身に覚えはありませんか? • とにかく動くものを早く作る。 • データが壊れるようなバグが出たら付け焼き刃的にバリデーションを 実装。 •

    そのバリデーションもUtilなどいい加減な箇所に五月雨に実装。 • バリデーションの呼び忘れで同じバグが発生することも。 機能開発時、正常系のことばかり考えてしまい、異常系がおざなりになっ たり、後手に回ることが多くはありませんか? 15
  5. © DMM データ破壊駆動 クラッカーになったつもりで以下を検討します。 • どうやったらクラス内のデータ(インスタンス変 数)を破壊できるか • どうやったら矛盾したデータを作れるか •

    どうやったらユーザーが困る状況に陥るか この検討をすることで、正常な値を保証する、即ち 完全性を保証する制約が洗い出されます。 25 Let’s 破壊駆動!!
  6. © DMM 26 // 金額クラス public class Money { public

    int amount; public Currency currency; } Moneyクラスのインスタンス変数を破壊してみよう
  7. © DMM 27 // 金額クラス public class Money { public

    int amount; public Currency currency; } • amount(金額値)をマイナスにできてしまう • 別の金額にすり替えることができてしまう • currency(通貨単位)がnullはありえない • 途中で別の通貨単位に変更されるのは問題
  8. © DMM 28 // 金額クラス public class Money { public

    int amount; public Currency currency; } 【制約】 • amountは0以上 • amountは不変 【制約】 • currencyは非null • currencyは不変
  9. © DMM 29 class Money { int amount; Currency currency;

    } class Validator { static boolean validateMoneyAmount(Money money) { return 0 <= money.amount; } } ダメなのはこういう構造。 せっかく制約を洗い出せても、これではMoneyクラ ス単体で完全性を保証できない!壊れたデータが入 り込む余地がある! 大した根拠もなく「バリデーションは別に実装するも のだ」と固く信じている人が一部にいるので注意。 ダメ絶対
  10. © DMM 30 カプセル化 カプセル化とは、データとそのデータを操作するロジックをひとつにまとめ ること。 クラスはカプセル化の手段のひとつ。 (golangでは構造体、Reactではコンポーネント) 「クラスって何のためにあるの?」と聞かれたら「カプセル化のためで す!!」と即答できるようになりましょう。

    クラスでのカプセル化とは、インスタンス変数とそのインスタンス変数を操 作するロジックをひとまとめにすること。 クラス自身で(←ココ大事)完全性を保証できるよう、 そのクラスに関連ロジックをカプセル化しよう。
  11. © DMM 31 // 金額クラス class Money { final int

    amount; final Currency currency; Money(final int amount, final Currency currency) { if (amount < 0) throw new IllegalArgumentException(); if (currency == null) throw new IllegalArgumentException(); this.amount = amount; this.currency = currency; } } finalを付与し不変に 完全コンストラクタ。 インスタンス生成時に値チェックし、 初期化。 Moneyクラス単体でデータ完全性を保証できるようにする
  12. © DMM テストコードもデータ破壊駆動で! 32 @Test void testNegativeAmountThrowsException() { assertThrows(IllegalArgumentException.class, ()

    -> { new Money(-1, Currency.getInstance(Locale.JAPAN)); }); } 境界値テスト。 異常値を入れて例外がスローされる ことを検証する。
  13. © DMM 35 class CommonManager { int addMoneyAmount(Money money1, Money

    money2) { return money1.amount + money2.amount; } } 金額加算ロジックがMoneyとは全然関係ない箇所に実 装されている。金額関係のロジックがどこに実装されて いるのか把握が難しくなり、変更容易性が低下する。
  14. © DMM // 金額クラス class Money { (中略) Money add(final

    Money other) { if (!currency.equals(other.currency)) { throw new IllegalArgumentException(); } final int added = amount + other.amount; return new Money(added, currency); } } 38 金額加算メソッドもMoneyク ラスにカプセル化する。 これでドメインモデルの完全性 が満たされる。 ドメインモデルの完全性を満たすことで変更容易性が向上する
  15. © DMM 40 メール設定 メール設定ID ユーザーアカウントID プライマリメールアドレスID メールアドレス メールアドレスID アドレス文字列

    * GitHubっぽいメール設定のモデル。 複数メールアドレスを追加できる。 どれか1つをプライマリに設定できる。 この手のドメインモデリングではデータ だけが洗い出されがち。もっと大事な のは制約!! データ破壊駆動で制約を洗い出してみ よう。 ドメインモデルの完全性の観点でモデ ルに必要な機能を洗い出してみよう。
  16. © DMM 41 メール設定 メール設定ID ユーザーアカウントID プライマリメールアドレスID メールアドレス メールアドレスID アドレス文字列

    1..* (null)も含め不正なIDだと困る フォーマットに従っていないアドレスだと困る IDやアドレスを変更されると困る (nullも含め)不正なIDだと困る メール設定IDやユーザーアカウン トIDを変更されると困る プライマリメールアドレスに他人のア ドレスIDを設定されると困る メールアドレスの追 加、削除ができる必 要がある メールアドレスを全部削除されると困る プライマリメールアドレスを削除されると困る 同じメールアドレスを追加されると困る データ破壊駆動で考えるだけでこれだけの制約が洗い出される
  17. © DMM まとめ • バグは、データ異常が原因のものが多くを占める。 しかし異常系の検討は後手に回りがち。 • データ破壊駆動で「どうやったらデータ(インスタンス変数)を破壊でき るか」を考えてみよう。破壊されないための制約を洗い出そう。 •

    クラス自身で完全性を保証できるように制約をカプセル化しよう。 • ドメインモデル完全性の観点から、必要なドメインロジックをカプセル 化し、変更容易性を高めよう。 • ドメインモデリングの段階からデータ破壊駆動で設計しよう。 43