告白します。2023年、私はテスト自動化フレームワーク用のプラグインシステムを構築するのに3週間を費やしました。設定可能なテストランナー、ホットリロード可能なプラグイン、依存性注入コンテナ。全部揃えました。
誰もプラグインを書きませんでした。
そのフレームワークはCI上で毎回同じ設定で実行されていました。私が構築した「拡張性」は、正確にゼロ人のユーザーに使われました。プラグインアーキテクチャなしで、全体を4日でリリースできたはずです。
過剰エンジニアリングはどのように起こるか
それは合理的な思考から始まります:「後でこれを拡張する必要が出たらどうしよう?」
その思考こそが罠です。なぜなら、「後で」はあなたが想像した通りになることは稀で、架空の要件のために構築した抽象化は、実際の要件の邪魔になることがほとんどだからです。
私自身で観察した進行パターンは以下の通りです:
- シンプルな関数を構築する ✅
- 「これは設定可能にすべきだ」と考える ⚠️
- 設定オブジェクトを追加する
- 「環境によって異なる実装が必要かもしれない」と考える ⚠️
- インターフェースとファクトリーパターンを追加する
- 「実行時にこれを切り替える必要があるかもしれない」と考える 🚩
- 依存性注入を追加する
- 誰もそれを切り替える必要がなかったことに気づく
- 抽象化を削除するよりも維持する方が難しいため、永遠に維持し続ける
三つの質問
抽象化を追加する前に、私は今こう自問します:
1. 「実際に誰かがこれを要求したか?」
答えが「いや、でも必要になるかもしれない」なら、構築しないでください。YAGNI(You Aren't Gonna Need It:それは必要にならない)は、エンジニアリングにおいて最も違反されている原則です。
2. 「これを後で追加するコストと今追加するコストはどれくらいか?」
実際に必要になったときに抽象化を2時間で追加できるなら、「念のため」今構築する理由はありません。時期尚早な抽象化のコスト(誰も使わないコードを維持すること)は、後で追加するコストよりもほぼ常に高くなります。
3. 「これがなぜ存在するのか、一文で誰かに説明できるか?」
「異なる環境でStripeとBraintreeの間で決済プロバイダーを切り替える必要があるため、依存性注入を使用しています。」これが本当の理由です。
「ベストプラクティスだから依存性注入を使用しています。」それは理由ではありません。それはカルト的模倣(cargo culting)です。
シンプルなコードの姿
\\
