柔軟性
柔軟性とは…
既存のコードを修正する(壊す)ことなく、機能追加できること
また、必要以上の汎用性があると柔軟性が高いとされる。
柔軟な設計とされることもあるが直結しないもの
テーブルに予備カラムを持たせておく
予備カラムをハンドリングするコード修正が必要になるので、柔軟性を達成するものではない
ALTER TABLE ADD COLUMNの実行コスト(作業者の工数含む)が非常に高い場合のコストの前払い
メッセージに予備フィールドを持たせておく
予備フィールドをハンドリングするコード修正が必要になるので、柔軟性を達成するものではない
固定長メッセージのような以下なる変更も、破壊的変更となってしまう場合の対策としてこの手段が一応理に叶うことがある。
DSLで書ける
既存コードは修正しないが、DSLは修正するしテストも必要なので、↑で定義した柔軟性の与件を満たさない
プログラミング言語での実装コストが、DSLで書くコストを大きく上回ることが前提での戦略と言える
処理フローをテーブルに入れる
https://gyazo.com/e6d9d4eeb987512c062d746891f98832
ある種のルールエンジンといえるが、共通処理の組み合わせの制約や順序性があったりして、全部テストしきっておくことが難しい。ので、柔軟性の恩恵を生み出すことができず、柔軟な仕組みとはいえない。
柔軟性を達成するための設計
データ定義域を必要よりも広めにとる
例えばベトナム料理屋のメニュー管理システムを考える。
初期は牛肉のフォーしかメニューがない(ただ大盛、パクチー抜きなどはある)ので次のような型を作る。
code:pho1.ts
type Pho {
price: MonetaryAmount;
coriander: Weight;
beef: Weight;
noodle: Weight;
}
type 原価率計算 = (pho: Pho) => MonetaryAmount;
しばらくすると鶏肉のフォーの取り扱いを始めるので、牛肉やパクチーはトッピングとしてひとまとめで考える。
code:pho2.ts
type Pho {
price: MonetaryAmount;
noodle: Weight;
toppings: Topping[];
}
type Topping = Coriander | Beef | Chicken;
type 原価率計算 = (pho: Pho) => MonetaryAmount;
pho2のPho型はpho1のPho型よりもより広いデータを表現できる。さらに新しいトッピングが追加されても原価率計算のロジックを修正しなくても良い可能性がある。
code:pho2_ext.ts
type トッピング原価計算 = (
topping :Topping,
amount: Weight,
tbl: ToppingUnitTable) => MonetaryAmmount;
例えば上記のように、トッピングの単価テーブルから原価を計算できるものであれば、種類が増えてもフォー自体の原価計算は修正の必要がない。
すなわち偶然でなく狙って柔軟性を実現するためには、以下の条件が揃う必要がある。
現在必要とされる以上の定義域を持つ型を作る。
広げた定義域のデータに共通の振る舞いが適用できるかどうか判別できていなければならない。
→ すなわち抽象化と全域性
code:pho3.ts
type Food {
price: MonetaryAmount;
ingredients: Ingredient[];
}
データの定義域をより広げて、フォー以外の商品全てを表すようにすることもできる。
仕様(インタフェース)と実装を分離する(OCP)