開発Tips

logbo をモノレポにした話 — 別リポのAPIを統合して得たもの・混ぜて失敗したもの

いまの logbo は、android/(旧ネイティブアプリ)・app/(Flutter)・api/(Go バックエンド+Web)を1つに束ねたモノレポです。ここに至るまでの経緯と、やってよかったこと・混ぜて失敗したことを、コミット履歴をたどりながら振り返ります。

これまでの経緯

git 履歴を掘り返すと、logbo のリポジトリは思ったより長い歴史がありました。

  • 2017年9月: Android アプリとして誕生(当時は Bitbucket)。リポジトリ名もアプリ由来の名前でした。
  • API は別リポジトリ(go_api)で管理。もともと Spring(Java)で書かれていて、2019年に Go へ移行しています(コミット「全APIをSpringからGoへ移行完了」)。
  • 2026年3月末、モノレポ化。別リポだった API を git subtree でアプリのリポジトリへ取り込み(履歴に Squashed 'api/' content が残っています)、.github をルートへ移動し、CI/CD と release-drafter をモノレポ構成へ組み直しました。
  • その後、API を Firestore へ移行し、Flutter 版を追加。リポジトリ名もサービス名(logbo)に合わせて統一しました。

つまり「アプリのリポジトリに、別で育てていた API を後から合流させた」というのが実態です。

git subtree で統合した

複数リポを1つにする方法はいくつかありますが、今回は git subtreego_api の内容を api/ 配下として取り込みました。サブモジュールと違い、取り込んだ後はふつうのディレクトリとして扱えるため、モノレポ内で素直に触れるのが利点です。統合と同時に、CI(GitHub Actions)や release-drafter を「パスごとに対象を切り替える」構成へ作り直しています。

やってよかったこと: 横断変更が一気に楽になった

いちばんの効果は、API とクライアントにまたがる変更を1つの単位で完結できることでした。

  • Firestore のフィールド名を変えたら、同じ PR でクライアント側の対応も入れられる。「サーバだけ先にマージして不整合」が起きにくい。
  • issue・PR・CI・リリースドラフトが1箇所に集約され、リポジトリ間を行き来するコンテキストスイッチが減った。
  • ドキュメントや開発ルール(CLAUDE.md など)も一元管理でき、全体像が掴みやすい。

個人開発で「API とアプリを両方いじる」場面が多いほど、モノレポの恩恵は大きいと感じます。

失敗したこと: 関心の違うものまで混ぜた

一方で、はっきり「やりすぎた」と思うのが、ポートフォリオや各アプリのLP、さらにこのブログまで api/ に載せてしまったことです。

api/ は本来アプリのバックエンドですが、そこに Web/マーケティング寄りの成果物(静的ページ)が同居しています。結果として、

  • 「アプリ開発」と「サイト運用」という関心の異なる作業が同じリポに混在し、コミット履歴や issue、レビューにノイズが増えた。
  • デプロイ単位や CI のトリガー設計が複雑になった(どのパスの変更で何を動かすか、を都度考える必要がある)。
  • リポジトリの「主題」がぼやけた。

モノレポ化そのものは正解でしたが、「何を1つのリポに入れるか」の線引きを最初に決め切れていなかったのが反省点です。

学び: 束ねる基準は「密結合かどうか」

振り返ると、束ねる/分ける の判断基準はシンプルでした。

  • 密結合なもの(API とそのクライアント)は束ねる → 横断変更が楽になり、恩恵が大きい。
  • 関心が独立したもの(アプリ開発 と 静的Web/ポートフォリオ)は、無理に同じリポへ入れない → 混ぜると管理コストが増える。

モノレポは「なんでも1つに入れる」ことではなく、「一緒に変わるものを一緒に置く」こと。その原則で線引きしていれば、ポートフォリオは別に切り出していたと思います。今の構成は動いていますが、もし作り直すなら、この基準で分割を検討します。

まとめ

  • 別リポの API を git subtree で取り込み、logbo をモノレポ化した。
  • API×クライアントの横断変更が楽になり、開発効率は明確に上がった
  • 一方で関心の違うもの(PF・LP・ブログ)まで混ぜたのは失敗で、履歴やCI設計にノイズを生んだ。
  • 判断基準は「一緒に変わるものだけを束ねる」。密結合は束ね、独立した関心は分ける。