ビルドシステムを選ぶ理由

問題を報告 ソースを表示 毎晩

このページでは、ビルドシステムの概要、仕組み、ビルドシステムを使用するべき理由、組織のスケーリングを始める際にコンパイラとビルド スクリプトが最適ではない理由について説明します。ビルドシステムの経験があまりないデベロッパーを対象としています。

ビルドシステムとは

基本的に、すべてのビルドシステムには単純な目的があります。エンジニアが記述したソースコードを、マシンが読み取れる実行可能バイナリに変換します。ビルドシステムは、人が作成したコードだけのものではありません。テストや本番環境へのリリースのために、マシンが自動的にビルドを作成できるようにします。数千人のエンジニアが存在する組織では、ほとんどのビルドがエンジニアによって直接ではなく、自動的にトリガーされます。

コンパイラだけではいけませんか?

ビルドシステムの必要性はすぐにはわかりません。ほとんどのエンジニアは、コーディングの学習中にビルドシステムを使用しません。ほとんどのエンジニアは、gccjavac などのツールをコマンドラインから直接呼び出すこと、または統合開発環境(IDE)で同等のツールを呼び出すことから始めます。すべてのソースコードが同じディレクトリにある限り、次のようなコマンドは正常に機能します。

javac *.java

これは、現在のディレクトリ内のすべての Java ソースファイルを取得してバイナリ クラスファイルに変換するように Java コンパイラに指示します。最も単純なケースでは、これだけで十分です。

しかし、コードが拡張されるとすぐに複雑化が起こります。javac を使用すると、現在のディレクトリのサブディレクトリを調べて、インポートするコードを見つけることができます。ただし、ファイル システムの他の部分(複数のプロジェクトで共有されているライブラリなど)に保存されているコードを見つける方法はありません。Java コードのビルド方法だけを認識します大規模なシステムには、さまざまなプログラミング言語で記述されたさまざまな部分と、それらの部分に依存関係がまとまっていることが多いため、単一の言語用のコンパイラがシステム全体を構築できない可能性があります。

複数の言語や複数のコンパイル単位から生成されたコードを扱う場合、コードのビルドは 1 ステップのプロセスではなくなります。次に、コードが何に依存しているかを評価し、各部分に異なるツールセットを使用するなどして、適切な順序でそれらの部分を構築する必要があります。依存関係が変更された場合は、古いバイナリへの依存を避けるため、このプロセスを繰り返す必要があります。中程度のサイズのコードベースでも、このプロセスはすぐに手間がかかり、エラーが発生しやすくなります。

また、コンパイラは、Java のサードパーティの JAR ファイルなどの外部依存関係の処理方法も認識しません。ビルドシステムを使用しない場合は、インターネットから依存関係をダウンロードし、ハードドライブの lib フォルダに格納して、そのディレクトリからライブラリを読み取るようにコンパイラを設定することで、依存関係を管理できます。時間の経過とともに、このような外部依存関係の更新、バージョン、ソースを維持することが困難になります。

シェルスクリプトについてはどうでしょうか

趣味のプロジェクトが、最初はコンパイラだけでビルドできるほどシンプルなものでしたが、前述の問題に直面し始めたとします。まだビルドシステムは必要ないと考えている方もいるでしょう。正しい順序でビルドを行うシンプルなシェル スクリプトを使用して、面倒な部分を自動化できます。しばらくすると役に立ちますが、すぐにさらに多くの問題に遭遇するようになります。

  • この作業は面倒になります。システムが複雑になるにつれて、ビルド スクリプトの作業に実際のコードの場合とほぼ同じ時間を費やすようになります。シェル スクリプトのデバッグは手間がかかり、ますます多くのハッキングが重なって行われています。

  • 処理に時間がかかります。古いライブラリに誤って依存しないようにするため、ビルド スクリプトを実行するたびに、すべての依存関係を順番にビルドするようにします。どの部分を再構築する必要があるかを検出するためのロジックを追加しようとしますが、スクリプトにとっては非常に複雑でエラーが発生しやすい作業です。あるいは、毎回再ビルドする必要がある部分を指定して、それから 1 つ目に戻ります。

  • このたび、リリースの時期になりましたのでお知らせいたします。最終的なビルドを行うために、jar コマンドに渡す必要があるすべての引数を確認することをおすすめします。アップロードして中央リポジトリに push する方法も忘れないでくださいドキュメントの更新をビルドして push し、ユーザーに通知を送信します。別のスクリプトが必要なのでしょうか

  • みなさんにハードドライブがクラッシュし、システム全体を再作成する必要がある。すべてのソースファイルをバージョン管理システムで管理できましたが、ダウンロードしたライブラリについてはどうでしょうか。もう一度すべて探して、最初にダウンロードしたときと同じバージョンであることを確認してください。スクリプトは、特定の場所にインストールされている特定のツールに依存しているかもしれません。その同じ環境を復元して、スクリプトが再び機能するようにできますか?コンパイラを適切に動作させるためにかなり前に設定したすべての環境変数が、その後忘れてしまいました。

  • 問題にもかかわらず、プロジェクトは十分に成功しており、エンジニアの増員を開始できます。これで、以前の問題が発生しても、災害を起こすわけではないことがわかります。新しいデベロッパーがチームに加わるたびに、同じ煩雑なブートストラップ プロセスを経る必要があるからです。最善を尽くしても、各人のシステムには小さな違いがあります。多くの場合、ある人のマシンで動作するものが、別のユーザーのマシンでは機能しません。また、違いを特定するのに毎回、デバッグツールパスやライブラリ バージョンに数時間かかります。

  • あなたは、ビルドシステムを自動化する必要があると判断しました。理論上は、新しいパソコンを入手して、cron を使用して毎晩ビルド スクリプトを実行するようにセットアップするのと同じくらい簡単です。面倒なセットアップ プロセスを経る必要はありますが、人間の脳が軽微な問題を検出して解決できるというメリットはありません。毎朝入ってくると、昨夜のビルドが失敗したのは、デベロッパーが昨日行った変更がシステム上では機能するものの、自動ビルドシステムでは機能しなかったためです。どれも単純な修正ですが、簡単な修正方法を見つけて適用するために、毎日多くの時間を費やすことになることがよくあります。

  • プロジェクトが大きくなるにつれて、ビルドの速度が遅くなります。ある日、ビルドの完了を待っている間に、休暇中のアイドル状態の同僚のデスクトップを悲しみに眺め、無駄な計算能力をすべて活用する方法が欲しいと思いました。

スケーリングという古典的な問題に遭遇しました。1 人のデベロッパーが最大でも 1 ~ 2 週間で数百行ものコードを手作業する場合(これは、大学を卒業したばかりの若手のデベロッパーにとってはそうであったかもしれません)、必要なのはコンパイラだけです。スクリプトを使えば さらに進められるかもしれませんしかし、複数の開発者とそのマシン間で調整が必要になると、たとえ完璧なビルド スクリプトであっても、これらのマシンのわずかな違いを説明することが非常に困難になるため、十分ではありません。この時点で、このシンプルなアプローチは機能しなくなります。次は実際のビルドシステムに投資しましょう。