🍏

webアプリ開発における環境変数まわりのベストプラクティス

に公開
5

Discussion

Error401Error401

環境はその3つだけではなく、開発環境のなかでも設定値のバリエーションが生まれたりします。いっそのこと開発環境・テスト環境・本番環境と区別せずに、設定の値だけ環境変数を増やすほうがこのバリエーションに対応できます。

うーん、新しい環境が必要なら、development.yaml, test.yaml, production.yamlがあるところに、staging.yamlを追加します、という方式(大抵のFW/ライブラリ/ミドルウェアが採用している方式)がいい気がします。

どの環境でも同じ環境変数を参照する仕組みにする場合、結局の所、staging.envとかstaging_setenv.shが必要になりませんか?

ハトすけハトすけ

コメントありがとうございます!

うーん、新しい環境が必要なら、development.yaml, test.yaml, production.yamlがあるところに、staging.yamlを追加します、という方式(大抵のFW/ライブラリ/ミドルウェアが採用している方式)がいい気がします。

はい、そうですね、僕もそう思います。ちょっとわかりにくい表現をしてしまいました。ここで伝えたかったことは、アプリケーションコード自体に自分がいまどの環境にいるのかを意識させないということでした。これは言い換えればコードの中に環境識別情報を変数(今回で言うところのNODE_ENV)でif分岐させないという意味です。

例えば以下のようなコードですね。こうなると環境が増えるたびにコード内にNODE_ENVをもとにした分岐が増えていきます。

アプリケーションコード
if(開発環境){
   const logger = new Logger({
    level: 'debug'
  });
} else if (ステージング環境){
   const logger = new Logger({
    level: 'debug'
  });
} else if (本番環境){
   const logger = new Logger({
    level: 'debug'
  });
}

それよりも、その環境による差分を、.env.development.env.productionenv.stagingに入れてしまって

.env.development
LOG_LEVEL=debug
.env.production
LOG_LEVEL=error
.env.stg
LOG_LEVEL=info

アプリケーションコードは素直にその環境変数を受け入れるようにしようという意味でした。

アプリケーションコード
   const logger = new Logger({
    level: process.env.LOG_LEVEL
  });

記事の方をもう少し表現変えたいと思います^^

ハトすけハトすけ

内容変更

変更箇所1

表現の変更

アプリの環境(例えばNODE_ENV)によって設定を分岐しない
->
アプリケーションコードに自分が今いる環境(開発|ステージング|本番)を意識させない

削除

よくDBとかで開発環境・テスト環境・本番環境ごとに設定を分岐させることがあります。The Twelve-Factor Appでも言及されているように、環境はその3つだけではなく、開発環境のなかでも設定値のバリエーションが生まれたりします。いっそのこと開発環境・テスト環境・本番環境と区別せずに、設定の値だけ環境変数を増やすほうがこのバリエーションに対応できます。ただし、環境を扱う環境変数(NODE_ENV)で分岐させたほうが素直な場合も極稀にあります(フレームワークがNODE_ENV環境によって挙動を変えるときとか)。

追記

これはつまり、コード内で環境識別変数(今回で言うところのNODE_ENV)によってif分岐を作らないという意味です。各環境にどのような設定が入るかはアプリケーションコード外にその種類分作成しましょう!

変更箇所2

表現の変更

アプリ自体を.envに依存させない
->
アプリに自分から環境変数を取りに行かせない。

削除

.envを読み込む設定の場合、開発環境ではいいのですが、本番環境だと.envを作成管理しなければいけません。できれば、本番環境はその環境の環境変数をそのまま使うほうが扱いやすいです。各本番環境ごとに、それぞれの環境変数を設定するだけで済みます。

追記

なぜこのようなことをするかというと、アプリ自体に環境変数を能動的に取得してほしくないからです。これは「アプリケーションコードに自分が今いる環境(開発|ステージング|本番)を意識させない」と似ていますが、アプリ側にどの.envに依存するのか、依存しないのかの判断をさせないための防御手段です。アプリ側には素直に渡された環境変数のみに依存してほしいのです。
アプリ自体はピュアに保っておき、どの.envに依存するのか、依存しないのかのバリエーションは外部が注入してあげます。
アプリ自体をピュアに保っていると、本番環境の環境変数を設定しやすいというメリットもあります。

イカフライイカフライ

とても参考になるいい記事でした。ありがとうございます。
一点だけ誤字を見つけたので共有します。


基本.envは気密性の高い項目にはダミーデータしか置かないほうがいいですね。


基本.envは機密性の高い項目にはダミーデータしか置かないほうがいいですね。

Shota TamuraShota Tamura

まさにAPP_ENVやらNODE_ENVを量産して地獄をみた経験があるので首がもげました。「あえて知らせないほうがうまくいく」ことがあるのは人間界でもコンピューター界でも一緒ですねぇ...