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

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

# どうしてまとめる必要が？
[The Twelve-Factor App（日本語訳）](https://12factor.net/ja/)
こちらをご覧いただくと分かるかと思いますが、**非常に分かりにくい**です。

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

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

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

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

## 各項目について
先述した通り原文が非常に分かりにくいので、要約して簡潔に紹介していきます。
<font color="Red">基本太字の部分だけ読んでいただければ大丈夫</font>なように記載しました。

### Ⅰ.コードベース
**ソースコード[^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の解説を試みる](https://www.slideshare.net/masatoshitada7/twelvefactor-app)

[^1]: GitHubのリポジトリと捉えていただいて大丈夫です。
[^2]: ソフトウェア内で使用する設定値ではなく、環境ごとに異なりえる設定値(DB定義やファイルの出力先等)のことを指します。
[^3]: スケールアップのこと。サーバ自体の性能を上げて処理能力を向上させること。
[^4]: スケールアウトのこと。サーバを増加させて全体の処理能力を向上させること。