本文へ
ハクソク

世界を動かす技術を、日本語で。

AIコーディングがCIのボトルネックを引き起こしたため、私たちはそれに対応するために再構築しました

元記事: 原文(linear.app)

概要

  • LinearのCIコスト削減と高速化の取り組みの全体像
  • インフラ・ツールの刷新やジョブの最適化、セットアップの削減
  • テスト実行効率化による待ち時間とランナー時間の短縮
  • 具体的な施策と効果の定量的な説明
  • 今後も継続的な改善が必要であることの強調

LinearにおけるCIコスト削減とパフォーマンス最適化

  • 2024年初頭、 CTOのTuomas より「CIコストが高い」との課題が割り当てられ、 CIの高速化 も同時に依頼
  • 開発速度向上により、 CIがボトルネック となり、インフラコスト増加やフィードバック遅延が発生
  • 施策により、 PRのCI待機時間 を6分超から5分強に短縮、 テストごとのランナー時間 も半減
  • 年初からテストスイート数が4倍近く増加したが、効率化を実現

CI最適化の主な4つの施策

  • インフラ・ツールのアップグレード
  • 他ジョブのゲートとなるジョブの最適化
  • 繰り返し発生するセットアップの削減
  • テスト実行自体の効率化

インフラとツールの刷新

  • GitHub Actionsから高速なサードパーティランナー へ移行し、同一パイプラインで 平均34%高速化、特定ワークロードでは 52%短縮
  • TypeScriptコンパイラをtsgoへ切替、型チェック処理のボトルネックを解消し 73%短縮
  • Lintルールの静的解析化 で型情報依存を排除し、 API lint時間68%削減、リポジトリ全体55%削減
  • Oxlint導入 により、さらにランナー時間を節約

クリティカルパス上のジョブ最適化

  • PRで変更されたパスの検出ジョブ を最適化し、不要なフルチェックアウトを排除
    • fetch depth制限 で最遅ジョブを94秒→20秒に短縮
    • 不要なcheckout削除 で27秒→7秒に短縮
    • sparse checkout導入 でさらに11秒短縮
  • checkoutの堅牢化 のため、独自アクションでリトライやキャッシュ利用、ネットワーク障害時の即時中断を実装
  • キャッシュマーカー書き込みのタイミング変更 で、merge queueでの待機時間を42秒短縮

セットアップコストの削減

  • 共通依存パッケージの事前インストール でAPIテストシャードごとのセットアップを短縮
  • 必要なパッケージのみインストール でpnpm install時間を44-73秒→16-18秒へ短縮
  • node_modulesキャッシュの廃止 でインストールの方が高速に
  • データベースセットアップのスナップショット化 で12秒→1-2秒へ短縮
  • 短時間ジョブのバッチ化 でランナー起動回数を削減し、月間87,000分(総CI使用量の11.8%)節約

テスト実行の効率化

  • Vitestによるテストファイル単位分割 で大きなテストファイルを細分化し、8シャード化で19%高速・19%コスト削減
  • isolate: falseプロジェクト導入 で安全なファイルはモジュールレジストリを共有し、最大17%の月間コスト削減
  • シャード数増加の効果 はセットアップ最適化とセットで初めて実現
    • セットアップ最適化前は4シャード8.3分、最適化後は8シャード7.5分

継続的改善の必要性

  • 改善前であれば、 現在のテストスイート実行に11分 かかる計算
  • 週2,000テスト増加 のペースで今後も拡大見込み
  • 新たなボトルネック に対しても、今回の知見を活かし改善を継続

提供: ハクソク · 要約更新:

AIによる日本語要約です。内容は原文とあわせてご確認ください。

Hacker Newsの議論を読む

Hackerたちの意見

セットアップコストを払えるなら、Bazelを使えば、巨大なプロジェクトでもキャッシュが温まっていれば約10秒でビルドできるよ。

└

数年前に、5つ以上のプログラミング言語で書かれたかなり複雑なソフトウェアのBazel移行をリードしたんだけど、完了するまでに数年かかったよ。もっとシンプルなプロジェクト(1つのプログラミング言語で、3つの主要なOSに配信するもの)では、私の知識とエージェントを使って2週間でBazel移行を終えた。Bazelのセットアップコストはかなり下がったし、業界全体がそれに気づいていないと思う。

└

Bazelについて具体的にはコメントできないけど、nxとturboの両方で作業した経験から言うと、ボトルネックは通常ネットワークとディスクのIOPSで、計算ではあまりないんだ。完全にキャッシュされた出力でも、リモートサーバーから取得して読み込む必要があるし[1]。ステップn-1の出力をリモートキャッシュサーバーから取得してディスクに書き込んで、またステップnで読み込む必要がある[3] - これらはすべてディスクI/Oとネットワークに依存する操作だよ。10秒は、Bazelがよく使われるJava/C++の世界では達成可能かもしれないけど、TSエコシステムでは、多くの人が大きなモノレポで1〜2分の範囲に入るだけでも大喜びすると思う。ここで「ビルド」をもっと明確に定義する必要があるね。トランスパイル/コンパイルのステップだけを実行するのか、それともテストを含む一連のステップ全体を指すのか(ここでLinearの投稿が話しているのはそのこと)。仮想DOMや実際のブラウザが必要な大規模なテストスイートの小さなサブセットでも、10秒以内で実行できるのは難しいと思うよ。[1] 管理されたCIセットアップでは典型的。[3] 異なる言語の一般的なフロントエンド+バックエンドスタックなど。

└

Bazelには多くのトレードオフがあるみたいだね。各タスクのサンドボックスのセットアップ時間から、並行して「普通の」ツールを維持するための使い勝手まで。さらに、「温かいキャッシュ」を使うと重い作業ができるけど、1週間の開発での実際のキャッシュヒット率はどれくらいなんだろう?コールドビルドや頻繁なアクションの改善に投資することは、Bazelや他のインクリメンタルビルダーでも重要だと思う。Bazelについて広く話すのが有用かどうかはわからないけど、実際のパフォーマンスや動作は使うルールに依存するからね。Bazelをturbo/nxのように設定して、各package.jsonモジュールでtsc/vitest/eslintをキャッシュすることもできるし、変更のたびに追い出されるキャッシュユニットを得ることもできる。あるいは、Gazelleを使ってファイルごとのアクションをターゲットにすることもできるけど、依存関係が変わらない限り無効にならないんだ。でも、ワーカーを使わない限り、バッチ処理のトレードオフがあるね。

└

AI時代にこれって本当に簡単なの?エージェントが得意とするはずの、繰り返し可能で検証可能な作業のように見えるけど。

Linearはもうずっと前に完成していて、これ以上の機能は必要ないから、AIコーディングはゆっくり進んでるのがいいね。ああ、次のJiraになりつつあるのか :(

└

Linearの進化については複雑な気持ちだな。いくつかの機能はあまり好きじゃないけど、全体的には使いやすさを保ってると思う。Jiraみたいになってきてる感じはしないけど、慎重に考えられたプロダクトデザインが失われつつある気がする。コードが簡単に生成できるようになったからかな。Jiraみたいになることは心配してないけど、魂を失ってしまった感じがする。それでも素晴らしい製品だよ。

└

すべてのソフトウェアは、古い巨大企業ではなく、新しくて速くてシンプルだから人気になる。そしてすべてのソフトウェアは成長し続けて、新しい巨大企業になり、命のサイクルが再び始まる。

私の場合、ボトルネックはCIじゃないんだ。人間のテストの方だよ。動くことは確かだけど、実際に私たちが求めていることをやっているのか(もっと重要なのは)、お客さんが理解できて、実際に気に入ってくれるやり方でやっているのか?

└

これは層のある問題だと思ってる。もし一番下の層(CI)がエージェントの出力に追いつけないと、上の層での問題解決、例えばユーザーエクスペリエンスのチェックなんかは、指数的に遅くて信頼性が低くなる。内側のループを最適化することで、プログラム全体が速くなるのと似てるね。

└

明らかに、古い人間のテスターをエージェントAIテスターに置き換えなきゃダメだよね。速度が上がるにつれて、人間のユーザーがボトルネックになって、すべての変更や新機能についていけなくなる。幸いなことに、簡単な解決策がある:人間のユーザーをエージェントAIユーザーに置き換えればいいんだ。

└

LLMのおかげで、コーディングやソフトウェアが「できるだけ多くを壁に投げつけて、何がくっつくか見る」状態になってる気がする。かなり短絡的で無駄だと思う、特に人類がエネルギーの生産と消費についてもっと良くならなきゃいけないことを考えると。ちょっと暗い気持ちになるね。

Hacker Newsで議論の続きを見る