プログラミング
環境構築
初心者
プログラミング教育
新人プログラマ応援

環境とは

この文書において、環境とは以下の要素を指します。

  • プログラムを実行するプラットフォーム(OSやインタプリタ等)
  • プログラムが依存しているライブラリ
  • ライブラリ同士の依存関係

チーム開発における環境の重要性

チーム開発において、複数コンピュータ間で同じ環境を再現することは非常に重要です。メンバー間の環境が異なる場合、特に環境依存の問題について問題の発見および共有、修正が困難となります。これは、メンバーそれぞれの環境が異なることで、問題を再現することに困難が生じる為です。

以下の例を考えてください。

AさんはプログラムPを書き、Aさんの環境ではうまく動きました。ところが、同じプログラムPをBさんが利用しようとするとエラーが発生して使えませんでした。実は、プログラムPはライブラリLに依存しており、Aさんは以前の開発でライブラリLをインストールしていた為、プログラムPを動作させることができましたが、Bさんの環境にはライブラリLがインストールされていなかったのです。

そこで、BさんはAさんに、プログラムPが動作しないよ、と伝えます。ところが、開発者のAさんの環境ではプログラムPは動作する為、何が問題なのかわかりません。

これは、もっとも簡単な環境依存の問題の例です。よくある具体例として、Windows上におけるVC++ランタイムライブラリが挙げられます。また、今回は依存性が単純ですが、実際の開発では依存が深く、ライブラリLが依存しているライブラリMがあって、さらにライブラリMが依存しているライブラリNがあって、そのライブラリNが依存しているライブラリXが欠けていた、という風に依存性の連鎖の深い部分で問題が発生することも起こりうります。

つまり、チーム開発において、メンバー間の環境の差異は致命的となります。

環境はメンドクサイ

ところが、メンバー間の環境を完全に一致させようとすると、すぐに問題にぶつかります。メンバーのすべてのPCについて、同じOSを使い、同じソフトウェアを同じ順番でインストールしていくといった作業は、もちろん開発初期はうまくいくかもしれませんが、時間が経つにつれ指数関数的に困難になっていきます。誰かがライブラリを利用しようとしたら、開発メンバー全員に、同じライブラリをインストールするように頼むほかありません。こんなことをしていたら、本来やるべき開発に集中できず、利用可能な時間のほとんどを依存性解決に費やすことになってしまいます。

また、環境はいともたやすく崩壊します。あるプログラムをインストールしたら、別のプログラムが動かなくなってしまった!ということは日常茶飯事です。その時に、最初から環境を構築し直すのは大変な労力を必要とします。

環境は薄く重ねよう

例えば、システムにライブラリをインストールすると、それはシステムの環境を編集することになります。この時、もしエラーが発生したら、システムの環境を一から構築し直すことになります。これではライブラリをインストールするときのリスクが大きすぎます。

そこで、環境を薄く切り分けることが大事になります。

例えば、アプリケーションのディレクトリ内にライブラリをインストールすることで、「システムの環境」+「アプリケーションの環境」という二層のレイヤーが成り立ちます。この時、仮にエラーが発生しても、アプリケーションの環境を再構築するだけで済みます。システム環境を構築し直すことと比べれば、圧倒的に軽い手間です。

このように、環境を薄く切り分けてから、それらを重ね合わせて利用することで、問題が発生した場合は問題が発生した層のみを修正することが可能となります。

また、当然ですが薄い環境は依存しているライブラリ等の数が根本的に少ないので、文字列として保存することが容易になります。

以上を踏まえて環境を設計しよう

以上の概念に基づき、環境を文字列化し、機械的に同じ環境を構築するツールを利用することで数多くの恩恵を得られます。これらのツールは、上述の薄い環境を構築することに長けている為、利用することで、まず第一に環境を可視化して依存性をわかりやすくし、さらに、複数コンピュータ間で同じ環境を再現することが可能となります。

環境を構築するツールの例

  • docker: プラットフォームの環境(実行環境)を構築
  • npm: アプリケーション環境を構築
  • composer: PHP用のアプリケーション環境を構築

環境構築ツールを利用することは、個人開発においても、以下のメリットを生み出します。

  • コンピュータを問わず、すなわち、場所を問わず開発できるようになります
  • 操作ミスなどで環境が壊れた際も、すぐに環境を回復できます
  • コンピュータをリフレッシュ(OSの再インストール)しても、以前と同じ環境の構築に手間がかかりません

実際の開発では、以下のような環境層を構築することを推奨します。

1. ホストOS環境

複数のプロジェクトで共通して用いる、エディタやgitなどをインストールします。ソースコードなどのプロジェクトファイルもまた、この環境に置きます。ホストOSの環境はアプリケーションの実行に影響を与えない為、この環境を自動構築する必要はありません。各人のおもいおもいに構築することができます。

2. 実行環境

開発したアプリケーションの実行環境です。インタプリタ等の、アプリケーションの実行に必要なもっとも基本的なものだけをインストールします。Dockerを利用する場合は、専用の設定ファイルを記述し、dockerコマンドを利用して自動的に環境を構築することができます。この環境設定は多くのプロジェクト間で共有可能な為、ほとんどの場合はすでに誰かが記述した設定ファイルが存在します。Dockerについての詳しい説明はここでは行いませんが、プロジェクトごとに新たなコンテナを作成し、ホストOSのプロジェクトファイルをマウントして利用するのが基本です。

3. アプリケーション環境

プロジェクトのディレクトリ内に、開発しているアプリケーションが依存するライブラリをインストールします。専用の設定ファイルを記述(もしくは自動生成できます)し、npmやcomposerといったライブラリを利用して自動的に環境を構築できます。アプリケーション環境の操作は、ホストOS環境もしくは、実行環境で行います。

具体例

PHPでウェブアプリケーションを開発する際の具体例を示します。プロジェクトディレクトリの構成は以下のようにします。

/<project-dir>/docker/<docker containers>  // 必要ならば、Dockerコンテナの詳細 
/<project-dir>/src/<source codes>
/<project-dir>/docker-compose.yml          // 実行環境を記述
/<project-dir>/composer.json               // アプリケーション環境を記述

docker-compose.ymlファイルは自身で記述する必要があります。記述後、docker-compose up -dを実行することで、Dockerによる実行環境が生成され、Webサーバーが起動します。

プロジェクトディレクトリにおいてcomposer initを実行することで、アプリケーション環境を記述するcomposer.jsonファイルが自動生成され、さらにアプリケーション環境が/<project-dir>/vendor以下に生成されます。すでにcomposer.jsonファイルが存在する場合は、composer installを実行します。