What is Monorepo? Nx?

# はじめに

**Monorepo**管理ツールの**Nx**を使用して以前フロントパッケージ開発やクライアントアプリの開発をおこなっています。
monorepoやNxと聞いてちんぷんかんぷんで、そもそもの**Monorepo**とは何か？**Nx**で何を実現したいのか？を改めて振り返りたいと思います。


- Monorepoの特徴
- Monorepoツールで実現できること
- Nxでの開発体験

以上についてまとめていきたいと思います。

## まずググってみた

まず**Monorepo**をリサーチしてみて人によって定義が色々あり、曖昧だったので代表的なサイトや会社をググって軽くまとめてみました。

###  Wikipedia
wiki引用
>In version control systems, a monorepo ("mono" meaning 'single' and "repo" being short for 'repository') is a software development strategy where code for many projects is stored in the same repository.
> バージョン管理システムにおける多くのプロジェクトのコードが同じリポジトリに格納されるソフトウェア開発戦略
> monoは「単一」、repoは「リポジトリ」の略

monorepoをwikiってみて単一のリポジトリで管理することは以下の印象でした。
- バージョンの依存関係を一つにまとめることでビルドを最適化できる。（複数のリポジトリがサードパパーティに依存している場合、各リポジトリでバージョンを合わせる必要がある）
- テストやビルド, デプロイなどのCI/CDを単一に行うことや機能やライブラリを共有も容易。

### Nrwl（Nx開発会社）

nrwl blog引用

>A monorepo is a single repository containing multiple distinct projects, with well-defined relationships.
> Monorepoは、複数の異なるプロジェクトを含む単一のリポジトリであり、その関係は明確に定義されています。

各monorepo toolsの特徴やPolyrepoとの対比についての取り上げていました。
こちらでも複数のリポジトリをmonorepoにする事で、バージョン管理やCI上のテスト・デプロイを一貫して通すことのメリットや反対にPolyrepoだと各レポで同じサービスやコンポーネント作成の工数やコマンド・コードの差異があるデメリットを言っていました。

Polyrepoだとチーム間での各リポジトリの把握がmonorepoと比べてしづらい印象や他のリポジトリとの依存関係の面倒も横断して調整に対する負担もかかると思いました。

https://monorepo.tools/

### CricleCI Blog

CricleciブログではマイクロサービスとMonorepoの記載やリポジトリを分割する（Polyrepo：ポリレポ）に対する懸念点にふれていました。
- メリット：単一で見やすいなど、コード共有・リファクタリング・リリース管理も良い印象。
- デメリット：共通ライブラリの変更を行う場合注意が必要
私があまりマイクローサービスに詳しくないのですが、マイクロサービス目線のMonorepo対する誤解（コードの密結合や個々のデプロイ周り）についても記載がありました。

https://circleci.com/ja/blog/monorepo-dev-practices/


## What is Monorepo？

プロジェクトに関わる複数のリポジトリを単一のリポジトリで管理するソフトウェア開発戦略のことを**Monorepo**という。
またMonorepoとは反対に複数リポジトリを一つひとつ単一に管理することをPolyrepo（or Mulch repo）という。

### Monorepoで実現できること・したいこと

色んな代表的な会社の記事を漁ってみて**Monorepo**で実現できることは以下の内容に落ち着きました。
（ただしプロジェクトによってフロントエンド、バックエンドでの技術選定や開発手法によってよりメリットになり得ることは省いた内容です。）

- コード管理・保守が容易
- 複数レポのGit管理

#### コード管理・保守・テストが容易

複数レポと比べて単一にすることによって、プロジェクトに関わる**コード全体の見やすさ**やリポジトリを横断してコードを共有することも可能です。
また以上の利点があることによって**リファクタリングやバグ改修などの開発体験向上**に繋がる。

複数レポが関わる場合の新規機能や機能修正の場合などは開発がしやすいと思います。また複数のモジュールを結合したテストを行う場合においてもバグ発見し修正しやすい印象。

<img width="400" alt="スクリーンショット 2022-09-11 13.14.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/df941735-9cee-22d0-cacd-50f0f8302b97.png">

#### Git管理

Gitの変更追跡・PR履歴も一つのリポジトリでの管理することで変更の**把握**がしやすい、github actions（CI）でデプロイやテストを一つにまとめれる。



#### monorepoで開発しづらいこと

現在業務で使用していて開発しづらいこととすれば以下を記載しましたがまだまだ出てきそう。
- package.jsonにコマンドの設定やパッケージがPJ数が多いほど肥大化してしまう。
- CIや環境周りを整備する時は全レポを巻き込み影響範囲がでかいので慎重に行わないといけない。



## What is Nx？

<img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="450">

高速かつ拡張可能なビルドシステムでmonorepoベースの開発ツールセットです。
様々なFWやライブラリを開発するための機能がプラグインとしてサポートされており、monorepoで複数PJを取り扱う際の便利な機能がいくつか備わっています。
主な利点としては以下になります。

- Nxコミュニティに豊富なプラグインがある。
- モダンな技術スタックでお手軽なプロジェクト生成
- 実行コマンドのキャッシュ
- PJの依存関係の可視化（Nx Graph）


### モダンな技術スタックでお手軽なプロジェクト生成

Angular, React, NestJS, Express, node.jsなどに対応しておりworkspaceを立ち上げる際に、どのツールで生成するか選択することが出来ます。

![スクリーンショット 2022-09-18 17.13.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/3abb7740-a0f9-0a4e-a979-78503807ed35.png)

生成時に、様々なCSSツール（SCSSやstyled-components, emotionなど）選択できたり、アプリ名を入力することで、選択したツールを元に`app`と`e2e`ディレクトリを生成します。

また、環境に応じてプラグインのサポートが豊富でReactベースのプロジェクトを対象に`Storybook`や`TailwindCSS`の環境設定もお手軽にできます。

Nx Consoleだと`generate`項目を表示してくれる。
![スクリーンショット 2022-09-18 17.22.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/37c1054e-43d5-5e3c-6e09-23b4b13f58bb.png)

### 実行コマンドのキャッシュ

`nx affected`コマンドでPRで変更したファイルとその依存関係を計算しキャッシュをしてbuildやtest,lintを行なってくれます。

例えば`/client1 ~ 3`のappsがあり、`/libs`のutils関数を変更したとします。そこで`nx affected --target=build`を実行するとビルド時にutils関数を使用している`/client2, 3`は依存関係があるのでビルド対象ですが、`/client1`については**依存関係がないのでキャッシュされるといった仕組み**です。


![nx affected (3).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/efad376f-b485-5c1c-e830-11387f278ae1.png)

- キャッシュ場所`/node_modules/.cahce/nx`

実際にはnx内部でそういった差分を計算し最終的にビルドするソースをwebpackを使用してビルドを行なっているみたいです。

またCI上にも適用することができるので提供会社が実際に`affected`を使うかどうかでのCI時間を比較していました。


>CI rebuild times can be dramatically improved, since any project that has no changed dependencies will just load from the cache instead of re-executing the command. The data for the chart below was taken from two production code bases. This is the power of caching.
・deeplでの翻訳
依存関係が変更されていないPJは、コマンドを再実行する代わりにキャッシュからロードするだけなので、CIの再構築時間は劇的に改善されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/924294/de61fe9a-6d71-fcbb-66c6-4e7ee8302fd5.png)


### Nx Communty

Nx上でアプリケーションやライブラリをスムーズに扱えるようプラグイン開発しているコミュニティがあります。
viteやstorybook, firebaseの初期設定などあります。
実際に開発するのはプラグインを開発できるnx/devlit環境を生成することで作成できます。独自のプラグインを共有するには、npmレジストリに公開することで可能です。（詳しくはこちらになります。）

https://nx.dev/packages/nx-plugin#publishing-your-nx-plugin

### Nx Console

GUIベースでNxコマンドを実行することができるVSCode上の拡張機能です。
`build`や`test`はもちろん、環境に応じて生成が可能な`generate`コマンドでGUIの操作が可能な`Nx CLI`をサポートしています。


## 参考記事

- [Monorepo開発のメリット vs デメリット](https://circleci.com/ja/blog/monorepo-dev-practices/)
- [monorepo tools](https://monorepo.tools/)

# まとめ

今回monorepoでの開発をするに至って複数のリポジトリを一つにまとめることによってコードの把握や共有、バージョン管理を容易にしている効果があることはわかりました。
また、上記の開発体験をサポートしている**Nx**（monorepo tool）を今回探ってみて、Nxコマンドやjsonファイルの設定などNxに対する学習コストが高い印象でした。
また`Nx console`でモダンな技術に対するサポートや開発初期の環境構築はしやすいと思いました。