Twelve-Factor Appを噛み砕いてみた


Twelve-Factor Appって何?

Herokuの中の人が提唱した、モダンなWebアプリケーションとしてあるべき姿を12のベストプラクティスにまとめた方法論です。
モダンなWebアプリケーションは、クラウド上で動くWebアプリ、と読み替えていただいて良いかと思います。
因みに提唱されたのが2012年と少々古い一面もありますが、現在(2018/10)でも通用する項目もありますので、
ここで改めてまとめようと思います。

どうしてまとめる必要が?

The Twelve-Factor App(日本語訳)
こちらをご覧いただくと分かるかと思いますが、非常に分かりにくいです。

  • 特定のプログラミング言語に依存しないように抽象的な書き方をされている
  • 方法論が書かれているのみであり、なぜその方法を採用すべきなのかが書かれていない
  • 記載内容が適切にまとめられておらず、順序もバラバラで捉えにくい
  • 原文が英語であり日本語訳しているため、あまりなじみのない表現が使われている

私も初めて読んだ時点ではさっぱり解釈できませんでしたが、現場で勉強する機会がありある程度ブレイクダウンできました。
この記事を読んだ方の理解の助けになればと思います!

本題

はじめに

前提ともいえる理解すべき原則がありますので記載します。
※ここは大まかな概要みたいなものですので解説しません。

  • セットアップ自動化のために宣言的なフォーマットを使い、プロジェクトに新しく加わった開発者が要する時間とコストを最小化する。
  • 下層のOSへの依存関係を明確化し、実行環境間での移植性を最大化する。
  • モダンなクラウドプラットフォーム上へのデプロイに適しており、サーバー管理やシステム管理を不要なものにする。
  • 開発環境と本番環境の差異を最小限にし、アジリティを最大化する継続的デプロイを可能にする。
  • ツール、アーキテクチャ、開発プラクティスを大幅に変更することなくスケールアップできる。

各項目について

先述した通り原文が非常に分かりにくいので、要約して簡潔に紹介していきます。
基本太字の部分だけ読んでいただければ大丈夫なように記載しました。

Ⅰ.コードベース

ソースコード1とアプリケーションは常に1対1の関係であるようにしましょう。
なぜなら1つのリポジトリから複数のアプリケーションが作られる場合は密結合である可能性が高く、拡張性が著しく低下します。
またその逆に、複数のリポジトリから1つのアプリケーションが作られる場合はビルドやデプロイの手順が複雑化し、思わぬオペミスを引き起こす原因になりかねません。

Ⅱ.依存関係

暗黙的な依存関係は作らず常に使用するライブラリ、システムツール等は明示的にしてアプリケーションだけで完結するようにしましょう。
なぜならシステムツール(curl等)は常にデプロイされる環境で使用できるとは限らないからです。
またアプリケーションで完結できれば、新たな開発者のセットアップにかかるコスト削減につながります。

Ⅲ.設定

設定2はコードや設定ファイルに含めず、環境変数で設定するようにしましょう。
なぜならコードに含めてしまうと環境ごとにビルドが必要になり、設定ファイルの場合は環境ごとにファイルが必要となりスケールしにくくなるためです。
環境変数であればOSが異なっても取得方法は基本的に統一できます

Ⅳ.バックエンドサービス

DBや外部サービスはアタッチ/デタッチ可能なリソースとして捉え、コードを修正しなくても変更できるように環境変数に設定値(URLやユーザ情報等)を定義しましょう。
なぜならコード修正が必要になると環境ごとにビルドが必要となってしまうためです。
また仮にDBが落ちた場合に、環境変数を書き換えるだけで別のDBに接続でき、障害対応が可能になるためです。

Ⅴ.ビルド、リリース、実行

コードを修正する場合には必ずビルド、リリース、実行の順で実行するようにしましょう。
環境ごとにビルドを行ったり、実行中のソースに手を加えたりするとオペミスによる障害につながるため、テスト済みのコードをビルドし、その結果(ビルド)を各環境にリリースして実行するようにしましょう。

Ⅵ.プロセス

プロセスはステートレスなものとし、サーバ内のインスタンスやファイルでステータスを持つことは避けるようにしましょう。
なぜならインスタンスは仮想サーバのスケールアウト/スケールインによって増減するものであり永続的に存在するものではないためです。
永続的なステータスを持ちたい場合はDB等を使用しましょう。

Ⅶ.ポートバインディング

アプリケーション内にサーバを組み込み、サーバ単位ではなくポート単位でサービス公開できるようにしましょう。
それによって環境ごとによるサーバ設定が不要になるためです。
また自分自身も他サービスのバックエンドサービスとして機能を提供することが容易になります。

Ⅷ.並行性

垂直スケール3ではなく、水平スケール4で性能向上させるようにしましょう。
なぜなら垂直スケールの場合はマシン再起動が必要となりダウンタイムが発生するためです。

Ⅸ.廃棄容易性

プロセスの起動と停止が高速に行えるような構成にしましょう。
プロセスの起動が高速であればあるほど、スケールが容易になるためです。
また停止前にはリクエストの受付停止、処理中リクエストの完了待機、各リソースの廃棄を行う(グレースフル)ようにしましょう。

Ⅹ.開発/本番一致

各環境のギャップは最小限になるようにしましょう。

  • 時間のギャップ:開発 -> デプロイを数時間で行えるようにしましょう。
  • 人材のギャップ:開発者が運用も行えるようにしましょう。
  • ツールのギャップ:ローカル、開発環境、本番環境によってツールが異ならないようにしましょう。

Ⅺ.ログ

ファイル出力ではなく標準出力に出力させ、ツールで1箇所に集約するようにしましょう。
なぜならスケールイン時に仮想サーバごと消える可能性があることと、環境(OS、IDE、ローカル/本番)が異なっても標準出力は常に行えるためです。

Ⅻ.管理プロセス

管理プロセスはアプリケーションの初期化処理として実行させるようにしましょう。
なぜなら手動で管理を実行するとオペミスが発生する可能性があるためです。
できる限り自動化しましょう。

最後に

最後までお読みいただきありがとうございました。
いかがでしたでしょうか?
正直おなか一杯だと思います。少なくとも私はおなか一杯です。

これでも分かりにくかった方は、下記参考のSlideShareをぜひご覧ください!
実装についても少し触れているので、よりイメージしやすいと思います。

解釈は様々だと思いますので、「ここはこういう事が言いたいんじゃないか」などコメントお待ちしております!!

因みにこの方法論をもとに、2016年にBeyond The Twelve-Factor Appが存在します。
また機会があればその記事も書いてみようと思います。

またどこかでお会いしましょう!

参考

とにかく分かりづらいTwelve-Factor Appの解説を試みる


  1. GitHubのリポジトリと捉えていただいて大丈夫です。 

  2. ソフトウェア内で使用する設定値ではなく、環境ごとに異なりえる設定値(DB定義やファイルの出力先等)のことを指します。 

  3. スケールアップのこと。サーバ自体の性能を上げて処理能力を向上させること。 

  4. スケールアウトのこと。サーバを増加させて全体の処理能力を向上させること。