モノレポとマイクロサービス


コロナの影響で在宅勤務(テレワーク)も一ヶ月以上も続き環境の変化に慣れてきましたが、`BBCパパ`のように急な家族の割り込みによる対応で頭を悩まされている streampack の Tana です。 

[![IMAGE ALT TEXT HERE](http://img.youtube.com/vi/Mh4f9AYRCZY/0.jpg)](http://www.youtube.com/watch?v=Mh4f9AYRCZY)
(在宅疲れした際に見るとリラックスできますw)

## モノレポ(Monorepo)とマイクロサービスへの取り組みについて

`streampack` は動画配信プラットフォームをお客様の要望にカスタマイズしながら、`AWS`などのクラウド上に提供しているサービスです。既存のシステムとマイクロサービスを最大限に活かすために、案件ごとに管理していた複数のレポジトリ管理から`モノレポ`へ移管したかについての経験談のお話になります。

以前は案件やレイヤー毎にリポジトリを切って開発してました。いわゆる `Polyrepo(Multi-Repo)` と呼ばれる方法です。

例えば、
- project1_frontend
- project1_cms
- project2_api
- project3_dev
などなど。

当時はまだ管理している案件が少なくまた固有な機能やシステムがあり、
それぞれのリポジトリで管理した方がいいだろうと、当時は短期的な目線で判断してました。

がしかし・・・

## 管理・保守の問題が発生

案件が増えるたびにリポジトリの管理が複雑になり、セキュリティアップデート、機能廃止、バグの修正によって、全てのリポジトリで下記の作業が必要した。

+ `Project-1`レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイ
+ `Project-2`レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイ
+ `Project-3`レポジトリのチェックアウト、アプリ起動、コード修正、テスト、レビュー、デプロイ

単純作業なのかもしれませんが、数が多いとどうしても時間がかかり非効率です。
また案件によっては、開発環境がないものがあったりなど、それをどう考慮するか、本番直反映でいけるかなど考慮すべき点が多々ありました。

## なぜモノレポの採用に至ったのか？

そこで、調査していく上で、影響を受けたのが、[なぜ Google は全てのコードをシングルレポジトリを管理しているのか](https://www.youtube.com/watch?v=W71BTkUbdqE)のYouTubeになります。Facebook, Twitter などの大規模システムでも採用されている手法です。


この手法で重要なのが、`Trunk-based Development` であり、常に Trunk に開発されたコードがマージされるということになります。そうすれば、常に最新なコードで動作確認できます。リリースはリリースブランチがあり、リリースしたいコードのみを `Cherry Pick` して、リリースブランチに反映してリリースを行います。`特別な機能やベータ段階のものは、フィーチャーフラグで制御します。`必要に応じて ON/OFF にすることにより、コードを修正することなく制御できます。また、シングルリポジトリなので、コード、ライブラリの共有ができるのもメリットの一つになります。

streampackとしても今後の保守・運用を考慮すると、`Rails`、 `Golang`、 `NEXT.js(NodeJS)`などのアプリケーション毎のバージョン・セキュリティアップデートがあることを想定すると、それぞれの一つのモノレポで運用した方がいいと判断し進めることにしました。また、`再利用することで開発の効率や無駄な開発を減らすのも目的の一つです。`

## 調査とコード移植

まずは、現状調査ですが、案件ごとに特別な機能やシステムを洗い出しをしました。その特別な機能の移植を `モノレポ` に反映し、フィーチャーフラグとして提供するようにしました。また、設定情報やサービスの固有な情報は環境変数で管理し、ローカル開発の際は、`.env`の参照、また本番環境では、`ECS(タスク定義)`上で汎用的に管理できるようにしてます。例え、ホスト名、AWS環境、API情報が変わったとしても簡単に変更できます。Docker上で開発する上では12factorの概念は重要です。

[Config - The TWELVE-FACTOR APP](https://12factor.net/config)

## DBマイグレーション

モノレポによる移行を考慮する際に重要だったのが、`Backwards Compatibility`です。移行前と移行後でも同様に正常にダウンタイムなく動く必要がありました。ある案件ではある機能不要だからといって、テーブルやカラムを削除したりすると、DBマイグレーション時に移行前の状態だと動かなくなるので、基本は削除しないようにしております。将来的に不要と判断したタイミングで精査して削除するという流れです。また、一部データ移行・更新が必要だったものに関しては、DBマイグレーションで実行のタイミングで、タスク(Script)により、制御し手動対応させず自動化させてます。


## マイクロサービス

ライブ配信制御機能やライブチャットなど一部のサービスや機能に応じてマイクロサービスとして管理されております。シングルなモノレポなので、ディレクトリを変え環境変数を変えることで、開発環境を立ち上げたり、異なる環境にデプロイし再現したり再利用することができるようにしてます。一部のお客様の要望により、固有な機能なものを幅広く使えるように共通仕様に持っていき再利用できるように心がけてはいますが、共有できない、固有な仕様になっているのが現状で、改善の余地があります。


## ビルド＆デプロイ

マイクロサービスでのアプリケーションごとに、インストール方法や実行コマンドが違って混乱することがあります。どんな人でも同じコマンドで動かせることで、ハードルを下げ、さらにドキュメント(README.md) などもシンプルになります。以前[こちら](https://qiita.com/ytanaka3/items/cdb7ab2cd59217e3c62d)のブログでも紹介させていただきましたが、make コマンドを使ってアプリケーションの立ち上げ、ビルド、デプロイまでできるようにしてます。

アプリを立ち上げたい場合:
> $ make run

ビルドしリリースしたい場合:
> $ make release

というイメージです。Code Deploy, Circle CIなどのCI/CDを導入するのも可能ですが、開発・リリース頻度の兼ね合いや`社内用のgit`では`CI/CD`に対応していないため見送り状態です。また`Bazel`などのビルドツールだと並列処理などメリットはありそうですが要検討が必要そうです。

## 新規・追加開発でのメリット

モノレポ対応できたことで、マイクロサービス間の修正が一貫性の変更がコードレビューで確認できます。それぞれのレポジトリの切り替えが必要なく、コードレビューをそれぞれ出す必要はなくなりました。一つのリポジトリさえクローンして修正すればいいのです。マイクロサービス化では重要な手法かと思っております。