The Twelve-Factor App

X. 開発/本番一致

開発、ステージング、本番環境をできるだけ一致させた状態を保つ

歴史的に、開発環境(開発者が直接変更するアプリケーションのローカルデプロイ)と本番環境(エンドユーザーからアクセスされるアプリケーションの実行中デプロイ)の間には大きなギャップがあった。これらのギャップは3つの領域で現れる。

Twelve-Factor Appでは、継続的デプロイしやすいよう開発環境と本番環境のギャップを小さく保つ。 上で述べた3つのギャップを見る。

上で述べたことを表にまとめる。

伝統的なアプリケーション Twelve-Factor App
デプロイの間隔 数週間 数時間
コードを書く人とデプロイする人 異なる人 同じ人
開発環境と本番環境 異なる できるだけ一致

バックエンドサービス(アプリケーションのデータベース、キューイングシステム、キャッシュなど)は、開発/本番一致が重要になる領域の一つである。多くの言語は、異なる種類のサービスへの アダプター を含め、バックエンド・サービスへのアクセスを単純化するライブラリを提供している。以下の表にいくつかの例を示す。

種類 言語 ライブラリ アダプター
データベース Ruby/Rails ActiveRecord MySQL, PostgreSQL, SQLite
キュー Python/Django Celery RabbitMQ, Beanstalkd, Redis
キャッシュ Ruby/Rails ActiveSupport::Cache メモリ, ファイルシステム, Memcached

本番環境ではより本格的で堅牢なバックエンドサービスが使われるにもかかわらず、開発者は自身のローカル開発環境で軽量なバックエンドサービスを使いたくなることがある。例えば、開発環境ではSQLiteを使い、本番ではPostgreSQLを使ったり、開発環境ではローカルプロセスのメモリをキャッシュに使い、本番ではMemcachedを使ったりするなどである。

たとえ理論的にはアダプターがバックエンドサービスの違いをすべて抽象化してくれるとしても、 Twelve-Factorの開発者は、開発と本番の間で異なるバックエンドサービスを使いたくなる衝動に抵抗する。 バックエンドサービスの違いは、わずかな非互換性が顕在化し、開発環境やステージング環境では正常に動作してテストも通過するコードが本番環境でエラーを起こす事態を招くことを意味する。この種のエラーは継続的デプロイを妨げる摩擦を生む。この摩擦とそれに伴って継続的デプロイが妨げられることのコストは、アプリケーションのライフサイクルに渡ってトータルで考えると非常に高くつく。

軽量なローカルサービスは、以前ほど魅力的なものではなくなっている。Memcached、PostgreSQLやRabbitMQなどのモダンなバックエンドサービスは、Homebrewapt-get などのモダンなパッケージングシステムのおかげで、簡単にインストールして実行できる。あるいは ChefPuppet などの宣言的なプロビジョニングツールと、Vagrant などの軽量な仮想環境を組み合わせることで、開発者は本番環境に限りなく近いローカル環境を作ることができる。開発/本番一致と継続的デプロイの利益に比べると、これらのシステムをインストールして利用するコストは低い。

異なるバックエンドサービスへのアダプターは依然有用である。これらのアダプターは、新しいバックエンドサービスに移植するときの苦痛を比較的和らげてくれるためである。しかし、アプリケーションのすべてのデプロイ(開発、ステージング、本番環境)は同じ種類かつ同じバージョンのバックエンドサービスを利用するべきである。