Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
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 ご清聴ありがとうございました