定数の管理設計方針
設計やプログラミングにおいて、「定数」というモノはよく登場する。そしてそれらの定義の仕方も様々である。
- プログラミング言語仕様が持つ「定数」、ないしは「定数クラス」として定義素r
- Java でいう
static final
、JavaScript ならconst
で変更を許可しない、など
- Java でいう
- プロパティファイル、コンフィグファイル
.properties
XML でも YAML でも JSON でも、ファイルに定数を書いておき、プログラムはファイルを読み込んで利用する
- DB にマスタテーブルを作成する
- 環境変数に登録し参照する
- ココでは JVM の起動オプションの引数として与える場合も同様の方法とみなす
古のアプリだと「定数クラス」と「プロパティファイル」の組み合わせが多く、ビジネスロジックが絡むモノは「DB マスタテーブル」が使用されることが多かった。
今日では Docker や Kubernetes などコンテナ化の仕組みに沿って、「プロパティファイル」の利用が減り、「OS の環境変数として注入する」方式が増えてきたと感じる。
では、全ての定数を「OS の環境変数から注入する」方式で定義するべきなのか。全て「定数クラス」として定義するのはどうなのだろうか。
結論から言えば、これら定数の管理方式は、その定数の使われ方、影響の与え方によって変えるべきである。一つの方法に集約するのがベストではない。
- プログラム内に記述する定数や、それらをまとめた「定数クラス」は、定数の変更時にロジックにも変更が入る可能性が高いモノに使用すると良いだろう
- 例えばドル通貨を示す
$
記号などは、その記号が変わる際は既存の金融関連のロジックが大きく変わっている可能性が高い。ロジックと定数値を近い位置に置いておく方が分かりよく、また「外部から記号だけを差し替えたい」ことは皆無だと思うので、プログラム内に閉じ込めておいて良いだろう - ちなみに、プログラム内の全ての定数を単一のクラスで管理するような「神定数クラス」は、一見して定数の一覧が見やすいと思う人もいるかもしれないが、あまりオススメしない。どこから参照されているのかスコープが分からなくなるためだ。できればビジネスロジックに近いところで、
private
なアクセス修飾子で示しておくと、対象の定数を使っている範囲が狭まるので分かりやすい
- 例えばドル通貨を示す
- DB にマスタテーブルを作る方式は、「カテゴリ定義」など、その個数や種類が増減しうるが、増減があってもプログラムには影響がない値の管理には向いている
- プログラムを再ビルド、再起動することなく、マスタ値の変更を反映させたい場合には有用
- プロパティファイルやコンフィグファイルとしての注入は、デプロイの際に変更を加えたい場合に用いると良い
- ビルドされるバイナリファイルや成果物群にはプロパティファイルを内包せず、ビルドした資材とプロパティファイルを一緒に配置することでデプロイする方式
- 1回ビルドした資材は再利用しつつ、プロパティファイルの記述によって動作や条件分岐を切り替えたい場合に用いると良いだろう
- OS の環境変数から注入する方式は、Docker や Kubernetes などによるコンテナ化が進んだ現在は「プロパティファイルによる注入」を内包する標準的な手法
- Docker であれば
--env
で定数値を1つずつ定義し、--env-file
で環境変数ファイルを丸ごと注入できる - Kubernetes であれば ConfigMap や Secret を使用して定数値ごとにでも、それをファイルとしてマウントすることもできる
- 内部利用するライブラリの都合などで、プロパティファイルしか受け付けない場合は、ファイルマウントの方法で OS 環境変数の注入と同様に扱えば良い
- いずれも、ビルドはし直さずに振る舞いだけを変えたい場合に利用すると良いだろう
- Docker であれば
ビジネスロジックの変更時にどのくらい定数値に変更が入りやすいかといえば、「定数クラス」が一番可能性が高く、次いで「DB マスタテーブル」、そしてそのビジネスロジック自体を切り替えるような外部注入を「OS 環境変数」(ないしは「プロパティファイル」) が担う、という考え方だと筋が通るだろう。
- 関連ブログ記事 : 2016-09-29 定数ってどう管理するのが良いかね