# 戦略的プログラミング Navigation: [[index]] | [[concepts/_index]] ## 定義 戦略的プログラミング(strategic programming)とは、プログラミングに取り組む際の心構え(mindset)の一つであり、「動くコード」自体ではなく「優れた設計、その結果として動くコード」を主目標とする投資マインドセットである。これに対置されるのが戦術的プログラミング(tactical programming)で、新機能やバグ修正を「とにかく動かす」ことを最優先し、将来への計画をほとんど考慮しない近視眼的な姿勢を指す。戦術的プログラミングは一つ一つの妥協が合理的に見えても、その蓄積がシステム全体を複雑にする。この姿勢を極端に推し進め、後始末の負担を他の開発者に押し付けながら大量にコードを生産する開発者を、戦術的竜巻(tactical tornado)と呼ぶ。戦略的プログラミングは、システムの長期的な構造を維持するために継続的な小さな投資を積み重ねることを要求し、著者(John Ousterhout)は開発時間の 10〜20% をこの投資に充てることを提案する。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]]) ## 投資の種類と割合 戦略的プログラミングは 2 種類の投資からなる。積極的投資(proactive investment)は、新しいクラスを設計する際に最初に思いついた案をそのまま実装せず複数の代替案を試す、将来の変更を想像してそれが容易にできる設計にする、文書化を丁寧に行うといった、問題が起きる前に行う投資である。消極的投資(reactive investment)は、設計上の問題を発見した際に無視したり場当たり的なパッチで済ませたりせず、その場で少し時間をかけて修正することを指す。著者はウォーターフォール式の巨大な事前設計は有効ではないとし、理想の設計は経験の中で断片的に見えてくるものだと述べたうえで、開発時間の 10〜20% を継続的な投資に充てることを提案する。この割合は初期プロジェクトのスケジュールを大きく損なわない程度に小さく、数ヶ月以内に同程度以上の速度向上として回収される程度に大きい。逆に戦術的に進めた場合は開発速度が徐々に低下し、最終的には少なくとも 10〜20% 遅くなる。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]] §3.2, §3.3) ## スタートアップにおける投資判断 早期リリースへの圧力が強いスタートアップでは、10〜20% の投資すら惜しんで戦術的アプローチに傾きがちである。しかしコードベースがいったんスパゲッティ化するとほぼ修正不可能になり、製品寿命全体にわたって高い開発コストを払うことになる。加えてコードベースの評判が悪化すると優秀なエンジニアの採用が難しくなり、コスト増と品質低下の悪循環を招く。著者は Facebook を戦術的プログラミングを奨励したスタートアップの例として挙げる。Facebook は長年 "Move fast and break things" を標語に掲げ、新卒エンジニアが入社初週から本番へコミットを push するのが普通という文化を持っていたが、コードベースは不安定でコメントやテストが乏しくなり、後に標語を "Move fast with solid infrastructure" へ変更した。一方 Google と VMware は同時期に創業しながら戦略的アプローチを取り、高品質なコードと優れた設計を重視することでシリコンバレーで強力な技術文化として知られるようになった。著者はこの対比から、スタートアップであっても戦略的アプローチで成功できることを示す一方、Facebook のコードが他のスタートアップの平均より特に悪いわけではなく単に目立つ実例に過ぎないとも補足している。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]] §3.4) ## 積極的投資の具体的な手続き: 二度設計する(design it twice) 積極的投資の代表的なプラクティスとして、著者は「design it twice(二度設計する)」という具体的な作業手続きを提示する。重要な設計判断のたびに、最初に思いついた案をそのまま実装するのではなく、根本的に異なる複数の案を出したうえで比較検討する。GUI テキストエディタのテキスト管理クラスを例にとると、行指向・文字指向・文字列(範囲)指向という互いに大きく異なる 3 つのインターフェース案を用意し、各案の主要なメソッドを大まかにスケッチする程度でよい。案は唯一の正解だと確信していてもあえて 2 案目を検討すべきで、悪いと思う案でもその弱点を他案の強みと対比させることに学びがある。 各案を出したら、長所短所を一覧化して比較する。比較の基準は、上位ソフトウェアから見た使いやすさに加え、(1) どちらのインターフェースがより単純か、(2) どちらがより汎用的か、(3) どちらがより効率的な実装を可能にするか、の 3 点である。この比較の結果、最良の選択が元の案のいずれかであることもあれば、複数案の特徴を組み合わせた、どの原案よりも優れた新しい設計が見えてくることもある。テキストクラスの例では、行指向・文字指向のどちらも上位ソフトウェアに余分なテキスト操作を強いるという共通の弱点から、範囲指向 API というどちらでもない着地点が導かれる。 この手法はモジュールのインターフェース設計だけでなく実装の設計にも、また小さなクラス単位からユーザーインターフェースの機能選定やシステムの分割判断といった上位レベルの意思決定にも適用できる。ただし着目すべき観点は場面によって異なり、実装の比較では単純さと性能が最も重要になる。二度設計するコストは、小さなモジュールであれば数時間程度で済み、実装に要する数日〜数週間と比べれば小さい。著者は、この手法が賢い人ほど受け入れづらいと述べる。成長過程で最初に思いついた答えだけで良い成績を得てきた賢い人は、2 つ目・3 つ目の案を検討する習慣を持たずに育ちやすく、「賢い人は一発で正解する」という自己像が複数案の検討を妨げる。しかし大規模ソフトウェアの設計は、誰であっても最初の一案だけで正しく仕上げられる領域ではない。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 11 Design it Twice]]) ## 潮流評価への適用: アジャイル開発とテスト駆動開発の場合 第19章は、本書の設計原則を使って既存の開発潮流を評価する応用章であり、戦術的/戦略的プログラミングの対比を具体的な開発プロセス上の実践に当てはめる実例を示す。著者はアジャイル開発のインクリメンタル・イテレーティブな考え方自体は戦略的プログラミングが説く漸進的アプローチと近いと認めつつ、開発者の注意を抽象ではなく機能に向けさせ、汎用的な仕組みの構築を後回しにする一部のアジャイル実践慣行を、投資的アプローチに反し戦術的プログラミングを助長するものとして批判する。著者はこの批判を「開発の増分は機能ではなく抽象であるべきである」という設計原則15(原書 p.154)として一般化する。同じ論理はテスト駆動開発にも向けられる。テスト駆動開発は次のテストを通すためだけに機能を継ぎ足す進め方になりがちで、設計を行う明確なタイミングがなく、著者はこれを「純然たる戦術的プログラミング」と明言して批判する。すなわち第19章は、機能単位の増分を積み重ねる開発プロセスが戦術的プログラミングへ退化しやすいという具体例を、アジャイル開発とテスト駆動開発という2つの広く使われる潮流について示している。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 19 Software Trends]] §19.2, §19.4) ## 横断的知見 - **投資マインドセットの抽象論から具体的な潮流批判への展開**: 第3章は戦略的プログラミングを「積極的投資として最初に思いついた案をそのまま実装しない」という抽象的な心構えとして定義するにとどまるが、第19章はこの心構えを既存の開発潮流(アジャイル開発・テスト駆動開発)への批判という具体的な適用例に展開する。「開発の増分は機能ではなく抽象であるべきである」(設計原則15)という第19章の主張は、機能単位の増分が戦術的プログラミングへ退化しやすいことを名指しし、第3章が定義する投資マインドセットを、どのような開発プロセス上の判断が戦術的退化を招くかという具体的な評価基準へ翻訳している。第11章の「design it twice」が積極的投資を「どう実行するか」という手続きへ翻訳したのに対し、第19章は「どのような既存の実践がこの投資を妨げるか」を診断する評価基準へ翻訳しており、両者は積極的投資という同じ抽象概念を異なる方向(実行手続き / 診断基準)へ具体化した点で対をなす。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]], [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 11 Design it Twice]], [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 19 Software Trends]]) - **積極的投資の抽象的な心構えと具体的な手続きの関係**: 第 3 章は戦略的プログラミングを「最初に思いついた案をそのまま実装しない」という積極的投資の心構え・投資割合(開発時間の 10〜20%)として定義するにとどまり、それをどう実行するかの具体的な作業手続きまでは踏み込まない。第 11 章はこの積極的投資の代表的な実践として、根本的に異なる複数案を出し比較基準(単純さ・汎用性・効率)で比較検討する「design it twice」という具体的な手続きを与える。両者を並べると、第 3 章の投資マインドセットが第 11 章の具体的なプラクティスによって初めて実行可能になるという、抽象(何にどれだけ投資するか)と具体(どう投資を実行するか)の階層関係が見える。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]], [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 11 Design it Twice]]) - **負債の発生源への向き合い方が異なる**: [[技術的負債]]が主に扱う Sculley ほか(2014)の技術的負債の枠組みは、負債が既に発生した状態を前提に、リファクタリングやテストカバレッジ向上といった「返済」手法を論じる。一方、本概念(Ousterhout, 2018)は負債の返済ではなく、戦術的プログラミングという**負債を発生させる振る舞いそのもの**を心構えの選択として問題視し、継続的な小さな投資(開発時間の 10〜20%)によって負債を最初から蓄積させない予防的な姿勢を主眼に置く。両者を並べると、技術的負債の議論が「負債をどう返すか」という事後対応の視点に立つのに対し、戦略的プログラミングの議論は「負債をどう発生させないか」という事前の投資判断の視点に立つという焦点の違いが見える。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]], [[@2014__SE4ML2014__Machine Learning - The High-Interest Credit Card of Technical Debt]]) - **組織的な帰結としての採用への影響という共通点**: 両ソースとも負債・複雑性の蓄積が単なる技術的コストにとどまらず組織的な帰結を伴うと示唆する点で重なる。Ousterhout はコードベースの評判悪化が優秀なエンジニアの採用を難しくし、コスト増と品質低下の悪循環を招くと論じ、Sculley ほかは機械学習システム特有の負債(entanglement・隠れたフィードバックループ等)がシステムレベルの複雑性としてチームの開発速度を蝕むと論じる。両者はともに、負債・複雑性の蓄積が個々のコード片の問題にとどまらず、組織のケイパビリティそのものを損なう点を指摘している。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]], [[@2014__SE4ML2014__Machine Learning - The High-Interest Credit Card of Technical Debt]]) - **結論章による総括: 投資は初期コストを増やすが早期に回収される**: 第 19 章は「本書第 21 章はこの対比を本書全体の結論としてどう総括するか」という問いを残していたが、第 21 章(Conclusion)がこれに答える。第 21 章は、本書が推奨する設計技法(深く汎用的なクラス・エラーの定義的排除・インターフェース文書と実装文書の分離など)を一括りに「投資」と呼び、これらはプロジェクト初期に余分な作業を生む欠点を持つ一方、丁寧に設計したモジュールは再利用のたびに、明快な文書は後の変更時に、それぞれ時間を節約する形ですぐに回収されると総括する。さらに設計スキルを磨く時間そのものも自己投資であり、経験が伸びるほど良い設計をより速く生み出せるようになるため、熟練すれば良い設計と手早く雑な設計の所要時間の差はほとんどなくなるとも述べる。第 3 章が投資割合(開発時間の 10〜20%)というコスト側を、第 21 章がその投資がなぜ・どう回収されるかという便益側を担っており、両者を合わせて初めて戦略的プログラミングの費用対効果の全体像が見える。(Source: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]], [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 21 Conclusion]]) ## 未解決の問い - 著者が提案する「開発時間の 10〜20%」という投資割合は、どのような規模・種類のプロジェクトを念頭に置いた経験則か。実証的な検証は本章では示されていない。 - design it twice は消極的投資(問題発見時にその場で修正する)にも同様の「複数案を出して比較する」手続きが当てはまるのか、それとも消極的投資は別の作業手続きを持つのか。第 11 章では積極的投資の文脈でしか論じられていない。 - 第 19 章は単体テストを支持しテスト駆動開発を批判するが、両者とも「テストを書く」という行為自体は共通する。戦術的/戦略的の分岐点はテストを書くタイミング(コードの前か後か)だけなのか、それともテストの粒度や設計判断が行われるタイミングなど他の要因も関与するのか。第 19 章の議論だけでは切り分けられていない。 - 機械学習システム特有の技術的負債(データ依存性・entanglement)は、Ousterhout の言う「継続的な小さな投資」だけで予防できるか、それとも機械学習固有の追加的な投資が必要か。 ## 関連 - 概念: [[技術的負債]] - ソース: [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 3 Working Code Isn't Enough]] / [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 11 Design it Twice]] / [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 19 Software Trends]] / [[@2018__YaknyamPress__A Philosophy of Software Design - Chapter 21 Conclusion]] - 実体: [[John Ousterhout]] - 関連 MOC: [[structures/Software Engineering - MOC]] ## 出典 - John Ousterhout, *A Philosophy of Software Design*, Yaknyam Press, 2018, Chapter 3: Working Code Isn't Enough. - John Ousterhout, *A Philosophy of Software Design*, Yaknyam Press, 2018, Chapter 11: Design it Twice. - John Ousterhout, *A Philosophy of Software Design*, Yaknyam Press, 2018, Chapter 19: Software Trends. - John Ousterhout, *A Philosophy of Software Design*, Yaknyam Press, 2018, Chapter 21: Conclusion.