/note/tech

Immutable Infrastructure, Immutable Code

要約:

■ 1. イミュータブルインフラストラクチャの原則

  • 2013年にサーバーを廃棄しコードを燃やすというアプローチを提唱
  • 実行中に変異するシステムは状態や履歴や不確実性を蓄積し人間が推論できなくなる
  • 何かが壊れた時に誰もどの変更が原因かシステムが実際に何であるかを知ることができない
  • サーバーにパッチを当てるのではなく置き換えるアプローチに移行
  • 人間の介入なしに同一の動作で再生できる能力こそが重要

■ 2. Wunderlistでの技術選択ルール

  • 誰でも新しい言語やフレームワークを使用できるが以下の条件を満たす必要がある:
    • ビルドシステムと連携すること
    • デプロイメントシステムと連携すること
    • チーム内で少なくとも1人の協力者を見つけサポート体制を確保すること
    • コードサイズを数インチの手のひらサイズに制約すること
  • 最後の制約により新技術がクラッシュしても誰も修正できない場合でも簡単に書き直して置き換えられる
  • コードは細胞のように扱うことができ部分が死んでもシステム全体は残る
  • コードを安価に再生できるならその場でのアップグレードはアンチパターンかもしれない

■ 3. イミュータブルインフラストラクチャが採用された理由

  • エレガントだからではなくミュータブルシステムが診断や再現やロールバックが困難な形で失敗したから
  • スノーフレークサーバーや設定のドリフトや手動修正や誰も再現できない部族的知識などの問題
  • マシンを修正するのではなく置き換えることでシステムをより賢くするのではなくより推論しやすくした
  • 各デプロイメントはクリーンスレートで各アーティファクトは既知のもの
  • 重要な洞察は技術的というより経済的で変異は置き換えよりも速く隠れたコストを蓄積する
  • この洞察は現在アプリケーションコードにも当てはまる

■ 4. コードの編集は変異である

  • コードをその場で編集することは本番サーバーにSSHして設定ファイルを調整するのと同等
  • システムの完全な状態を理解していると仮定している
  • 変更がローカルで履歴が重要でなく副作用が予測可能だと仮定している
  • これらの仮定は常に不安定だったが維持不可能になりつつある
  • 人間やAIまたは両方によってコードがより急速に生成されるにつれ変異率は増加するが理解率は横ばいまたは低下
  • すべてのその場編集はドリフトイベントでありAIはタイムラインを圧縮することでこれを可視化する

■ 5. ミュータブルコードがエントロピーを蓄積する仕組み

  • その場での変更には隠れたコストプロファイルがある
  • 増分編集は意図とそれを生み出した変更のシーケンスを絡み合わせる
  • コードがコードの上に重ねられローカルな修正がグローバルな動作を不明瞭にする
  • 理解するにはコードベースの進化を頭の中で再生する必要があり考古学的作業になる
  • レガシーシステムは年月ではなく変異によって生まれる
  • システムはどこにもエンコードされていない歴史的知識を必要とするようになるとレガシーになる
  • チームはAIで変異が安価に感じられる一方で理解が静かに高価になるためこの失敗モードをより速く再現する
  • 数秒で1000行を生成できるがそれらの行を編集し始めた瞬間に歴史的にしか理解できないアーティファクトを作成する
  • コードの置き換えはこれを完全に回避する

■ 6. フェニックス原則

  • イミュータブルインフラストラクチャを機能させたのはサーバーそのものではなく特性
  • 何かを燃やして人間の介入や組織的記憶なしに同一の動作で再び立ち上がる能力
  • この特性がシステムを大規模に理解可能にする
  • ドキュメンテーションやコードコメントやエンジニアの記憶ではなく仕様から再生する能力
  • コードに適用すると仕様と評価基準からコンポーネントを再生できない場合そのコンポーネントは存在するのに十分に定義されていない
  • これはフィードバックであり火はあなたが実際に知っていたことと思っていただけのことを教える
  • 置き換え優先システムは異なる動作をし各再生は明示的で各デプロイメントは意図的でロールバックは簡単でドリフトは蓄積できない

■ 7. 現在これが機能する理由

  • 歴史的にコードの記述が高価で調整が遅くすべての再テストが苦痛で人間のレビューがボトルネックだったため完全な置き換えを避けていた
  • AIは生成コストを変化させテストは自動化され調整はインターフェースを通じて行われる
  • より深い変化は理解がボトルネックになったこと
  • ソフトウェアエンジニアリングの歴史全体がコードを理解しやすくすることに関するものだった
  • スタイルガイドやデザインパターンやクリーンコードや自己文書化関数はすべて人間が実装を読んで推論することを前提としていた
  • 読み取りが必須だったため可読性のために最適化した
  • イミュータブルコードはこの問題を回避し仕様からコンポーネントを再生できるなら実装の理解はオプション
  • コントラクトやインターフェースや期待される動作を理解する必要があるがどのように達成するかは理解する必要がない
  • 残る高価なものは何が欲しいかを定義することで実装の理解はデバッグ活動であってメンテナンス活動ではない

■ 8. 置き換えで存続するもの

  • コードがイミュータブルなら他の何かが連続性を担う必要がある
  • それはインターフェースやコントラクトや評価やモニタリングやデータ
  • これらが安定した層でありコードはそれらの一時的な表現
  • これはインフラストラクチャを完全に反映しておりAMIよりAPIが重要でコンテナよりコントラクトが重要でサーバーよりサービスが重要
  • 気にかけていたのはマシンではなくマシンが何をするかとそれが正しく動作していることをどう検証できるか
  • ソフトウェアも同じ認識に追いついておりコードは資産ではなく仕様と評価が資産でコードは現在のレンダリング

■ 9. 反論への回答

  • 無駄である:
    • 変異こそが無駄で将来のデバッグやオンボーディングやインシデント対応にコストを隠すだけ
    • 置き換えは境界リスクを持つ明示的なコスト
  • 最適化を失う:
    • 最適化が重要なら制約や不変条件としてエンコードする
    • 正式に表現できないなら実際の価値ではなく偶然だった可能性が高い
  • 組織的知識はどうなる:
    • これが本当の不安でありコードは誰も書き留めなかった決定を体現している
    • しかしこれこそがイミュータブルコードが解決する問題
    • 知識が実装にのみ存在するならそれは知識ではなくリスク
    • 再生は暗黙を明示的にするか本質的ではなかったことを受け入れることを強制する
  • 大規模システムでは機能しない:
    • 大規模システムはすでにインフラストラクチャを常に置き換えている
    • コードが次で困難なのは分解であって置き換えではない
  • 開発者の直感を壊す:
    • コンテナもCIもバージョン管理もローカルな利便性をシステム的明確性と交換するすべての進歩がそうだった

■ 10. 更新されたルール

  • 古いルールはインフラストラクチャをその場でアップグレードしないこと
  • 新しいルールは代わりに再生できるならコードをその場でアップグレードしないこと
  • 本番環境でサーバーにSSHして何かを調整することがまだ可能だが明らかに望ましくないのと同様にコードの編集は最後の手段
  • 再生が失敗したことや仕様が不完全だったことや評価が十分でなかったことの兆候
  • これはデバッグ活動であって開発活動ではない

■ 11. メリット

  • イミュータブルコードは予測可能なデプロイメントや低い認知負荷やクリーンなロールバックや簡単な監査や速い進化や小さな爆発半径をもたらす
  • 本当のメリットは心理的で変更を恐れなくなる
  • レガシーな決定の周りをつま先立ちで歩かなくなる
  • これは何を壊すかではなくこれは評価に合格するかを尋ねるようになる
  • コードは脆弱なアーティファクトではなく再生可能なリソースになる

■ 12. 結論

  • インフラストラクチャはミュータビリティが理解の敵であることを教えた
  • AIは同じレッスンをスタックのより上位で再び教えている
  • AIが生成したコードをその場で編集している場合は設定ドリフトの最悪の時代をより速く追体験している
  • 年ではなく日でレガシーシステムを作成している
  • 燃やして再生し火に耐えたものを信頼せよ