コードを書くとき、テーブル駆動方式は過小評価されています。非常に強力なテクニックなので、事例とそのインパクトを説明します。
概略サンプル
if age < 10: return price / 2 elif age < 20: return price / 3 elif age < 50: return price / 5 else: return price / 100
↓
age_table = [ [10, 1.0/2], [20, 1.0/3], # 小数点扱い注意 [50, 1.0/5], [float('inf'),1.0/100] #番兵パターン ] for target in age_table: if age < target[0]: return price * target[1]
メリット:ほぼどんな言語でも使える
いわゆるデシジョンテーブルです。パターンマッチがない言語でも大丈夫です。Unit Testで使うとテーブル駆動テストと呼ばれるようです。
メリット:読みやすい
同じ構造なので驚きがありません。3パターン目が急に謎の処理をしないか不安になったことはありませんか?1行1行ドキドキしながら読む必要はなく、読み飛ばせます。IF文と違い、語彙が精緻といえます。
メリット:変更に強い
データを増減させるなり修正するなりすればOKです。
メリット:考えやすい
複雑な条件は表にするとわかりやすく整理できます。表で考えたり修正したほうが早いでしょう。テーブル駆動は表にしやすい...というより、表をそのままプログラム化したものです。
2次元テーブルの例を見比べてみましょう
条件1/2 | カレー | ステーキ | ラーメン |
---|---|---|---|
100円 | レトルト | 危険 | カップラーメン |
1,000円 | いいね | 大丈夫? | 普通 |
10,000円 | 宮廷料理? | 満足 | 卒倒 |
decision = { # 例。pandasで書いたほうが何次元でも対応できそう 100:{'カレー': 'レトルト','ステーキ':'やばい','ラーメン':'カップラーメン'} 1000:{'カレー': 'いいね','ステーキ':'怪しい','ラーメン':'普通'} 10000:{'カレー': '卒倒','ステーキ':'満足','ラーメン':'卒倒'} } print(decision[budget][menu]) #工夫すればbetweenにも対応できる
テーブルを使えないかを考えるだけで、たとえ実際に使わなくてもロジックがスッキリします。
*多くのプログラミング言語は第一級関数を持っており、配列等に入れた関数をapply/callといった形で呼び出すこともできます。
メリット:外部化しやすい
データをjsonといった外部ファイルにできます。修正してもデプロイ不要に。Excelに入れるもDBに入れるも可能です。そうすればビジネスロジックの専門家が直接ロジックの更新できるようになります。
=> ルールエンジンへ
テーブル駆動方式が与えるインパクト
ビジネスロジックをコードからデータに変換できます。外部化してデータとして扱えば開発へのインパクトが大きくなります。
テストが大幅に削減できます
ルールをロジックに転写できているかのテストが不要です。もちろんルール自体が誤っていないかは検証が必要です。
デプロイ、リリースが削減できます
アプリケーションのデプロイからリリースはまだまだリスクが大きい組織が多いでしょう。リードタイムも長い傾向にあります。ロジックからデータに移行することで、素早く反映できます。
また、ロールバックする際、コードのロールバックなら1時間、インフラでの切り戻しなら10分かかります。データなら1分で反映可能です。
*コード修正によるロールフォワードは半日かかり、さらに新しい障害が発生します。
ビジネスユーザーが修正でき、調整が削減できます
データ化し、管理画面などを提供することで、圧倒的リードタイムで修正できます。エンジニアの工数も不要になりますね。
注意点
- テーブルに存在しないパターンを必ず考慮する
- 同一構造が前提なので構造ごと変えたいときは弱い
- テストはしやすいが、コンパイラによる支援は効きづらいことも
- 仕様自体の誤りからは逃れられないのでパラノイアだけが生き残る
最後に
Code is a liability
Code is a liability, not an asset. So goal of software engineer is delivering the maximum amount of desired functionality at the cost of the least amount of code complexity, even as desired functionality evolves over time.
— Greg Brockman (@gdb) 2022年12月24日
ということで、なるべく価値あたりのコードベースを削減していきましょう。テーブル駆動方式はその一つの手段です。サーバレス化もそうですが、理解しやすさとユーザー価値を両立させましょう。
文責: 高木