Sansan Tech Blog

Sansanのものづくりを支えるメンバーの技術やデザイン、プロダクトマネジメントの情報を発信

マイクロサービスアーキテクチャのリポジトリ構成を漸進的にモノレポに移行した話

Sansan Engineering UnitでSansan Data Hubの開発をしている藤原です。

はニッチに深く潜り過ぎたので、今回は(使い古されたネタではありますが)モノレポ化についてお話ししたいと思います。

おさらい:モノレポ(mono repo)とは

一連のソースコードを単一のリポジトリで管理している状態のことです。 特に、実装言語、またはサブシステムやドメインといった何らかの区切りでリポジトリを分けている場合に、それらを集約することをモノレポ化と言います。 逆に、複数のリポジトリに分けている状態をポリレポ(poly repo)と言います。

モノレポのメリットとデメリット

モノレポ化することで、以下のようなメリットが得られます。

  • プロダクト全体で統一したい設定、たとえばCIスクリプトやlinter設定などの管理が楽になる。
  • 検索が楽になる。GitHubの検索で事足りることも多いとはいえ、ローカルでさくっと検索できる手軽さは魅力です。
  • コードのグループをディレクトリの階層構造でダイレクトに表現できる。ポリレポの場合、リポジトリどうしの構造に階層構造がある場合、命名規則などで工夫する必要があり、その階層構造を名前から都度推し量る必要があります。

一方で、デメリットもあります。

  • サイズが大きくなる。これは初期セットアップの体験を悪化させるかもしれません。
  • チーム構造がフラットでない場合(業務委託など)の権限管理が大変。機密性の高いアルゴリズムを含むソースコードへのアクセスを制限したいと言った場合、別リポジトリにしておいた方が権限管理は楽です。

Data Hubの実態と課題

私が携わっているSansan Data Hubはいわゆるマイクロサービスアーキテクチャを採用しており、多数のプロセスが連携して動作しています。 本記事で紹介するモノレポ化を行うまでは、ソフトウェアを一定のまとまりで区切った「ドメイン」(「ドメイン駆動開発」の「ドメイン」です)ごとにリポジトリを用意しており、約40のリポジトリが存在していました。 また、CI/CDの設定も各リポジトリに存在しており、そこから別リポジトリにある共通のテンプレートファイルを参照する構造でした。

そして、Data Hubのリポジトリ構造は以下の問題を抱えていました。

  • 機能が散在して探しづらい
  • ドメインをまたがる変更が複数のリポジトリにまたがる
  • CIの設定が散在

逆に、サイズとしては100万行程度(さまざまな設定ファイルなどを含めて550万行)とそこまで大きくはありませんでした。また、チームも内製チームであり、特殊な権限管理が必要なソースもないため、権限管理の問題はありませんでした。

課題を一つひとつ見ていきます。

機能が散在して探しづらい

機能拡張や修正、特に運用に関わるようなドメインをまたがった機能のコードを探す場合、Git Hubのリポジトリをまたがって検索する必要がありました。 Git Hubではリポジトリをまたがった検索もできますが、正直そのワンクッションが面倒です。 シンボル検索もできないので、まぁ不便ではありました。

モノレポに統合することで、少しだけ検索が楽になりました。 また、Readme.mdなどで他のドメインのソースコードを相対パスで指定することで、Git Hub上でもローカルでファイルを開いた時にもリンクとして動作するようになりました。地味にうれしいところです。

ドメインをまたがる変更が複数のリポジトリにまたがる

Data Hubはデータ連携のプロダクトであり、非同期メッセージングでデータのパイプラインになっています。 特定のドメインに閉じた修正もありますが、複数のドメインに影響を与える修正も存在します。 その場合、リポジトリが分かれていると、プルリクエストが複数になり面倒です。レビューする側も複数のプルリクエストを横断してみる必要がありました。 またブランチの管理も煩雑になっていました。

言うまでもなく、モノレポに統合することで、一つのプルリクエストでまとめて対応できるようになりました。

CIの設定が散在

似たような問題として、CI/CDの設定ファイルも各リポジトリにあり、さらに共通のテンプレートを定義したリポジトリに存在していました。 そのため、共通部分のCIやCD用の新機能を足す場合に、試験用のブランチを作成してそこでまとめて試行するのが困難でした。

モノレポにしたことで、一部または全部のCI/CDの設定をブランチを分けて試験できるようになりました。

移行戦略

移行戦略として、漸進的に行うか、開発を止めて一気に行うかがあると思います。 世の中の事例を見ると一気に行う場合が多いようですが、以下の理由から、Data Hubは漸進的な移行を実施しました。

  • 対象のリポジトリごとに変更頻度の差が大きく、変更頻度の小さなリポジトリの統合は開発を止めずに行うことができた
  • CIの最新化を同時に行いたいと思っており、その実地検証として影響の少ないリポジトリを先行して実施したかった
  • プロダクト変更のアジリティをできる限り確保し続けたかった

また、ソースツリー全体に対する大規模な移行作業として、全体を俯瞰できる立場にいるエンジニアが一気にやってしまうのも手だと考えていました。 たとえば、.NETのリポジトリでnull許容参照型を導入するときは、上級エンジニアであるStephen Toubがある程度のまとまりで一気にコミットしています。 このやり方には賛否両論あるかと思いますが、少なくとも調整コストを減らすことはできそうです。調整の時間や気力はプロダクトの価値に直結する部分にかけたいものです。

移行の実施

移行の計画は11月に入ってから行い、対象の洗い出しを行いました。ghコマンドで愚直に最終更新日を取得し、プロダクトのロードマップやバックログを見つつ、リスクの少ないところから順次移行し、高頻度のところはプロジェクトの合間を縫って配置、隙間を低頻度のもので埋める、という形で計画しました。 チームの中では比較的朝早くから活動しているので、朝に移行をコミットし、PRを投げ、指摘事項があれば夕方に対応し、翌日マージといったサイクルを続けていきました。

ツールは手製のスクリプトで実施しました。OSSとして公開されているツールの使用も検討しましたが、それほど大がかりな変更が不要だったこと、ツールの中身を見ると意外とシンプルであったこと、移行に伴うディレクトリ構成の調整などの自由度の確保が欲しかったこと、Windowsマシンで実行するための工夫をするよりも手で書いた方が早かったためです。なお、同時にAzure PipelinesのCI/CDジョブの移行も実施しており、これも移行スクリプトの中で実施しました。やってみると、モノレポの移行よりも、微妙に統一されきっていなかったCI/CDジョブの移行に手間取りました。ここも、モノレポになることで「同じリポジトリなのだから同じ流儀でCI/CDジョブを書く」という意識が高まることを期待しています。

他にも、プロジェクトの都合からスケジュールを数日延期したり、移行の真っ最中に元リポジトリにコミットが入ったりなど細かいトラブルはいろいろありましたが、全体としては大過なく終えることができました。 複数あるリポジトリ全体をロックしてビッグバン移行するのではなく、漸進的な移行をするという戦略自体はうまくいったと考えています。 そして、月並みではありますが、チームメンバーの前向きな協力や、小まめなフィードバックがあったからこその成功だと思います(もしかしたら、ハイブリッドワークなのでモノレポ化に対して怒り狂っている姿を見ずに済んだだけかもしれませんけど :) )

モノレポに統合してどうなったのか

先ほど課題のところで課題が解決されたことは述べましたが、それ以外にもいくつかの気づきがあったので共有します。

よかったこととして、変更の時系列がコミットログから追いやすくなりました。20人弱のチームのためということもあり、全体の作業の見通しは見やすくなりました。気分の問題かもしれませんが、全体を把握する心理的な負荷も下がったように思います。 一方で、油断するとあっという間にコミットが流れていくようになりました。あっという間に分岐元のコミットが古くなっていきます。こまめなブランチの統合の重要性が増したと言えるでしょう(言うはやすく行うは難し、ですが)。

なお、杞憂だったことして、 変更の衝突やマージの負荷が増えるかと思いましたが、実際はそうでもありませんでした。そもそも各チームの担当範囲がうまく分かれているので、同じファイル群を編集することはあまりなかったためです。もちろん、ファイル単位での調整は必要ですが、それはモノレポに統合する前と変わりません。

まとめ

モノレポ化という使い古されたネタですが、40ほどのリポジトリを、全体を止めずに、ある意味結果整合の考え方で統合した方法の紹介でした。 今のところ、やってよかったと思っています。もし、まとまった時間が取れないからと躊躇している方がいらっしゃれば、本稿が参考になれば幸いです。

© Sansan, Inc.