可能なかぎり最も単純なことをせよ
(seangoedecke.com)- ソフトウェア設計では、常に「可能なかぎり最も単純なこと」を選ぶのが効果的な助言である
- 優れた システム設計 は大げさには見えず、実際には最小限の構成要素だけで問題を解決する
- 単純な解決策を追求する際には、新しい要件が生じたときにのみ段階的に拡張していく YAGNI(You Aren't Gonna Need It) 原則を中核となる設計思想にできる
- 「単純さ」の定義には議論があるが、コンポーネント数が少なく、内部結合が疎で、安定したシステム が最も単純さに近い
- 過度なスケーラビリティ への執着はコードベースの柔軟性を損なうため、実際の要件に忠実な単純な設計のほうが長期的には有利である
可能なかぎり最も単純なことの追求
ソフトウェアシステムを設計するときは、「可能なかぎり最も単純なこと」をするのが重要である。このアプローチは、バグ修正、既存システムの保守、新しいアーキテクチャ設計など、ほぼあらゆる場面に適用できる。多くのエンジニアは、「理想的な」システム、つまり、よく整理され、ほとんど無限に拡張可能で、きれいに分散された構造を夢見るが、実際には現行システムを深く理解したうえで最も簡単な解決策を選ぶほうが効果的である。
単純さは過小評価されている
- システム設計には、アプリサーバー、プロキシ、データベース、キャッシュ、キューなど、さまざまなツールを使いこなす力が必要である
- ジュニアエンジニアほど複数の技術を使って複雑な構造を作りたがるが、本当の熟練とは、むしろ不要なものを削ることにある
- 優れたソフトウェア設計は地味に見え、むしろ問題を思ったより簡単に解けるという印象を与える
- たとえば、Unicorn と Rails REST API は Unix の基本機能を活用し、最小限の構造 で中核的な保証(隔離、拡張、復旧など)を実現しており、設計として優れている
単純に実装するための考え方
- たとえば Golang アプリケーションに rate limiting 機能を追加するとき、Redis のような外部ストレージを使うこともできるが、本当に必要でない限り、メモリ内カウント のような、より単純な方法をまず試せる
- 単純な方法で十分なら、重いインフラの追加は先送りできる
- 実際に新しい要件が現れたときにのみシステムを拡張する 段階的な開発の展開 が可能になる
- これは YAGNI 原則を設計の最優先に置くアプローチである
単純さの落とし穴と現実的な限界
1. Big Ball of Mud 現象
- あらゆる要求にその場で対応していると、複雑で保守しにくい「泥の塊(big ball of mud)」なコードベースに陥る危険がある
- しかし、その場しのぎの修正(hack)は単純さではなく、むしろ理解と保守にさらなる複雑さをもたらす
- 本当に単純な解決策を見つけるには、多くの方法を比較し、実際に 体系的なエンジニアリング を行わなければならない
2. 単純さの定義
- 「単純さ」が何を意味するのかについて合意するのは簡単ではない
- 一般に単純なシステムは、可動部分(動作要素) が少なく、コンポーネント間の結合が疎 で、インターフェースが明確 である
- 実例として、Unix プロセスと Unicorn はメモリを共有しないため単純性が高く、Puma や Redis と比べても内部の結合性が低い
- 選択が曖昧なときは、より少ない保守で済むほうが単純 だと考える
3. スケーラビリティへの執着への批判
- 「単純な方法」は大規模トラフィックには適さないかもしれない
- しかし、将来の急激な規模拡大に合わせてあらかじめ複雑に設計するのは、たいてい無駄な努力である
- ほとんどのコードは実際には 2〜5 倍程度のトラフィック増に備えれば十分であり、それ以上は実際に問題が起きたときに対応するのが合理的である
- 過度にスケーラビリティ中心の設計はコードの柔軟性を損なう。必要以上の構造分割は特定機能の実装をかえって難しくし、複雑なトランザクション管理まで要求しかねない
結論
- 時間がたつほど、システムの将来要件を予測する能力には悲観的になる
- 実務では、現在のシステム状態を正確に把握するだけでも十分に難しく、これが良い設計を妨げる主な問題である
- ソフトウェア開発には大きく二つのやり方がある
- 将来の要件を予測して設計するやり方
- 現在の要件に忠実に、可能なかぎり最も単純なこと を繰り返すやり方
- 後者のほうが実際には効果的であり、YAGNI と単純さを重視する考え方が長期的によい設計を生む
付録: Hacker News の議論と用語の出典
- アーキテクチャの単純さは規模が大きくなるほど意味を失うという意見に対して、著者はむしろ大規模であるほど 単純な構造がいっそう重要 だと主張している(機能間相互作用の複雑さに備えるため)
- 「Do the simplest thing that could possibly work」という表現は Ward Cunningham と Kent Beck が作った
1件のコメント
Hacker Newsの意見
このアプローチは単純なドメインではうまく機能しうると思う。だが大手テック企業で長く働いたあとでも、求められる複雑さにはいつも驚かされる。最も単純なビジネス上の問題でさえ解決に1年以上かかったり、無数のエッジケースやスケールの問題でしばしば壊れたりする。単純さを叫ぶ人は、大規模な経験がなかったのだろう。10年物のコードベースを見ても、考慮すべきことが多すぎて、リライトもよく失敗する。Chesterton's Fenceのたとえのように、何かが存在する理由を知らないなら、むやみに取り除かない知恵が必要だ
これはソフトウェアエンジニア同士のコミュニケーション不足から生じる典型的な誤解だと思う。記事タイトルのように「可能な限り最も単純なこと」をしろという意味だ。複雑な問題に複雑さは避けられないが、不必要にさらに複雑にしてしまうミスに気をつけろということだ。複雑さを完全に避けろという話ではなく、過剰に複雑にしてしまう習慣を警戒すべきだということだ
指摘の通り、その複雑さはドメイン自体のせいではないかもしれない。ソフトウェア設計のまずさから生じた問題かもしれない。依存関係と副作用だらけなら、関心の分離や結合度の管理ができていないということだ。リファクタリングはほとんど不可能になり、組織文化が改善されなければ、リファクタの途中で新たな問題が継ぎ足されるだけになる。それでも、関心の分離と単純な組み合わせだけで複雑な問題を解決することはできる。難しくはあるが、シニア開発者がこうした視点をしっかり持つほど成功しやすくなる
筆者がGitHubのスタッフエンジニアだと述べられている点からして、この人にも十分に大規模システムの経験があると思う
レガシーシステムはエッジに存在する。実際のシステムでも、多次元空間で次元が増えるほど点が境界面に集まるように、実ユーザーもシステムの限界付近で大半の作業をしている。そうしたあらゆるエッジを最適に受け止めているのが、結局は既存の古いシステムだ
前職では、複雑さのかなりの部分が、失敗したり、途中で放棄されたり、未完成のままになったリファクタリングや改善の試みから来ていた。こうしたものを初期の段階で防げていたら、もっと単純なシステムを引き継げたのだろうかとよく思った。リファクタや改善を一切するなという話ではなく、確実に100%のユースケースをカバーするよう計画し、予算とマイルストーンを確保したうえで、段階的に改善されることを保証すべきだと思う
「可能な限り最も単純なこと」という表現の起源を、ぜひ明らかにしてほしかった。このフレーズは、Wikiの発明者Ward CunninghamとKent Beckが一緒に仕事をしていた80年代後半によく使っていた原則だ。2人はコーディングしながら互いにこの原則を何度も思い出させ、その後の発表や執筆でも重要なテーマになった。閉じたドアの例のように、一見単純に見えても状況によってその「単純さ」は異なる、という点にこの記事でも触れている。単純な解決策を見つけること自体が、常に単純とは限らないということだ。このやり方が技術的負債を残しうるという自覚もあったが、とにかくまずコードを動かすことが優先だった。個人的には、今回の記事でも技術的負債の側面がもう少し語られてほしかったと思う
Kent Beckはその後、Extreme Programmingを体系化した。この方法論は、要件が変わるたびに単純なシステムが自然に進化できるよう支える実践の集まりだ
この表現を同僚から聞いて、人生のモットーのように使っている人がいるのは知っていたが、Ward Cunninghamが元祖だとは知らなかった。あまりに広く使われているので、原作者を誰も知らないくらいなのが最高の栄誉なのかもしれない
Wikiへの言及が興味深かった。以前の職場ではLotus Notesでプロジェクトを管理していたが、文書がいつ変更されたかを基本的にハイライトしてくれて便利だった。その次のプロジェクトではWikiだけを使ったが、どの文書が変わったのか一目で分からず、実質的に役に立たなくなった。単純ではあったが、単純すぎてかえって実用性が落ちていた
「動く」の定義については、キャリアを通じて最も議論になってきた。「動くからといって壊れていないわけではない」という言葉は、自分で何かを直したことがある人には直感的に響く。修理工は壊れた道具でだましだまし直しているうちに結局交換しようと決めるが、開発者は「直すべきだ」という必要性をあまり感じないように思える
自分のキャリアで最もつらかった時期は、プロトタイプ好きのチームがいた会社だった。そのチームは素早く概念実証だけ作り、役員にデモをしてすぐデプロイした。すると役員たちは「こんなに早くできたなら、すぐ本番投入できる」と勘違いした。その後、担当チームがコードを開いてみると、エンドツーエンドのセキュリティ、検証、エラー処理など、必須のものがすべて欠けていた。結局最初から作り直すしかなく、役員たちはデプロイ担当チームが無駄に複雑にしているのだと誤解していた
「プログラムが動くだけでは十分ではない。正しい理由で動かなければならない」という印象的な引用をどこかで見たことがある。本質的には同じメッセージだ
こうした会話は職業上とても重要な部分だ。あるシステムが望ましい出力を出せるという意味では「動く」と言えるが、信頼性やコストの面では依然として失敗していると見なせる場合もある
自分の担当業務における「動く」の定義は、雇用主がリソース、自分の時間をどこに投じるかによって変わる。品質向上に時間を使ってよい状況なら最善を尽くす。逆に、単に目標達成やチェックリスト消化だけを求められるなら、それに合わせて働く。結局、測るものどおりの結果になると思うので、助言はできても決定権は自分にはない
こういう助言の皮肉は、実際にうまく適用できる人は、すでに経験豊富な専門家だという点だ。たとえば「最も単純なもの」が何かをどう知るのか、それが本当に機能するかをどう判断するのか。最近、自作のXLSXインポーターでXML名前空間処理のミスを経験した。実際にはExcelが常にデフォルト名前空間しか使わないと仮定していたため問題が起きた。後で別の名前空間を使ったファイルを受け取ったら即座に壊れた。接頭辞だけ取り除いて処理すれば単純かもしれないが、将来の自分のために4時間かけてパーサ全体を名前空間フレンドリーに書き直した。「最も単純なこと」をするのは実際にはそう簡単ではなく、経験が多いほど少しはうまく判断できる。でも、それだけ経験があるなら、こうした助言自体が不要だとも思う
こうした助言が適用しにくい理由について、本文でも触れられていたと思う。「最も単純な解決策を見つけるには複数のアプローチを検討する必要があり、結局はエンジニアリング的な思考が必要だ」という点が核心だ
うちの会社では「間違った方向にコードを足さない」という原則を置いている。部分実装であっても、後で発展させやすい方向にだけコーディングする。KISSだが、安易なハックは決して許さない
自分は「移行が最も容易なもの」を基準に単純さを判断している。複雑な抽象化やインフラに依存しない単一サービスは、結局移行しやすい。読む人がすぐ理解でき、引き継ぎやデバッグもしやすい。ただし抽象化が必要なときは必ず入れ、インフラが本当に必要なときは追加する。重要なのは、コードを引き渡すときに最も説明しやすい構造かを常に考えることだ。以前は、できる限り全体を抽象化し、サービスごとに分割し、設定駆動にして、コードがほとんどない形を目指していたが、実際には移行も引き継ぎも完全に失敗した。今は、本当に必要なときだけ構造を複雑にし、基本は直感的な単純さを保っている。これが結局、新しい人のオンボーディングやバグ修正、実際の移行すべてに利益をもたらす
AI vibecodingも似ている。経験とノウハウが増えるほど、適したタスクの選定やエージェント管理がしやすくなる
「最も単純なこと」が安易なハックや場当たり的な応急処置ではない、という点を多くの人が見落としている気がする。単純な方法であるほど、実はより多くの検討とシステム理解が必要で、記事の冒頭で言っていたのもその点だ。多くの人はタイトルだけ見て自分の不満をぶつけたように見える
一般に、この種の原則や強い主張を聞いた瞬間に警戒心が生まれる。ソフトウェア開発に何か普遍的な正解があるかのように語る人は、実際にはよく分かっていないことが多い。本当に経験豊富な開発者の結論は、ソフトウェアは難しく慎重さが必要だということだ。万能の答えなど決してない。開かれた思考と配慮が必要だ
単純さ、つまり複雑さの反対は、ソフトウェア設計の代替案を比較するとき、ほとんど最優先の基準だ。なぜなら結局、人が企画し、合意し、実装し、保守しなければならないからだ。しかし単純さを判断するのはあまりにも難しく、業界平均のエンジニアにはこの判断を信頼できない。しかも「単純さ」という主張自体が、意味の薄い流行語のように広がってしまい、まともな主張に対して「こっちのほうが単純だ」と反論するためだけに使われる場面も多い。チームリーダーがこうした問題をうまく見抜くべきだが、リーダーの力量が信頼できないほど低くなってきていて、なおさら難しい
記事にも印象的な一節があった。本当の達人は「足すこと」ではなく「減らすこと」を知っていて、初心者は動きが多く派手だが、達人は少なく動いて決定的な一撃だけを使う、というような話だ
この記事を読んで最初は少しいら立ちもしたが、「ハック」は別の複雑さを追加するだけなので、試行錯誤の本質をよく突いていると思った。問題は、こうした原則が経営陣の命令のように過剰適用されると、複雑な問題に単純すぎる対応をしてしまい、知識移転もしにくく、あとでさらに複雑な後始末だけが残ることだ。逆に、必要以上に複雑になる理由は、継ぎはぎの即興対応やハックに長く縛られたあと、一気に片づけようとして今度はやりすぎてしまうことにある。結局、開発者は会議に積極的に関与し、最初から賢明な決定へ導くべきだ
自分は、これが警告灯レベルだとまでは思わない。不必要な複雑さは日々増えていくので、単純さを守ろうと主張する必要は確実にある。デザイナー、プロダクトマネージャー、さらには顧客やアーキテクトまで、本能的に複雑さを加えようとするからだ
あなたの主張にも共感するが、結局は「すべてはトレードオフ」あるいは「うまい話はない」という結論に帰着する点にも注目したい。どんな一般論も現場経験の集積なのだから、完全に捨てることはできない。問題は、実用的なコンセプトがある時点から過剰な風評や宗教のように変質し、フォルダ名の議論だけが残るような場合だ
スタートアップ、Seed〜Series Cで0→1のシステムをいくつも作る中で身についた原則がある。「単純さは堅牢さだ」というものだ。初期設計でも既存システムの改善でも、過剰設計に陥りやすい。顧客要求は絶えず進化し、将来の要求を予測しても結局は外れる。単純さは単にエラーを減らすだけでなく、構造を容易に変えられる土台になると思う。可能なX、Y、Zを用意しつつも、将来の拡張性と余地を残すために「最も単純なもの」を作る方向を目指す。複雑さは必然的に制約を増やし、時間とともに積み重なるほどスタックは弱くなる
「理想的なシステム」を設計しようとする試みをある程度やってみてこそ、結局「最も単純なもの」にたどり着けるのだと思う。読みやすく、変えやすいシステムを作るにも多くのノウハウが必要だ。本当に「単純な」改善も、経験と深い理解から生まれるのだと思う
Gall's lawと同じ文脈だ。この理論によれば、うまく機能する複雑なシステムは、常に単純なシステムから始まり、徐々に複雑さが追加されたものだ。最初から複雑に作られたシステムはうまくいかない。だから最も単純なシステムをまず作り、要件に合わせて少しずつ複雑さを足していくべきだ
記事の趣旨には同意するが、クラウドインフラの登場で「単純さ」の定義は変わったと思う。以前は「単純だがスケーラブルではないもの」対「複雑だがスケーラブルなもの」という構図だったが、今はそうではない。インメモリのrate-limitingソリューションはシングルサーバーでは単純かもしれないが、サーバーが2台になっただけで即座に分散状態の問題になる。一方で、DynamoDBやElastiCacheのようなmanaged serviceは、単一ノードでも1000台でも単一の真実の源泉となり、複雑さを大きく減らしてくれる。「単純なシステムは堅牢だ」という観点から見れば、managedサービスを使うほうが、より根本的に単純だと言える。データ損失や分散状態管理のような繰り返し出る問題を消してくれるからだ。いまや「最も単純なもの」の定義は、自前で管理しないmanaged serviceをうまく活用することへ変わってきたように思う。今どきは外部依存を避けることより、隔離された検証済みシステムを効果的にレバレッジして複雑さを最小化するほうが、むしろ時間とコストを節約すると考えている
「可能な限り単純に、しかしそれ以上に単純にしすぎるな」という名言に共感する。いつもこの原則に従おうとしているが、最新技術をよく知らないせいで不要な複雑さを見逃しているのか、それともみんなが不要な複雑さに陥っているのか、いつも悩む。実プロジェクトで直接使ってみなければ本当に使い物になるか学びにくいし、逆に自分の学習のためだけに最新ツールを実戦へ無理に入れるのは、チームにも迷惑をかけると見てきた
似たような悪夢を体験している。常に最新ソフトウェアに関心の強い上司のせいで、意味があるか分からないツールを実運用向けに検討しなければならない。成果と関係なく、毎週そうした調査を続けろと言われるので負担だ
実際には、まず最も簡単な方法で動かしてみて、必要なら手作業でもよく、必要な瞬間が来たときだけ全機能を追加するのが正しいと思う。最初にすべてを自動化したりツール化したりして無駄に時間を使ったとしても、後になってなぜ必要なのかが明確に分かったという経験のほうが重要だ
この感覚はとてもよく分かる。自分もこういう文章にはいつも共感し、単純さを実践しようと努力するが、それが本当に賢明さと実用性なのか、それとも単に経験や実力が足りないだけなのか、いつも迷う
これがあるので、「履歴書主導開発」に陥らないよう本当に気をつけるようにしている