mtx2s’s blog

エンジニアリングをエンジニアリングする。

モノリポとマルチリポの比較が浮き彫りにする開発能力を高めるための課題とトレードオフ

ソフトウェアプロダクトに対して求められ、日々繰り返される機能追加は、コードベースを肥大化・複雑化させ続ける。成長する組織では、開発者の増員がそれを更に加速させるだろう。そして、認知負荷の軽減を目的に、いずれはコードベースの分割について考えるようになる。その目指すアーキテクチャがマイクロサービスにせよ、モジュラモノリスにせよ、コンポーネントやモジュール単位でリポジトリを分けるというのが、コードベースのもっとも一般的な管理方法ではないだろうか。

しかし、ここにはもう1つの選択肢がある。「モノリポ(モノレポ)」だ。すべてのコンポーネント、モジュールを1つのリポジトリで管理する。それどころか、社内のあらゆるソフトウェアプロダクトを1つのリポジトリで管理することさえあり得る。

モノリポにはどのような利点や欠点があるのだろうか。私自身、小規模のマルチプロジェクトリポジトリを複数組み合わせて扱うことが多いが、これは後述するマルチリポだと認識している。モノリポがどういうものであるかの知識があまりなく、採用すべき手法であるかどうかの判断ができない。そこで、Googleのモノリポについて書かれた論文 "Advantages and Disadvantages of a Monolithic Codebase" を読むことにしたのだが、そこで得られたのは、組織の開発能力を高めるための知識や課題であった。

本記事では、モノリポと、その対極にあるマルチリポを比較する中で、組織が獲得し得る開発能力を明らかにしたい。

モノリポとは?

ソフトウェアエンジニアリングにおいて、ソースコードは、VCS(Version Control System, バージョン管理システム)内のリポジトリで管理するのが一般的だろう。「モノリポ(monolithic repo, monorepo)」は、複数のプロジェクトのコードを、同じ1つのリポジトリに格納するソフトウェア開発戦略だ。これに対し、複数のリポジトリに分けて管理する戦略を「マルチリポ(multi-repo)」や「メニーリポ(manyrepo)」、あるいは「ポリリポ(polyrepo)」と呼ぶこともある。

それではマルチプロジェクトのリポジトリがすべてモノリポなのかと言うと、そうではないように思う。明確な定義は分からないが、モノリポと呼ばれるリポジトリには、それぞれが完全に独立した複数のプロジェクトがホストされているのではないか。例えば、マイクロサービスアーキテクチャを構成するサービス群のソースコードを1つのリポジトリで管理するような場合だ。それらは更に細かくサブプロジェクトに分割されてホストされているだろう。また、Googleのように、Google検索、GmailGCP関連サービスといった複数プロダクトのホストもあり得る。

このような背景から、モノリポでは、1つのリポジトリを複数のチームで共有することが多いのではないだろうか。それぞれが所有するプロジェクトを共有リポジトリにホストしているのだ。

一方、マルチリポでは、リポジトリ内が複数プロジェクトであっても、それらを1つのチームやコミュニティが所有する。オープンソースプロジェクトのリポジトリは、マルチプロジェクトのものも多いが、今回取り上げる論文内でもマルチリポに分類されていた。

モノリポと言えば、Googleが採用していることで有名だ。2016年の論文 "Why Google Stores Billions of Lines of Code in a Single Repository" によれば、彼らのモノリポは、調査当時で約20億行のコードを含む86TBのデータが含まれ、Googleの95%の開発者によって使用されていると言うから、その規模にはあらためて驚かされる。

調査

論文 "Advantages and Disadvantages of a Monolithic Codebase" での調査は、Googleでモノリポを利用している開発者を対象に行われた。アンケート調査とログ分析が主な手法であり、前者については23,000人からサンプルとして無作為に選んだ1,902人の開発者のうち、46%にあたる869人から回答が得られた。そのうち、379人(44%)が企業でのマルチリポのコードベースの利用経験があり、337人(39%)がオープンソースでのコードベースの利用経験があり、205人(24%)が他社でのモノリシックなコードベースの利用経験があった。

満足度に対する設問(論文内Table 1のQ1.1, Q2.1)では、Googleのモノリポに対する満足度は全体的に高く、マルチリポに対する満足度は意見が分かれている(論文内Figure 3)。86%にあたる326人は、Googleのモノリポをより好んでいるという点も注目だろう(論文内Table 1のQ2.2に対する回答)。

調査結果の観点は、主に3つに分けることができる。「可視性」「依存関係」「開発者ツール」だ。以降でその内容をそれぞれ見ていく。

可視性

モノリポでは複数のプロジェクトの開発者が互いのコードを共有し、それらを自由に検索・閲覧できるという、高い可視性を持つ。マルチリポ経験者に対する設問(論文内Table 1のQ2.1)で、Googleのモノリポをより好むと回答した開発者は、その理由としてこの「コードベースの可視性(Visibility of codebase)」を多く挙げている(論文内Figure 4)。裏を返せば、回答者らのマルチリポでの経験は、担当するプロダクト領域(PA, Product Area)以外のコードへのアクセスが制限されるケースも多かったのだろう。Googleのモノリポを経験した彼らには、過去に関わったマルチリポでのそのような制限が、欠点として感じられたのだ。

それではコードベースの可視性の高さは、具体的にどのように役立つのだろうか。調査では、コードの「閲覧」と「編集」の2種類に分けてログを分析し、その用途について触れていた。

まず、「コードの閲覧」についての調査結果では、開発者の半数が、閲覧回数の28%以上を担当外のPAにあるファイルに対して行っている(論文内Table 2)。アンケート設問の結果を見ると、その目的が、「コードの再利用(Code Reuse)」や「利用例(Usage Examples)」にあろうことが見て取れる(論文内Figure 4, 5)。「利用例」とは、例えばあるAPIをはじめて利用する時に、既にそれを利用している他のプロジェクト内のコードを見つけ出し、それを参考にして自身のコードを書く、といったことを指している。開発の速さやコードの品質の高さに関する設問(論文内Table 1のQ1.2, Q1.3)でも、多くの開発者が、PAを横断したコードの検索が重要だと回答している点も注目すべきだろう(Figure 1, 2)。

次に、「コードの編集」についての調査結果では、開発者が10%程度が、60%以上のコードのコミットを担当外のPAに対して行っていることがわかる(論文内Table 2)。これは、自身が開発を担当するAPIに変更を加えた時などに、それを利用する他プロジェクトのコードを最新バージョンに対応させる(Easy Update)ために行われているようだ(論文内Figure 4, 5)。

このようなコードの閲覧および編集の自由度がコードの保守性に良い影響を与えることは、DORAのドキュメントでも言及されている。次の引用は、保守性を高める3つの要因のうちの1つとして挙げられていた一文だ。

It’s easy for the team to find examples in the codebase, reuse other people’s code, and change code maintained by other teams if necessary.

(チームにとって、コードベース内から例を探したり、他人のコードを再利用したり、必要に応じて他チームが保守するコードを変更するのが簡単である)

一方で、マルチリポの利点としても「開発の速さ」が挙げられている点が興味深い。しかし、その理由がモノリポとは違った。

マルチリポの利点とする開発の速さには、コードの「サイズの小ささ(Small Size)」や「ビルド時間(Build Time)」の短さが挙げられている(論文内Figure 6)。コードのサイズが小さければ、開発者にとって認知負荷が低い。加えて、ワークスペースへのコードのコピーが短時間で済むし、ビルド時間も短く済む。また、既にビルドされてバイナリ化された依存プロジェクトを取り込めるから、その分、ビルド時間は更に短くなる。

このような、ビルド時間の短縮は、高品質なコードを作り出すためにとても重要な役割を果たす。それは、継続的インテグレーションの文脈で明らかだ。自動テストも含めたビルドパイプラインの実行に一晩かかるのと、数分で終わるのとでは、ビルド失敗時の解決コストの大きさが違うことは、開発者なら理解できるだろう。

また、マルチリポであっても、モノリポのような可視性を実現することが不可能なわけではない。ただし、そこには課題もある。例えば、リポジトリごとの設定によって、コードベースの可視性は簡単に制限されてしまう。そもそも、組織のガバナンスとして不可視に設定しているケースもあるだろう。

逆に、モノリポの実現にも課題はある。特に、コード編集時のコミット権限だ。以前投稿した記事『マイクロソフトの調査にみるコードのオーナーシップと品質の関係』にもあるように、コードの所有権を明確にすることが、品質の高さにつながる。所有者のレビューを経なければ、変更がコードベースに反映されないようにする必要があるということだ。マルチリポであれば、リポジトリごとに所有権を設定しやすいのだが、モノリポではコードベース内のディレクトリごとに所有権を管理するなどの手段が必要となる。組織が採用する開発プラットフォームがそのような権限管理に対応していなければ、実現手段に悩まされることになるだろう。

mtx2s.hatenablog.com

依存関係

Googleのモノリポでは、「トランクベース開発(trunc-based development)」が採用されている。その運用方法として、ブランチは、リリースのために使われるが、ほとんどのケースで開発ブランチを持たない。そのため、開発者によって変更されたコードは、リポジトリのヘッドにコミットされる。

リポジトリ内の依存関係にはバージョンがなく、プロジェクトはリポジトリのヘッドにある依存関係のバージョンを使用する。Googleには、「単一バージョンルール(One-Version Rule)」というものがある。その定義は次のとおりだ(書籍『Googleのソフトウェアエンジニアリング』から引用)。

開発者には、「このコンポーネントのどのバージョンに依存すべきか」についての選択の余地が絶対にあってはならない。

これがダイヤモンド依存関係に対する悩みから開発者を解放する。Googleのモノリポをより好む理由に、この点(Dependency Mgmt)を挙げる開発者も多い(論文内Figure4, 5)。

「ダイヤモンド依存関係(diamond dependency)」とは、プロジェクトが依存するソフトウェアのバージョンが衝突する状況を言う。例えば、プロジェクトがAとBの2つに依存しており、AとBが共にCに依存していたとする。しかし、Aが依存するCのバージョンと、Bが依存するCのバージョンが異なると問題が起きる。これが、ビルドを失敗させたり、実行時エラーを引き起こしたりするからだ。

こういった問題を解決するためには、依存するCのバージョンを統一し、Cの呼び出し元となるAやBのコードをすべて修正することになるが、修正対象がそれぞれ異なるリポジトリにホストされていると、修正の網羅性を担保することが難しくなる。もちろん、リポジトリが分かれているために、1度のコミットですべての変更をコミットすることも不可能だ。

モノリポであれば、コードベース全体の高い可視性によって修正箇所を見つけ出し、すべての変更をアトミックにコミットすることも可能になる。これは、可視性で Easy Update として挙げられた利点でもある。そして、この利点は、モノリポによるコミット範囲の柔軟性によってもたらされることにも気づく。上述した通り、変更が複数のリポジトリに分散すると、それらを1つのコミットにまとめることができない。しかし、モノリポであれば、そのような境界はなくなるのだ。これは、分散システムにおけるトランザクション境界の話にも似ている。このようなコミット範囲の柔軟性も、モノリポの魅力のひとつだろう。

さらに言えば、Easy Update による恩恵は、コミュニケーションコストにも及ぶ。自身が担当するプロジェクトのAPIに変更を加えたとしよう。マルチリポであれば、このAPIに依存するプロジェクトの所有者それぞれに、APIの新バージョンへの対応を促すことになる。しかし、モノリポであれば、APIの変更と同時に、それに依存する他のプロジェクトのコードをすべて修正することも可能になる。これによって、プロジェクト間でのコミュニケーションコストが不要、あるいは最小限にできるという効率性も得られるのだ。

前述したもうひとつの論文 "Why Google Stores Billions of Lines of Code in a Single Repository" でも述べられているように、依存関係の更新は、開発者にとって苦痛でコストの高い作業だ。そのために、更新が後まわしにされ続け、気付けばその対応コストもリスクも高い状況に陥りやすい。Googleのモノリポのように、APIの更新と共に、影響を受けるすべての依存元コードを同時に更新することは、まさに合理的なのだ。

依存関係に関するマルチリポの利点としては、バージョン管理された「安定した依存関係(Stable Dependencies)」が挙げられている(論文内Figure 6)。つまり、バージョン指定による依存関係のセットを持ち、それを組み込んだプロジェクトをビルド、テストすることで、期待通りに動作することを保証する安定したバージョンのプロジェクトを提供できるということだ。これも、裏を返せば、モノリポによる Easy Update は、依存関係を壊す原因にもなり得るということだろう。

依存関係については、モノリポとマルチリポの間にある利点と欠点はトレードオフの関係にあるようだ。

開発者ツール

オープンソースのコードベース経験者を対象とした設問(論文内Table 1のQ3.1~Q3.3)では、Googleのモノリポとオープンソースコードベースが共に、「利用可能な開発者ツール(Available Developer Tools)」を最大の利点としている(Figure 8, 9)。しかし、その意味合いは異なる。むしろ、両者の利点もまたトレードオフの関係にあるようだ。

オープンソースプロジェクトでは、ツールやスタイル、プログラミング言語などの選択が自由だ。DORAによる研究では、このような「チームへのツール選択権限の付与」が、ソフトウェアデリバリのパフォーマンスを高めるケイパビリティの1つとして特定されている。プロジェクトの課題や特性を把握しているのはチーム自身である。そして、その解決にもっとも適したツールを選択できるのもチーム自身だろう。この観点から、ツール選択の自由は、Available Developer Tools として利点に挙げられたことに納得できる。

しかしその自由度は、欠点にもなり得る。

ツール選択の基準が、テクノロジーに対する興味や目新しさにばかり焦点があてられてしまうと、その選択は、後から大きなコストとなって跳ね返る可能性がある。また、プロジェクトの課題や特性をチームが正しく定義できなかったり、適したソリューションを選択できなくても同様だ。「チームへのツール選択権限の付与」が機能するのは、あくまでも、チームに自律性とスキルが備わっていること、あるいはそうなろうと試行錯誤しているチームであることが前提になるのではないだろうか。

もう1つ考えられる欠点としては、一貫性の欠如につながるという点だ。プロジェクトやチームごとにツールセットが不統一だと、他人が書いたコードのデバッグや実行が困難になる場合も多い。加えて、開発者のチーム異動にともなう学習コストも高くなる。

Googleのモノリポでの開発は、これらの欠点が補われている。彼らは、巨大なコードベースを扱いやすくするために、多くのツールが自社開発されており、開発者らはそれを利用している。この標準化によって、Googleのモノリポ上での開発が高効率性を獲得していることは、調査の中で報告されている。加えて、標準化による「一貫性のあるスタイル(Consistent Style)」も、数は少ないが利点に挙げられており(論文内Figure 4, 5)、これが、高品質のコードに繋がっていると考える開発者が多いことも指摘されている。

Googleのような標準化は、開発者にとってのツール選択の制限となり、DORAの定義するケイパビリティの欠如に見えてしまうが、実態はそうではないのだ。結局は、ツールの選択権の自由度云々よりも、ツールがどれだけ開発者に有用であるかがポイントであるとも考えられる。

まとめ

以上が、モノリポとマルチリポの比較の結果であるが、注目すべきはその比較として抽出された数々の開発能力だろう。普段はマルチリポのみを使っていたとしても、こうやって比較することで、あたり前に得ていた便益や損失を見出すことができる。それを知るだけでも価値がある。

コードベースの広範な可視性は、Code Reuse, Usage Example によって、開発速度に良い影響を与える。そこに、コミット範囲の柔軟性が加わると、さらに、Easy Update が可能になる。小規模なコードベースは、開発者の認知負荷を下げるとともに、ビルド速度を高めてくれる。単一バージョンルールが導入できれば、ダイヤモンド依存関係の煩わしさから開発者を解放するが、バージョン指定での依存関係であれば、依存関係を安定させることができる。チームへのツール選択権限の付与は、チームのパフォーマンスを高めるが、リポジトリ間でのスタイルの一貫性の欠如を招く。標準化によって一貫性は保てるが、ツールの有用性が担保されなければチームのパフォーマンスを落としかねない。

組織がこれらの開発能力の何を特に必要とするか。それを評価することがまず先だ。その上で、選択した開発能力の獲得を見据え、適したプラットフォームや言語・フレームワーク、ツール、テクニックを組み合わせる。その中に、モノリポやマルチリポといった開発戦略が含まれる。どちらを選択することになるにせよ、そこに含まれる欠点を補う方法があることも忘れてはならない。

既存のコードベースに対するリポジトリ戦略や依存関係管理手法の切り替えは、コストが高い。だからといって、あまりにも限定的な導入では、モノリポにせよ、マルチリポにせよ、その便益はほとんど得られないのではないか。ハイブリッドでの導入が現実的であるようにも思うが、最大の効果を発揮できるような境界を見つけ出す必要がある。慎重に判断したいところだ。