ミノ駆動さんのデータ破壊駆動を防ぐ設計のセミナーレポート
社内で展開するように書いてるので、文章ざっくり書いてます。
すいません
ミノ駆動さんが今伝えたいドメインモデリングの勘所 〜“想定外”を排するデータ破壊駆動設計とは?〜
https://findy.connpass.com/event/332976/
パワポはこちら
https://speakerdeck.com/minodriven/data-destroy-driven
参加理由
ミノ駆動さんの話は何度も聞いてるので、話される内容は自分が実践できるし、最近は新しい情報を知ったり、気づきがあることは減りました。
ただ、現場などで説明したり、説得したりする際に理解がまだ自分言葉で説明することができてません。
そのため、ミノ駆動さんの言葉を聞くことによって、自分の考えと合うところは同じ言葉を流用させていただいたり、話を聞く中で自分の経験と結びつき言語化ができたことは自分の言葉にしたりと伝えるための言葉を構築することがしたくて参加してました。
セミナーの内容
データ壊れて困ること
マイナスの個数が設定されて、請求が減額してしまって、それを悪用されて損失したことがDMMさんにあったそう。
負の値以外にも想定してないデータパターンが入ったことによって、意図しない処理になったり、データベース上のデータが壊れてしまい、そのデータを元にした障害が起きるってよく聞きますね。
データに不整合がなく、正常な状態を維持することをデータの完全性と言う。
この完全性を担保するためにカプセル化しよう。
カプセル化できてないアンチパターン
例にあがった金額を例にします。
Javaで言うと、int型は負の値を含みます。Javaの型だけでは正の値が保証できません。
非Nullもライブラリなしでは保証できません。
よくみそうな金額に関するロジックはこんな感じかなと思います。
金額は額と貨幣単位を属性として持ち、制約は以下
- 金額は0円以上
- 貨幣単位は非null
- 金額、貨幣単位は不変
ダメな構造例
public class Money{
private int amount; //額
private Currency currency: //貨幣単位
//コンストラクタは割愛
public static boolean validateAmount(){
return amount > 0;
}
}
validateを別のクラスに書くのは論外なので、割愛します。
このコードの問題は以下です。
- validateAmountメソッドを呼び出しFalseであれば、エラーにするなどの処理を書かないと負の金額が存在できてしまう
→最終的にマイナスの値がユーザ向けに発行されたり、データとして保存されてしまう - 金額が可変可能なので、エラーロジックを通した後に不正な値で上書きされてしまう
→結果不正な値の影響が発生する
あるべき
public class Money{
private final int amount; //額
private final Currency currency: //貨幣単位
public money(int money,Currency currency){
if(amount < 0){
thorw new IllegalArgumentException();
}
if(currency == null){
thorw new IllegalArgumentException();
}
this.money = money;
this.currency = currency;
}
}
コンストラクタに制約を入れることによって、負の金額を持つMoneyが存在できない。
変数もイミュータブルなため、コンストラクタの制約を通ったMoneyの金額が不正な値に変更されることもない。
金額を変更する際は
public Money changeAmount(int amount){
return new Money(amount,this.currency);
}
同様にコンストラクタを通るため、負の金額が存在することはMoneyクラスが保護している。
金額の仕様、制約をMoneyクラス単体で保護していることになる。
カプセル化はprivate型にしてSetter、Getterを介して変数を触れるようにすることではない。
データの完全性を自分のクラスで保証するために、コンストラクタや値の変更のロジックをまとめることが必要になっている。
制約のための働きかけ
カプセル化を元に自分自身で制約を守りデータの完全性を保護します。
セミナーではなかったが、早期リターンを使って想定できるケースのみ、処理させる方法もあります。
制約を全部洗い出すことは難しいです。
で、その際DMMさんで実行していたことがチームの中で逆に今のモデルのデータを壊すにはどこを攻撃するか。クラッカーの立場になって考えることをしたそうです。
そうすると、攻撃方法の意見が多く上がり、その反転を制約としていくことによってモデルの制約を洗い出したそうです。
設計をする方法として逆の壊す方法の意見の方が出しやすいのかもしれない。
この設計のアプローチはどんな設計のやり方にも言えるのかなと思います。