モノレポについての誤解 - Misconceptions about Monorepos: Monorepo != Monolith を翻訳しました

このドキュメントは、モノレポについて書かれた記事
Misconceptions about Monorepos: Monorepo != Monolith (https://blog.nrwl.io/misconceptions-about-monorepos-monorepo-monolith-df1250d4b03c) を、筆者であるVictor Savkin氏の許可を得て翻訳したものです。

複数のプロジェクトを同一のリポジトリで運用する モノリシックリポジトリ(モノレポ)― この記事では、モノレポを使う際によくある誤解とその対策、モノレポが持つ本当の課題と利点がまとめられています。モノレポはガチガチの「一枚岩(モノリス)」ではなく、もっと柔軟にあることができる手法なのです。


モノレポについての誤解 : モノレポ != モノリス

Victor Savkin
投稿日:2019年8月14日

monorepo_img_01.png

私はモノレポ用の開発ツールを開発し、長年、企業への導入を支援しています。 その中で、いくつものチームからモノレポの考え方に対して、似たような反対意見を耳にしてきました。

  • 同時リリースが強制されてしまう。モノリスはダメだ
  • 私の知らないうちに他のチームがコードを変更してしまう
  • 大きな泥団子を作るようなものだ。アプリケーションを理解したり保守することが難しくなる
  • スケールしない

これらの多くの場合は、Lerna[訳注1] のようなツールを試そうとして引き起こされた混乱から生じたものです。 その混乱によってモノレポ自体が、マルチプロジェクトあるいはマルチチームというシナリオに対して、現実的なアプローチではないと結論づけてしまうのです。

訳注1:Lerna (https://github.com/lerna/lerna) は、git や npm においてマルチパッケージリポジトリ管理周辺のワークフローを最適化するツール

この記事では、コードコロケーションツール(Lerna 等)と、Google/Facebookスタイルのモノレポツールの違いを明示します。そして、モノレポに関する一般的な誤解をしめします。

モノレポは銀の弾丸ではありません。そんなものは存在しません。しかし上手くいけば、この記事を読み終えたとき、あなたが今後直面する現実の課題へ取り組む際に、その方法が組織にとって正しいアプローチであるかどうか、モノレポのもたらす効果を明確に理解できることを願っています。

この記事内の例は Nx と呼ばれるモノレポ用の拡張可能な開発ツールセットを使用します。しかし、この記事は Nx に関するものではありません。ほぼ全てがモノレポのツールに該当します。

Lerna と モノレポ

Lerna は有用なツールです。大好きです。しかし、Google、Facebook、Microsoft、Uber が言うモノレポは、Lernaのことではありません。彼らは何のことを指してモノレポと言っているのでしょうか?

モノレポスタイル開発はソフトウェア開発手法です。このような:

  • 複数のプロジェクトが、同一リポジトリ内にある
  • プロジェクトは相互依存可能で、コードも共有できる
  • 変更を行う場合、モノレポでは全てのプロジェクトで再ビルドや再テストをしない。その代わり、変更の影響を受ける可能性のあるプロジェクトだけを再ビルドと再テストする

最後の点は、次の2つの理由で重要です:

  • CIが高速になる。大規模な場合は1000倍早くなる
  • チームがモノレポ内でも独立して活動できる。もし2つのプロジェクトAとBが相互依存でない場合、どんなときも相互に影響を及ぼすことはありません。チームAが彼ら自身のプロジェクトを開発し、テストし、ビルドし、プルリクをmasterにマージする際、チームBによって書かれたコードが動くことはないです。チームBにイマイチなテスト、ダサいコード、壊れたコード、壊れたテストがあったとしても、チームAは、まったく気にしなくていいです。

誤解

モノレポ !== モノリス

すべてのリリースを同じ日にする必要はありますか? だから私はモノリスが好きじゃないんです!

これはリポジトリとアーティファクトのデプロイが強く関係することに起因する、よくある誤解です。

しかし、どこでコードを開発するか、と、なにをいつデプロイするか、は関係ないことは、簡単にわかります。たとえば、Googleのモノレポには何千ものアプリケーションがありますが、明らかに全てが一緒にリリースされていません。

さらに、CIをしたければ、ビルド済みアーティファクトを保持し、その保持されたアーティファクトを複数の環境へデプロイするというのは優れたCI/CDプラクティスです。 言い換えれば、あるアプリケーションをデプロイする際、いかなるリポジトリにもアクセスする必要はないのです。

だから、モノレポ !== モノリス。まったく反対なのです。なぜなら、モノレポはコードの共有とプロジェクトをまたがるリファクタリングをシンプルにし、ライブラリやマイクロサービスとしてマイクロフロントエンドの作成コストを大幅に下げます。つまり、モノレポを採用すると、大抵はデプロイの柔軟性が高まります。

他のチームが知らないうちに私のコードを変更してしまう

他のチームが私のアプリを壊すことができる、私の知らないうちに、しかもリリース直前に!

この誤解は、リポジトリ設定だけでアクセスとパーミッションを制御することに起因します。 多くのツールではフォルダごとに所有権を設定できることがほとんど知られていません。

たとえば、Githubには、CODEOWNERS と呼ばれている機能があり、このように設定できます:

apps/app-a/* @susan
apps/app-b/* @bob

この設定の場合、あなたがアプリAを更新するプルリクを出したら、スーザンが承認する必要があります。もし、アプリBのみを触る場合はボブが承認します。また、プルリクがAとBに触れる場合、スーザンとボブの承認が必要です。

ちなみに、コードの所有権に関しては、より多くのコントロールが可能です。この図では:

monorepo_img_02.png

組織内には2つのチームがあります。チームBはアプリケーション間でコードを共有したいと思っており、彼らは shared-b という共有ライブラリを作りました。このライブラリは private であり、彼らはチームAがそれに依存することを望んでいません。なぜでしょうか? もしチームAが依存してしまうと、チームはお互いに密になり、チームBは共有ライブラリを変更するたびにチームAへの影響を検討しなければならないからです。

レポジトリが複数ある場合、チームAが shared-b を彼らの package.json へ追加することは防げません。チームBが管理できないリポジトリなので、チームBがその変更を知ることができないのです。ほとんどのモノレポのツール(Nxを含む)では、ライブラリの可視性を的確な方法で定義できます。チームAがshared-b をインポートしようとすると、このようになります:

monorepo_img_02-1.png

大きな泥団子になってしまう

ひとつのアプリケーションでさえ、なんとか管理しているのに、5つのアプリケーションを同じリポジトリにおいたら、誰もまったく理解できなくなるよ!

この誤解は、同一リポジトリ内であれば、どのファイルでも他のファイルをインポートできるという事実から来ています。 人々はコードレビュー中になんらかのルールを課そうとしますが、それらは明確な定義として長期間定着せず、依存関係がグチャグチャになってしまいます。

みんな、知っているのです。そこそこのサイズのプロジェクト(5万行ぐらい)を開き、メインコンポーネントとその周りの相互依存についての依存関係図を描きます。そしてリポジトリを確認してみましょう。あなたは"予期しない"依存をたくさん見つけることになります。

Nxでは、明確に定義されたpublic APIを持つライブラリを作ることができます。ライブラリはほんの数秒で作れてしまうので、たくさんのライブラリを作成するようになります。よって、典型的なアプリケーションは数十個のライブラリに分割され、それらはpublic APIによってのみ相互依存します。

monorepo_img_03.png

Nxであれば nx dep-graph とすれば依存関係グラフの生成を自動化できます。

monorepo_img_04.png

アーキテクトがWikiに貼り付けた図は、すぐに時代遅れになりますが、依存関係グラフは正確かつ適切に更新されます。

さらに、リポジトリ内のライブラリへメタデータを追加することで、それを基にした制約を定義することが可能です。たとえば、プレゼンテーションコンポーネントがステートを管理するコードに依存できないことを静的に保証できます。

monorepo_img_05.png

面白いですよね。モノレポにすることによって、多くの人々が考えていたことと逆のことが起きるのです。

スケールしない

CIに5時間もかかるなんて思った?

すべてのコミットのたびに、すべてを再ビルド・再テストすると遅くなります。 片手ぐらいのプロジェクトを超えてしまうとスケールすることはありません。 しかし前述のように、モノレポを使用すれば、影響を受けるものだけを再ビルド・再テストします。

もちろん、CIを何もいじらずに際限なくスケールするということではありません。もし、リポジトリに多くの大きなアプリがあるなら、平均的なCI時間は早くなります。しかし、もし全アプリが依存する変更があった場合には、すべてを待たねばなりまん。そんなプルリクは稀でしょうが、スケールを得るためには複数台でCIを回すことを考えてもいいでしょう。

gitは壊れますか?

この懸念は根拠がないことではないです。もしリポジトリに100万のファイルがあった場合、Gitそのものを含め、あなたが愛用する多くのツールは動かなくなります。ただし、多くのモノレポには何千ものアプリはありません。1つの組織であれば1ダース(12個)ぐらいでしょう。数千のファイル、数百万行のコード。たいていのツールは問題なく扱えるでしょう。

マイクロソフトは膨大なレポジトリ数を前提としたスケーラブル版GitであるGVFSをリリースしました。既に Azure Pipelines や、BitBucket もサポートしています。Github も近々にサポートするでしょう。

本当の課題

これまでに書いたことは誤解にもとづくものです。モノレポが完全という意味ではないです。モノレポも課題を抱えています。

トランクベース開発

モノレポと長期にわたるfeatureブランチは相性が悪いです。 トランクベースの開発を取り入れるチャンスです。 しかし、トランクベース開発への移行は一部のチームにとっては簡単ではありません。 フィーチャートグルのような新しいプラクティスを採用する必要があるからです。

私は、リポジトリのサイズに関わらず、トランクベース開発が高品質なコードと高ベロシティにつながると信じていますが、それでも何かしらの考慮は必要です。

すべてのサービスが動作するわけではない

モノレポはまだ主流ではなく、一部のサービスはうまく機能しません。 単一デプロイアーティファクトや、リポジトリ単位でのカバレッジレポートが必要になるかもしれません。とはいえ、ほとんどの課題はなんとかなるでしょう。

CI

モノレポへ移行するには、継続的インテグレーションの方法を再考する必要があります。そもそも、1つのアプリをビルドしています、なんてことはないのです。変更によって影響を受けたものだけをビルドしているでしょう。

ポピュラーなCIソリューション(Azure、Circle、Jenkins等)にはNxなどを組み込む十分な柔軟性がありますが、その方法を把握するのに時間がかかるかもしれません。

大規模な変更

モノレポは大規模な変更をよりシンプルにします: あなたは100のライブラリから作り出された10のアプリをリファクタリングして、変更をコミットする前に、それらすべての動作を検証できます。

ただ、そうしてしまうことで、大規模な変更によって、より多くのことを考える必要がでて、物事をややこしくしてしまいます。たとえば、共有ライブラリを変更した場合、それに依存するすべてのアプリケーションが影響を受けます。もしそれが、破壊を伴う変更で、自動化もできていないなら、下位互換性がある変更をおこなわなくてはなりません。あなたは、2つのバージョンのパラメータ/メソッド/クラス/パッケージを作り、利用者が古いバージョンから新しいバージョンへ移行するのを助ける必要があります。

まとめ

モノレポには次の利点があります:

  • すべてにおいて現時点でコミットされたものが動きます。変更の検証がすべての影響範囲に対して実施可能です
  • コードを構成可能なモジュールへ簡単に分割できます
  • 依存関係をより簡単に管理できます
  • 単一ツールチェーンでのセットアップできます
  • コードエディタやIDEは “ワークスペース単位” で動かします
  • 一貫した開発者エクスペリエンスがあります

色々という人はいるでしょうが、モノレポはまた:

  • あなたにより柔軟な開発をもたらします
  • 所有権の方針を正確に設定することが可能です
  • ソースコードに、より明確な構造を提供します
  • 適切なツールによって、適切にスケールします

ただし、いくつかの困難も伴います:

  • トランクベース開発は、より一段と重要になります
  • すべてのサービスがモノレポで上手く動くわけではありません
  • より精巧なCIセットアップが必要です
  • あなたは大規模な変更について考える必要があります

もっと詳しく知るには

Nx はオープンソースで拡張可能なモノレポ用の開発ツールセットです。様々な JavaScript や TypeScript ベースの技術で使われていますが、特にWebコンポーネント、Angular、React、Express、Nest をサポートしています。

nx.dev をチェックしたり、この動画でさらに詳細を確認してください:

元記事の著者について

Victor Savkin は Nrwl の共同設立者です。2016年以降、Googleのような企業の開発を支援しています。我々は、コンサルティング、エンジニアリングとツールを提供しています。

monorepo_img_06.png

もしこの記事が気に入ったら(元記事の)👏をクリックして、他の人にも Medium上でこの記事が目につくようにしてください。 ツイッターで @victorsavkin をフォローすると更に、モノレポ、Nx、Angular や React について読むことができます。