Techtouch Developers Blog

テックタッチ株式会社の開発チームによるテックブログです

えぇっ、Nx Cloud を知らない!?――前編:「CIで分散並列実行とキャッシュ利用ができるだって!?」――

記事のタイトル画像。記事のタイトルと、筆者であるcanalunのアイコンがのっている。

さあさあ、面白そうなタイトルに惹かれて(?)やってきたそこのあなた!ありがとうございます!!

はじめまして、テックタッチの canalun と言います👶
普段は DOM について考えたり、CI/CD の改善をしたりな毎日です!
DOM が好きすぎて週刊DOMDOMタイムスというのをやってますので、興味がある方はぜひ見てみてくださいねえ🌞

この記事では前後編2回に分けて、Nx Cloud の主な機能の紹介と実際の導入の仕方を解説します!!
前編にあたる本稿では、Nx Cloud の2大最強ポイントである「CIの自動分散並列実行」と「CI結果のキャッシング」を紹介します

ちなみに後編ももうあるよ。

tech.techtouch.jp

では早速行きましょう!
目次を見てオモロそうなところだけ読むもよし、とりあえず上から読んでみるもよしです。自由にやってくれ!!

👇👇

これは一体なんの記事なんや!?(あらためて一応)

さて、今日のソフトウェア開発においてはCI/CDがめちゃくちゃ大事なものとして取り沙汰されがちです。
実際どのくらい重視するかは現場によりけりですが、テックタッチのように toB の SaaS を開発する場合はもう説明の必要がないくらい大事です。

海外のアニメより、燃えている部屋の中にコミカルな犬のキャラクターが座って呆然としているシーン。そこにキャプションで「A WORLD WITHOUT CI/CD」と書いてある。
Mallaidh Mleziva; Why the World Needs CI/CD より

そして特に、CI を如何に高速にまわすかはめちゃんこ重要なワケです

……でも誰しもがこんな悩みを抱えたことがあるはずです👇

  • 「え〜ん😭 CI がぜんぜん速くならないよお、、、」
  • 「遅いよお、、、」
  • 「どんだけがんばっても自動テストに3日かかっちゃうよお、、、」

「自動テストに3日かかっちゃうよお」はなかなか珍しいかもしれませんが、いずれにせよ CI の高速化はエンジニアを熱くする永遠のテーマの1つです(知らんけど。でもそうでしょう!?)。

さて、ここに Nx Cloud という便利な道具があります
Nx Cloud とは、モノレポツール Nx と組み合わせて使用されることで CI を爆速にするクラウドサービスです。

    _____
./        /|
| ̄ ̄ ̄ ̄ ̄| |    <  実際はソフトウェア、実体はコードでは?
|Nx Cloud| |
|_____|/

本当の自分に気づき、韻を踏む Nx Cloud の図

👆なにこの図!?

さて「Nx Cloud ?なんだいそれは?一体どんくらい速くなるってんだい??」という声が聞こえてきます。うんうん。
なんとテックタッチでは Nx Cloud のおかげで CI の1回あたり実行時間が12分から7分になりました!
厳密には Nx Cloud を入れたあとに Nx Cloud の効果を最大化するためのフローの組み直しやコンテナスペック調整など、色々な打ち手を実施しているので「入れただけ」ではありません👶
ただ、御手製スクリプトによるテスト並列実行、Jest の CPU 使用数調整、CI コンテナのスペック調整などなどなどよく言われる打ち手はだいたい実施済みだったところから40%近い削減効果を捻出したのは CI ツールとして相当優秀なのではないかと思います。

さあそこで本題です。
この記事では前後編2回に分けて、Nx Cloud の主な機能の紹介と実際の導入の仕方を解説します!!
前編にあたる本稿では、Nx Cloud の2大最強ポイントである「CIの分散並列実行」「CIのキャッシュ利用」を紹介します。

というわけで、あたしゃこんな人に読んでいってほしいよ!

  • Nx Cloud の使い方が分からない
  • Nx の並列実行処理に興味がある
  • CI が遅くて CI の並列実行処理を入れてみたい
  • なんでもいいからマイナーなツールの話が知りたい
  • 他に読むものがない(👈そんな人いる?)

そもそも Nx ってなに?(ちょっとだけ説明するよ)

大前提として Nx Cloud は Nx というツールを使用しているレポジトリで使うものなのですが、その Nx についても一瞬だけ説明しておきます!!

Nx とは、いわゆる「モノレポフレームワーク」です。
要するに、色々なアプリケーションを同じレポジトリで開発(=モノレポ開発)するときに使うと便利なアプリケーション👶

モノレポ開発において便利な機能が色々そろっており、例えば下記のように色々な場面で Nx の機能が活躍します。

まあこんな感じで便利なワケ!

オーケー、わかった。で、結局そのクールなソフトウェアは一体何をしてくれるって言うんだ?

さてさて、ようやく Nx Cloud の話が始まります……
Nx Cloud の機能は色々あるのかもしれませんが、目玉は要するに2つ。

  • コマンドの自動分散並列実行
  • コマンド実行結果のキャッシュ

これを聞いて「ふ〜ん、興味ないわ」ってなった方(いまさらそんな人いる?)も、もうすこし読んでいってください!!こっからが面白いんです!!

順番に見ていきまっせ〜〜〜👶👶

1. コマンドの自動分散並列実行

これは「複数プロジェクトを対象にあるコマンドを実行したとき、自動で分散して並列実行してくれる」という機能です。

これだけだとよくわからないと思うので、ちょっと具体例で考えてみましょう。
今回の話はモノレポが前提ですから、レポジトリに多くのプロジェクトが存在するとします
だから、例えばこんなディレクトリ構成だったりするわけです。映画館の席管理システム的な?

# サブディレクトリ1つ1つが Nx において「プロジェクト」と呼ばれる単位です
apps/
  booking/
  check-in/
libs/
  ticket/
  api/
  seatmap/
  profile/

このときテストをapps/booking, libs/ticket, libs/profileで実行する場合、Nx は便利なのでこんな書き方ができます。

nx test -t booking, ticket, profile

便利ですねえ〜!

さて、これをリモート CI 環境で実行したとしましょう。
もし何の工夫もなければ3つのプロジェクトのテストすべてが1台のマシンで順番に実行されます
しかしテストは並列で実施したいのが人の心であり世の常であります。実際、こういった3つのプロジェクトは並列にテストができるように作ってあることがほとんどでしょう。

ここで、そのような並列実行をがんばってスクリプトを書いて実現するという手段もあります。
ただ、忘れてはならないのはテストしたいプロジェクトは毎回毎回変わるということです。
実際これはモノレポなんだから、せっかくなら「前回コミットと差分があったところとそれに依存する部分だけピックアップしてテストする」のがオイCやり方なわけで、テストしたいプロジェクトも、その個数も当然変わるわけです
また、工夫しないとログが散らかってしまったり、テストに限らず CI 全体まで考慮すると場合によっては順序依存を持つジョブ群があったりするでしょう。

というわけでやっぱりスクリプトはちょっとがんばる必要が出てきます(テックタッチはがんばってやっていました👶)。

そこで Nx Cloud が登場

    _____
./        /|
| ̄ ̄ ̄ ̄ ̄| |    <  任せて下さい分散実行、かかってきなさい瞬間一掃
|Nx Cloud| |
|_____|/

上機嫌で韻を踏みながら並列実行する Nx Cloud の図

👆なにこの図!?

Nx Cloud は並列実行を、ジョブを自動で分散して実現してくれます
具体的には、こちらが指定した数のマシンを立ち上げて、マシンごとの計算状況をモニタリングしながら、手が空いているマシンを見つけ次第タスクを入れてくれます。すごいねえ👶

下記は公式による並列実行の解説の図ですが、こんな風にクラウド経由でマシン間の成果物共有も必要に応じて行われるのです(下図のケースでは、e2e には build の成果物が必要だということでマシン間で成果物が共有されている)!嬉しいですねえ👶
なお、分散して実行されるのにログはちゃんと1つのコンテナに集約できますよ!

build, test, lint, e2eという4つのジョブがNx Cloudを通して4つのマシンに分散され並列で実行されることの図解。あるマシンでbuildジョブにより作られた成果物が、他マシンがe2eジョブを実行する際にクラウドを通じて共有されることも図解されている
Nx 公式ドキュメント; Distribute Task Execution (DTE) より

テックタッチは実際に CircleCI で利用していますが、下のような雰囲気です(initialize で CI の初期化を終えたあと、タスクを分散実行している)。
Nx Cloud が立ち上げるマシンには好きな名前をつけられるので、それも楽しいヨ🌝 CircleCI上でNx Cloudを使った際の実際の画面。分散実行を担う各マシンの名前が色々な表情の顔文字になっている。

2. コマンド実行結果のキャッシング

さあ、2つめの目玉機能です。これは読んで字の如く。
ビルド成果物、テスト結果(出力はもちろんカバレッジファイルも)、VRT で撮影したスクショデータ、型チェック結果などなど、コマンド実行の結果や成果物をキャッシュしてくれます

これも、もう少し具体的な流れを見てみましょう。再びこのディレクトリに戻ります。

apps/
  booking/
  check-in/
libs/
  ticket/
  api/
  seatmap/
  profile/

これらが下記のような依存関係を持つとします。 計6つのプロジェクトの依存関係の図。プロジェクト名はcheckIn, ticket, api, booking, profile, searmapの6つ。checkInはticketとapiに依存し、bookingはprofileとseatmapとapiに依存し、profileはticketに依存している

さて、あなたは Nx Cloud を導入したばかりの開発環境で、ticket プロジェクトに手を入れる作業をしているとします。
そしていま Nx Cloud が導入されてから初めて自分のブランチでテストを実施しました
このとき Nx によれば main ブランチとの差分は ticket プロジェクトのみだったようで、ticket およびそれに依存するプロジェクトののべ4プロジェクトに対してテストが実行されました

  • ticket
  • check-in
  • profile
  • booking

このとき、 Nx Cloud のキャッシュはまだ何もありませんから、4つのプロジェクトすべてのテストが順当に実行されます

では、その後 seatmap を変更して、もう一度テストを実行します
seatmapを変更したので、 main ブランチとの差分は ticket に加えて seatmap にも存在することになりますね。
Nx は再び main ブランチとの差分が存在する場所およびそれに依存する部分をテストの実行対象とします。つまり、先ほどの4つのプロジェクトに seatmap が追加された、のべ5プロジェクトでテストが実行されます

  • ticket
  • check-in
  • profile
  • booking
  • seatmap 👈 あたら©

さあ、ここでクイズです。このとき Nx Cloud さんはどうするでしょうか?

  1. seatmap だけテストをやって、残りはさっきの結果を持ってくる
  2. seatmap と booking だけテストをやって、残りはさっきの結果を持ってくる
  3. なんかもうワケわかんなくなってテストしない
  4. 逆に全部テストする

チクタクチクタク ……

……

さあ、そろそろよいでしょうか?

……

……

正解は b の「seatmap と booking だけテストをやって、残りはさっきの結果を持ってくる」です!

c と d は冗談なので置いておいて、ここでは a の「seatmap だけテストをやって、残りはさっきの結果を持ってくる」ではないのがポイントかと思います。
なぜ新しく変更を加えた seatmap だけでなく booking のテストも実行されるのでしょうか?
先ほどの依存関係をもう一度見てみましょう。 計6つのプロジェクトの依存関係の図。プロジェクト名はcheckIn, ticket, api, booking, profile, searmapの6つ。checkInはticketとapiに依存し、bookingはprofileとseatmapとapiに依存し、profileはticketに依存している

ポイントは booking が seatmap に依存していることです!

そうです、プロジェクト間の依存関係をもとに判断すれば seatmap に変更を加えた以上 booking もテストすべきなのです。seatmap に依存する booking のテスト結果が既にオシャカになっていることに Nx Cloud は気づいているのです。
なんでも知っているんだねえ!?

さて、具体例を通じてイメージをつかんで頂けましたか?👶
要するに「コマンド実行結果のキャッシュ」とは、あるプロジェクトに対してCIジョブが実行されたとき、そのプロジェクトおよびそのプロジェクトの依存先ともにソースコードが以前と同じなら以前の結果をノータイムで返してくれるし、逆に、依存先含めてどこかが変わっているなら、ちゃんと再実行されてキャッシュが更新されるという話なのです🌝

これだけでも十分に嬉しいのですが、まだもう2つ下記のうれしポイントがあります。
2とかナカナカ刺激的じゃないですか?👶

  1. キャッシュは Nx のサーバーに勝手にいい感じに置いてくれます。自分たちのレポジトリで管理する必要も、キャッシュの置き場やディレクトリ構成に悩む必要も一切ないです!
  2. キャッシュはローカルとリモート、両方の実行が出処になります。要するに、誰かが自分のマシンでローカルでテストを実行すれば――もちろんネット接続は必須ですが――その結果は他の誰かのローカルでのテスト実行時も、CircleCI のような CI でのテスト実行時もキャッシュとして参照されます!

さて、ここまで話した上でもう一度書いておきます。

  • VRT で撮影したスクショ
  • ビルド成果物
  • Jest によるテスト結果の出力、カバレッジファイル
  • tsc による型チェック結果の出力

Nx Cloud は、こういったものをすべてキャッシュして即座に返してくれます
「ビルドが遅いなあ」とか「VRT のネックはスクショやな……」とか、そんなこと言っている場合じゃなくなるかもしれませんヨ!

えんもたけなわ

さてさて、楽しい時間は一瞬で過ぎ去ってしまうものでありまして、前編はここでおしまいとなります😭
「こんな面白い、すごいツールがあるんだねえ!?」となった方も、「ふ〜ん」で終わってしまった方もぜひ後半戦を楽しみに待っておいて頂けると嬉しいです!
後編では――Nx をすでに導入している前提になるとは思いますが――この激ヤバツール Nx Cloud の導入方法とハマりどころ(テックタッチCIチームがハマったところ!!!)を解説しちゃうゾ☆

ではでは今日はここまでであります、またね〜👶👶