破壊せよ!データ破壊駆動で考えるドメインモデリング / data-destroy-driven
by
MinoDriven
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Slide 1
Slide 1 text
© DMM © DMM 破壊せよ! データ破壊駆動で考える ドメインモデリング 2024/10/25(金) 合同会社DMM.com プラットフォーム開発本部 ミノ駆動
Slide 2
Slide 2 text
© DMM 自己紹介 ミノ駆動 ( @MinoDriven ) 合同会社DMM.com プラットフォーム開発本部 第3開発部 DeveloperProductivityGroup DMMプラットフォームの設計を改善し開 発生産性向上を図るのがミッション 2
Slide 3
Slide 3 text
© DMM もうちょっと具体的な仕事の内訳 サービス全体で共通利用されるDMMプラットフォーム(アカウント管理、不 正対策、決済、DMMポイント etc..)の設計品質改善 ● 設計ガイドライン策定 ● チームへの設計指導 ● プラットフォーム所属のエンジニア(約120人!)に対する設計勉強会 ミノ駆動本を使ったワークショップ形式の実践講習 ● リファクタリング体制整備 3
Slide 4
Slide 4 text
© DMM 著書紹介 『良いコード/悪いコードで学ぶ設計入門』 変更容易性の高い設計を学ぶ、 初級〜中級向け入門書 ITエンジニア本大賞2023技術書部門大賞受賞 12刷重版 4
Slide 5
Slide 5 text
© DMM 皆さんバグは好きですか?
Slide 6
Slide 6 text
© DMM 嫌いですよね
Slide 7
Slide 7 text
© DMM でも バグを発生させない設計 ちゃんとやってます? 本日はそういうお話です
Slide 8
Slide 8 text
© DMM 恐怖 注文数の事例(実話)
Slide 9
Slide 9 text
© DMM とあるショッピングサイトにて 本番環境に対してセキュリティ的に問題 がないか検証することになった。 インフラ面やログイン認証などいろいろ 確かめてみたが、特に問題は見当たらな かった。 ところが…… 9
Slide 10
Slide 10 text
© DMM マイナス注文数と返金 注文画面で注文数に「-1」を入力し注文実行し たところ、異常を知らせるような表示もなく、 すんなり注文できてしまった。 後日経理の人がすっ飛んで来て、「注文した人 に返金するよう返金指示書が発行された。そ の人は今いるか」といった奇妙なことが発生。 注文した人に返金!? もうヤバいですねこれ。 10 総額: $-39 注文数: -1 カートに入れる 今すぐ購入
Slide 11
Slide 11 text
© DMM 注文総額を好きなように減額する裏技 このマイナス注文数による返金があったか 調査したが見当たらなかった。 しかし別の不正が大量にあったことが発覚。 注文の際、買い物カゴの中に欲しい商品と 一緒に、マイナス注文数の商品を入れること で注文総額を減額する、という裏技だった。 この手口は噂として広まっていて、かなりの 不正が発生していた…… 11 総額:$207 価格:$246 注文数:1 価格:$39 注文数:-1
Slide 12
Slide 12 text
© DMM 詳しくは書籍『セキュア・バイ・デザイン』を読もう 12 マイナス注文数に関する詳細が解説されています
Slide 13
Slide 13 text
© DMM 皆さんが開発しているサービスは大丈夫ですか? 不正な値から守るロジックになっていますか? 実はヌケモレがあったりしませんか?
Slide 14
Slide 14 text
© DMM 壊れたデータによるバグ バグの原因はさまざま。 その中でも、不正なデータ、壊れたデータによるバグが多くを占めます。 ● 外部から不正な値を入力される ● ロジックが正しくないために、壊れたデータが内部的に作られてしまう だから本日はセキュリティの話ではありません。 データ全般の異常系に関する設計の話なのです。 また、壊れたデータがDBに保存されてしまうことがマズいので、POSTや PATCHといった更新系リクエストを対象とします。参照系は対象外です。 14
Slide 15
Slide 15 text
© DMM 異常系は後手に回りがち こういうの多くないですか?身に覚えはありませんか? ● とにかく動くものを早く作る。 ● データが壊れるようなバグが出たら付け焼き刃的にバリデーションを 実装。 ● そのバリデーションもUtilなどいい加減な箇所に五月雨に実装。 ● バリデーションの呼び忘れで同じバグが発生することも。 機能開発時、正常系のことばかり考えてしまい、異常系がおざなりになっ たり、後手に回ることが多くはありませんか? 15
Slide 16
Slide 16 text
© DMM データ異常系の設計を ちゃんとやりましょうね、 という話です
Slide 17
Slide 17 text
© DMM 解決編
Slide 18
Slide 18 text
© DMM 解決したい問題を整理 以下2点の問題を解決する必要があります。 1. 異常系のヌケモレ 2. バリデーションなどの異常系対策ロジックが バラバラに実装される問題 18
Slide 19
Slide 19 text
© DMM データ完全性
Slide 20
Slide 20 text
© DMM データ完全性 データに欠損や不整合がなく、正常な状態を維持すること。 つまりデータ異常の対策には、 データ完全性を保証する設計が必要なんですね。 20
Slide 21
Slide 21 text
© DMM 問題解決に必要な設計 1. データ完全性を保証する設計 2. (完全性保証用の)バリデーションが バラバラに実装されるのを防ぐ設計 この2つを同時に設計できるとても良い設計があります。 それが…… 21
Slide 22
Slide 22 text
© DMM DDD
Slide 23
Slide 23 text
© DMM ドメイン駆動設計だと思った?
Slide 24
Slide 24 text
© DMM データ破壊駆動 (Data Destroy Driven)
Slide 25
Slide 25 text
© DMM データ破壊駆動 クラッカーになったつもりで以下を検討します。 ● どうやったらクラス内のデータ(インスタンス変 数)を破壊できるか ● どうやったら矛盾したデータを作れるか ● どうやったらユーザーが困る状況に陥るか この検討をすることで、正常な値を保証する、即ち 完全性を保証する制約が洗い出されます。 25 Let’s 破壊駆動!!
Slide 26
Slide 26 text
© DMM 26 // 金額クラス public class Money { public int amount; public Currency currency; } Moneyクラスのインスタンス変数を破壊してみよう
Slide 27
Slide 27 text
© DMM 27 // 金額クラス public class Money { public int amount; public Currency currency; } ● amount(金額値)をマイナスにできてしまう ● 別の金額にすり替えることができてしまう ● currency(通貨単位)がnullはありえない ● 途中で別の通貨単位に変更されるのは問題
Slide 28
Slide 28 text
© DMM 28 // 金額クラス public class Money { public int amount; public Currency currency; } 【制約】 ● amountは0以上 ● amountは不変 【制約】 ● currencyは非null ● currencyは不変
Slide 29
Slide 29 text
© DMM 29 class Money { int amount; Currency currency; } class Validator { static boolean validateMoneyAmount(Money money) { return 0 <= money.amount; } } ダメなのはこういう構造。 せっかく制約を洗い出せても、これではMoneyクラ ス単体で完全性を保証できない!壊れたデータが入 り込む余地がある! 大した根拠もなく「バリデーションは別に実装するも のだ」と固く信じている人が一部にいるので注意。 ダメ絶対
Slide 30
Slide 30 text
© DMM 30 カプセル化 カプセル化とは、データとそのデータを操作するロジックをひとつにまとめ ること。 クラスはカプセル化の手段のひとつ。 (golangでは構造体、Reactではコンポーネント) 「クラスって何のためにあるの?」と聞かれたら「カプセル化のためで す!!」と即答できるようになりましょう。 クラスでのカプセル化とは、インスタンス変数とそのインスタンス変数を操 作するロジックをひとまとめにすること。 クラス自身で(←ココ大事)完全性を保証できるよう、 そのクラスに関連ロジックをカプセル化しよう。
Slide 31
Slide 31 text
© 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クラス単体でデータ完全性を保証できるようにする
Slide 32
Slide 32 text
© DMM テストコードもデータ破壊駆動で! 32 @Test void testNegativeAmountThrowsException() { assertThrows(IllegalArgumentException.class, () -> { new Money(-1, Currency.getInstance(Locale.JAPAN)); }); } 境界値テスト。 異常値を入れて例外がスローされる ことを検証する。
Slide 33
Slide 33 text
© DMM ここまではバグを発生させないための 異常系対策設計の話です
Slide 34
Slide 34 text
© DMM もうひと手間加えて 変更容易性が向上するようにします
Slide 35
Slide 35 text
© DMM 35 class CommonManager { int addMoneyAmount(Money money1, Money money2) { return money1.amount + money2.amount; } } 金額加算ロジックがMoneyとは全然関係ない箇所に実 装されている。金額関係のロジックがどこに実装されて いるのか把握が難しくなり、変更容易性が低下する。
Slide 36
Slide 36 text
© DMM ドメインモデルの完全性
Slide 37
Slide 37 text
© DMM ドメインモデルの完全性とは ドメインに関するデータやロジックに欠損や不整合がなく、正常な状態を維 持していること。 データ完全性を踏まえた設計は、データが壊れないように保証することは できる。しかし機能性までは保証できない。 ある概念に強く関係する機能が欠損したり、どこか別の箇所に実装されて しまう懸念がある。 37
Slide 38
Slide 38 text
© 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ク ラスにカプセル化する。 これでドメインモデルの完全性 が満たされる。 ドメインモデルの完全性を満たすことで変更容易性が向上する
Slide 39
Slide 39 text
© DMM 39 ドメインモデルの完全性 データ完全性 完全性はこのような関係にあります。 ドメインモデルの完全性だけで説明がつきますが、データ異常によるバ グ発生に対処するため、あえてデータ完全性を話題に出しました。
Slide 40
Slide 40 text
© DMM 40 メール設定 メール設定ID ユーザーアカウントID プライマリメールアドレスID メールアドレス メールアドレスID アドレス文字列 * GitHubっぽいメール設定のモデル。 複数メールアドレスを追加できる。 どれか1つをプライマリに設定できる。 この手のドメインモデリングではデータ だけが洗い出されがち。もっと大事な のは制約!! データ破壊駆動で制約を洗い出してみ よう。 ドメインモデルの完全性の観点でモデ ルに必要な機能を洗い出してみよう。
Slide 41
Slide 41 text
© DMM 41 メール設定 メール設定ID ユーザーアカウントID プライマリメールアドレスID メールアドレス メールアドレスID アドレス文字列 1..* (null)も含め不正なIDだと困る フォーマットに従っていないアドレスだと困る IDやアドレスを変更されると困る (nullも含め)不正なIDだと困る メール設定IDやユーザーアカウン トIDを変更されると困る プライマリメールアドレスに他人のア ドレスIDを設定されると困る メールアドレスの追 加、削除ができる必 要がある メールアドレスを全部削除されると困る プライマリメールアドレスを削除されると困る 同じメールアドレスを追加されると困る データ破壊駆動で考えるだけでこれだけの制約が洗い出される
Slide 42
Slide 42 text
© DMM 42 弊社DMMでデータ破壊駆動をやってみた とあるチームの新規機能開発で、ミノ駆動が設計支援に入りました。 設計フェーズでドメインモデリングを実施し、そこでデータ破壊駆動をやっ てみました。本スライドにあるように「クラッカーになったつもりで、どう やったらモデルのデータを壊せるか、矛盾したデータにできるかを考えて みましょう」と指示。 すると、以降ミノ駆動があれこれ何も言わなくてもチームメンバー同士が 自律的にどうやったら壊せるかを議論し始め、あっという間に制約を洗い 出すことができました。そして頑強なコードを実装できました。 効果てきめんです!!
Slide 43
Slide 43 text
© DMM まとめ ● バグは、データ異常が原因のものが多くを占める。 しかし異常系の検討は後手に回りがち。 ● データ破壊駆動で「どうやったらデータ(インスタンス変数)を破壊でき るか」を考えてみよう。破壊されないための制約を洗い出そう。 ● クラス自身で完全性を保証できるように制約をカプセル化しよう。 ● ドメインモデル完全性の観点から、必要なドメインロジックをカプセル 化し、変更容易性を高めよう。 ● ドメインモデリングの段階からデータ破壊駆動で設計しよう。 43
Slide 44
Slide 44 text
© DMM 皆さんにあらためて問います
Slide 45
Slide 45 text
© DMM バグは好きですか?
Slide 46
Slide 46 text
© DMM 深夜緊急対応は好きですか?
Slide 47
Slide 47 text
© DMM 致命的障害が発生すると サービスや会社の信頼を著しく損ねます そしてサービスが使われなくなります
Slide 48
Slide 48 text
© DMM サービスが使われないと お金が入って来なくなります
Slide 49
Slide 49 text
© DMM そしてあなたの給料が上がらなくなります
Slide 50
Slide 50 text
© DMM そうした 恐ろしい事態を起こさないために
Slide 51
Slide 51 text
© DMM 今すぐデータ破壊駆動で モデルを点検しましょう 正しいデータを維持できるよう バリデーションなどをモデルにカプセル化しましょう
Slide 52
Slide 52 text
© DMM ご清聴ありがとうございました