YAGNIが語っていなかったコスト
(newsletter.kentbeck.com)- YAGNIは「まだ必要のないコードを書くな」という単純な節約ルールではなく、必要性が確定する前に推測で構造を先取りすることのコストを扱う原則である
- 問題の中心は設計そのものではなく、いつ設計するかであり、早すぎる構造化は遅すぎる構造化と同じくらい危険になり得る
- 先行した構造は、情報が来る前に選択肢を閉じてしまうオプションコストと、コストを前倒しし収益を遅らせるNPVコストを同時に生み出す
- コード生成コストがほぼゼロに近づいてもYAGNIはなくならず、むしろ安価な生成は推測ベースのフレームワークをより簡単に作れるようにする
- 必要なときに作れという結論は、コードを書くコストのためではなく、使っていない選択権と使っていないお金の価値が依然として残っているためである
YAGNIは設計を禁じていない
- YAGNIは「You Aren’t Gonna Need It」の略で、不要なものを絶対に設計するなという言い訳ではない
- 必要なものがあれば作ればよいが、核心はタイミングにある
- プロジェクト中に「3週間後には単純な実装では足りなくなるはずだから、今もっと複雑なものを作りたい」という状況で、「You aren’t going to need it」という返答が繰り返された逸話が出発点である
- この原則は、構造を早く作りすぎることも遅く作りすぎることも、どちらも危険だと見なす
問題はコードを書くコストではなく、推測ベースの構造である
- よくある解釈では、YAGNIを「まだ必要のないコードは高くつくから書くな」という節約ルールとして捉える
- しかしYAGNIが狙っている対象はコード生産コストではなく、実際の機能が必要とする前にあらかじめ作った**投機的構造(speculative structure)**である
- こうした構造は、異なる時点と理由で2種類のコストを発生させる
1つ目のコスト:選択権
- 機能が到着する前に構造を作ると、まだ分からない要求に対して推測でコミットすることになる
- 事前に備えた機能は、実際に到着する機能とはたいてい異なり、その結果として2度コストを支払う
- 誤った形の構造を迂回するコスト
- その構造を再び取り壊すコスト
- この問題は、単に「予測は難しい」という話にとどまらない
- 推測が当たっていたとしても、事前にコミットせず後で正しい構造を作れる選択権を失うという点で損失が残る
- 待つことは怠慢ではなく、選択権という資産を保有することである
2つ目のコスト:NPV
- お金に時間価値があるように、機能にも時間価値がある
- 3か月後に必要な機能のために今構造を作ると、コストは前倒しされ、実際にお金を稼ぐ機能のリリースは遅れる
- このコストは推測が当たっていても発生する
- 完璧な予測でもコストと収益の順序を変えることはできず、損失はコストを収益より先に置いた間隔から生じる
- 選択権コストは「情報が来る前にコミットするな」という問題であり、NPVコストは「必要になる前に支払うな」という問題である
- 「後で直すと高くつきすぎる」という反論があっても、その高価な改修自体がまた1つの予測である可能性がある
コード生成が安くなってもYAGNIは残る
- 2つのコストのどちらにも、コードをタイピングするコストは含まれていない
- コードを書くコストがほぼゼロに近づくと、「コードが安くなったのだから事前に作ってもよいのではないか」という節約型のYAGNI解釈は崩れる
- しかしYAGNIは節約ルールではないため、安価なコード生成はYAGNIを廃棄させない
- 選択権コストは努力の量ではなく、未来の選択肢を閉じるコミットから生じる
- NPVコストは生産価格ではなく、キャッシュフローのタイミングから生じる
- 無料の生成はYAGNIを弱めるのではなく、むしろ推測ベースのフレームワークをより簡単に作れるようにする
- 生成された構造は依然として2つのコストを生み出し、自分で書いていないため理解度はさらに低い可能性がある
- 結論は「コードが高いから待て」ではなく、選択権とお金は使っていないときの方が価値があるので、必要なときに作れということである
1件のコメント
Hacker News の意見
構造変更のコストも下がったと思う
AI のおかげで、構造変更の前にテストで動作を補強するコストが下がり、無停止マイグレーションの実装コストも下がった
Rust が注目された大きな理由の一つも、AI 以前からアプリケーション内部の構造変更コストが低い点にあり、今ではなおさらそうだ
安全に構造を変えられないことによる機会費用は大きく上がっており、今はコードとプロダクトの大きな部分を素早く安全に変えられる能力を最優先で最適化している
ただし AI 以前は構造変更にはるかに時間がかかったので、今最適化しようとしている対象の価値はむしろ下がったとも見られる
依然として価値はあるが、以前より少し低いかもしれない
壊れやすい AI 生成テストが増えることで、構造変更のコストは以前より大きくなっている
テスト群を整理して問題の本質を検証し、偶然の設計判断を検証しないようにする作業は、AI がまだ得意ではない
だが、そうせずにざっくり 75% ほどの出来の脆弱なテスト群を手に入れるのも簡単すぎる
「人間が書いた、平凡で脆弱なテストがいくつか」から「AI が書いた、平凡で脆弱なテストが大量に」へ進むことを客観的な改善と見なし、それで満足する人は多い
ツールをこのように活用することには全面的に同意するが、だからといって早すぎる段階で誤った砂上の楼閣を築く心配をしなくてよいとは言いにくい
リファクタリングに耐える完全なテスト契約を設計するのは、今でもかなり難しい
古いものがまた新しいもののように戻ってきたわけだ
DDD やクリーンアーキテクチャのようなアプローチのコンテキスト効率からこうした項目まで、AI は新しいトレードオフを作るのではなく、増幅器のように機能する
きちんとやるチームの生産性を高める一方で、設計やアーキテクチャの品質基準が低いチームの負債も増やす
得られるのは、深く考えなくてよいという点だけだ
深く考えるのにそれほど多くの時間や労力がかかるわけではないので、同じように AI を活用しつつも、無駄撃ちにならない程度には考える人たちに負けるだろう
Kent Beck は、まだ書いていないコードを特定の価格で買える金融オプションになぞらえている
しかしそれはあくまで比喩であり、あまり遠くまで引っ張るとおかしくなる
コードをまったく書いていなければ選択肢は無限なのか? まだ時間を使っていないとしても、それは正しくないように見える
何も確定しないために計画段階にとどまり、コードを書くことを無期限に先延ばしする根拠にもなり得る
それでもこの比喩が機能するなら、コストはコードを読むことにあるのかもしれない
書かれていないコードは読む必要がなく、コーディングエージェントを使うなら、無関係な細部でコンテキストを乱すこともない
まだ書いていないコードはテストする必要もなく、まだ書いていないテストには実行時間もかからない
だからプロジェクトはできるだけ小さく保つのがよく、機能を先送りすればコードベースの成長を最大限遅らせられる
他人のコードを実行すれば多くのコストを避けられる、という意味でもある
標準 API を使えるなら、実装を詳しく理解したりそのテストを実行したりする必要はないが、依存関係を追加することにはリスクがある
書かれていないコードには価値がない
今日書かれるコードが価値を生むには、今日のリクエストや issue を解決するか、明日何かをより簡単にできる方向に傾いていなければならない
ハック的な解決策で技術的負債を抱えたり、YAGNI に反するものに時間を浪費したりすれば、価値は生まれない
重要なのは書かれていないコードではなく、これから書くコードとその目的だ
今日のチケットや ToDo を解決することと、将来の自分の足を撃たないことの間で、正しいトレードオフをしなければならない
コードを書くことは約束であり、今日の価値は見えるが、明日の価値は推定に近い
それでも後で支払うコストは常にあるので、何が必要になるかを予想してコストを最小化しようと見積もることになる
AI 時代のベストプラクティスが十分に強調されていないと思うが、Kent が完全に見落としている部分がある
必要な機能が何かをより早く見極めることには相当な価値がある
推測に基づく構造を作ることが、要件を確定させる強制装置になり得るし、少なくとも失敗の様相を見せ始める
待つより高くつく場合があるので、ほとんどの要件でそうすべきではないが、時には最善の選択になり得る
間違ったものを作るコストは今やはるかに低くなっており、そのため YAGNI をめぐる計算も変わる
それでも計算はなお必要であり、今は各チームが自分たちにとってどう変わったのかを自ら把握する必要がある
捨てないなら、それは汚い成果物を作る強制装置になる
YAGNI は、現在の要件にないものを、後で要件が変わると予想して作る問題だ
現在の要件と制約を具体化することとは違う
そうしたものは主に、ステークホルダー・ユーザー・顧客との対話、リソース、工学上の制約と能力から出てくる
プロトタイプは、ステークホルダーと対話したり、プロジェクト管理モデルを作ったり、工学研究をしたりするときに価値がある
それ以外では順序が逆だ
稼働中のソフトウェアを資産と見るアプローチは正しい
ただし、稼働させて作り直すコストは大きく下がった
下がっていないコストは、予測可能な結果に対する信頼の連鎖を壊すコストだ
稼働中のソフトウェアの特定バージョンは信頼を蓄積してきており、ゼロから書き直すとリリース時にその資本がリセットされる
ある時点から考えが変わった
具体物を YAGNI として先送りし、できるだけ抽象的なバージョンを書くようにした
UserStore を作るべきか? それが一番単純に見えるが、特定の User という形が必要ないかもしれない
そこで、保存可能なものなら何でも入れられる Store を作る
慣れていないと過剰設計やジェネリクスまみれに見えるが、逆説的には、どんな具体実装にも最も少なくしか約束しないやり方である
おそらく不要だった UserStore インターフェースを作っただけでなく、確実に不要だった汎用化された Store 抽象化まで作ったことになる
具体実装に約束しないために、不要で、今後も不要である可能性が高い粘着的なレイヤーを実装したわけだ
実際の必要性に基づかない抽象化なら、後で必要になったとしても、ほぼ間違ったものを作っていた可能性が高い
結局 UserStore は必要になるのだから、それを先に作るべきだった
「より鋭いアーキテクトなら避けられる、という意味で予測が難しいと言っているのではない」には同意しない
この主張は、予測が難しいという前提があって初めて成り立つ
可能性が非常に高い機能の足場をあらかじめ作っておき、すべてが噛み合えばより早くリリースできる
チームが必ず大きくなる、あるいは人員が維持される保証もないので、締め切り直前に YAGNI に合わせようと慌てるより、節制を自賛するほうが悪く感じる
最近、YAGNI が大量に積み上がったコードベースから機能的に抜け出す必要があったが、エージェントがあってもものすごい作業だった
分散システムで、何が本当に使われているのかをどうやって知ればいいのか? 私が見落としたものも、エージェントが見落としたものもあり、全体として必要以上に時間がかかった
単純に 1:1 でポーティングしたわけでもなく、単純化の機会にしたため、旧システムがどう動作するのかを完全に理解する必要があった
実際にはまったく使われていなかったものも、そう識別できなければ理解対象に含まれた
結局、問題を探索し、解決策を実装することに帰着するのだと思う
間違った問題を解くことには常にコストがあり、必要でもないものに悪い解決策を実装するコストもある
ソフトウェア開発は、ときに探索すべき戦略や問題の集合を考える代わりに、単純な試行錯誤へ流れてしまうことがある
必要以上に特定の方向へ問題を深く探索することが長期的に役立つ場合はあるが、目的もなく解決策を実装するのは決して良くない
Kent Beck が本当に批判しているのは、将来必要になるかもしれないという理由で「念のため」に何かを実装する態度だと思う
「機能が来る前に構造を作ると、推測に約束することになる」と言っていたが、どちらにせよ推測はしていると思う
その機能が来る可能性は高いかもしれないが、確実ではない
今構造を作らなければリファクタリングのコストがあり、早すぎる段階で作ったのに機能が来なければ労力を無駄にする
それらの可能性の間にあるコスト、確率、トレードオフは何か? 当然、状況によって異なる
YAGNI 全体が意図的に大きな一般化である
結局は事情次第だ
どちらにせよ、推測と身ぶり手ぶりの説明で満ちていることが多く、信頼できる作業見積もりと同じような問題である
不確実な世界にうまく耐えられない一部の開発者は、あらゆるものに白黒のルールを探そうとする
https://www.sebastiansylvan.com/post/the-perils-of-future-co...
要約すると YAGNI 側に立っている
Kent Beck の記事で、チップ企業に役立ちそうな内容を見たことがない
チップ企業では多くの人が長期間働く必要があり、顧客は完成するまで何も見ることができず、収益を上げるには数百万個単位で売らなければならない
ハードウェアには強い制約がある
そもそもソフトウェアが発明された理由も、まさにそうした制約から抜け出すためだった
多くのチップ企業が進行中の作業を共有しないのは確かだが、シミュレーション、プロトタイプ、エンジニアリングサンプルを共有することは可能で、実際にも行われている
もちろん通常は大口顧客である必要がある
変更コストが比較的小さい業界の洞察は、変更コストが大きい業界には簡単には適用できず、その逆もしばしば同様である
チップ企業はそうしたプロジェクトをどのように計画しているのだろう? アジャイル、ウォーターフォール、それともソフトウェア業界とは別のフレームワークを使うのだろうか?