バージョン管理

『Google のソフトウェアエンジニアリング』第16章を要約したもの。本文の引用はしていない。 書籍由来の主張には (書籍16章) のように出典を付けている。

モノリポの論文 PDF が同ディレクトリの google-monorepo.pdf にある (CACM 2016, Potvin & Levenberg。公開されている論文)。

何を解いている道具なのか (書籍16.1)

VCS は、複数人が同じファイル群に同時に作業できるようにして活動を協調させる道具。 中核にあるのは、「どちらがより最近のものか」という問いを消すこと。 これが曖昧になった瞬間に、作業の上書き合いという厄介な問題が発生する。

得られるもの。

取り消せる
複数の開発者間、あるいは1人の別々の時点間で整合性が取れる
どの変更セットが適用済みかの追跡という、間違いを起こしやすい操作が自動化される
全行への全変更の正式な記録が残る(監査要件を満たす手段にもなる)
コード全行の起源と発祥を追跡できる

単一バージョン原則 (書籍16.3)

この章で最も重要な原則。リポジトリ内の各依存関係について、選ぶべきバージョンは1つだけ。

言い換えると、開発者に「このコンポーネントのどのバージョンに依存するか」という選択の余地を与えない。 選択の余地を残すと、マージ戦略の議論、ダイアモンド依存、無駄な作業、労力の浪費に直結する。

モノリポ (書籍16.4)

モノリポの最大の利点は、単一バージョンルールを守るのが自明なほど簡単になること。 どのバージョンが正式かを決めるプロセスも、どのリポジトリが重要かを探すプロセスも存在しなくなる。

副次的に、他の全員がやっていることが見えるようになり、 自分の設計上の選択を他者に伝える手段にもなる。

ただし書籍の結論はモノリポ推しではない。 重要なのはモノリポかどうかではなく、単一バージョン原則をできるだけ守ること。

判断基準として書かれているのは、要件が揃っているかどうか。 組織内の全プロジェクトに同じ機密・法律・プライバシー・セキュリティの要件があるなら真のモノリポでよい。 そうでないなら、モノリポの機能性は目指しつつ、実装方式は変えてよい。

技術的な制約が本丸

モノリポへの反対論のほとんどは、思想ではなく単一の巨大リポジトリの技術的制約を指している。

  • Git は数百万コミット後にパフォーマンス問題が出やすく、大きなバイナリを含むとクローンが遅くなる
  • クローンが速く安いほど、開発者は変更を小さく分離した状態に保つ (間違った作業ブランチにコミットする事故も減る)
  • 逆にクローンに何時間もかかるなら、組織がその依存を敬遠するのは当然

Git 側の主要な改善はこの方向に向いている。shallow clone(最新コミットだけ取る)、 sparse checkout(全体ではなく一部だけローカルに展開)など。

社内であれば、コンピュートリソースの可用性・協調・ある程度の中央集権的な権力を前提にできる。 細粒度リポジトリを連合させたバーチャルモノリポなら、 単一バージョンルールを守りつつ、実験的・極秘のプロジェクトを分離できる。

ブランチ戦略

トランクベース開発(リポジトリ1個、開発ブランチなし)が最もスケールする。 (書籍16章)

DORA も、トランクベース開発とパフォーマンスの高いソフトウェア組織の間に予測可能性があると指摘している。 大規模変更を行う場合ほど、トランクベースの重要性が増す。

開発ブランチをなぜ使わないか (書籍16.2.2)

開発ブランチが解こうとしている問題(製品の不安定さ)自体は真っ当な問題。 ただしその解き方が見当違い、というのが書籍の立場。

同じ問題は、テスト・CI・徹底したコードレビューの3つを広く使う方がはるかにうまく解ける。

理由は単純で、小さなマージは大きなマージより容易だから。 長期間分離されたブランチが複数あると、マージ操作の協調コストがトランクベースより著しく高くなる。 大きなマージのたびに再同期と再テストが必要になる。

中毒の構造も書かれている。チームが他の開発中ブランチを土台にして新しいブランチを切り始める。 そのブランチが主要開発ブランチと定期的に同期されているとは限らない。 唯一の「信頼できる情報源」が存在しなくなる。

未完成のものをどうトランクに置くか (書籍16.3.4)

作業はトランクに対する小さくインクリメンタルな増分として定期的にコミットする。 準備できていない機能の扱い方は2つ。

  • 実行時に無効化した状態でコミットし、可能なら可視性ポリシーで他の開発者から隠す
  • 新旧2つの選択肢が同じプログラムにリンクされても共存できるように設計する

Google のモノリポで作業する約1,000チームのうち、開発ブランチを持つのは2〜3チームだけ。 しかもそれは、単一バージョンでは足りず 古いクライアントが新しいサーバーで動くことを約束しなければならないような特殊事情のため。

書籍はここで一般則を出している。 時間をまたぐ依存関係は、どんな形式であれ、時間が経っても不変なコードよりはるかに高コストで複雑。 だから本番サービスがその種の約束をする範囲は狭く保ち、 本番ジョブは最長でも6ヶ月ごとに再ビルド・再デプロイする。

リリースブランチ (書籍16.2.3, 16.3.5)

判断はリリース間隔で決まる。

状況判断
リリース間隔が数時間より長いリリースビルドに入ったコードを正確に表すリリースブランチを作るのは筋が通る。致命的な欠陥はトランクからチェリーピックする
1日に何度もトランクからリリースできる(継続的デプロイ)リリースブランチは要らない。 直して再デプロイする方が簡単で、チェリーピックとブランチは余計なオーバーヘッド

書籍の観察では、最もうまく回っている技術組織にリリースブランチはほぼ存在しない。 一方で、月次リリースをしながら次のリリースに向けて作業を進めるなら、リリースブランチは完璧に筋が通る。 書籍も、リリースブランチによる広範囲のコストは経験上なかったと書いている。

いずれにせよ、複数ブランチの利用は生産性の足かせになるという前提は共通。

関連