Corredor

ウェブ、プログラミングの勉強メモ。

定数ってどう管理するのが良いかね

はじめて学ぶプログラム設計

はじめて学ぶプログラム設計

プログラミングをしていて必ず出てくる定数。基本的に変更が発生しない値のことだけど、これをどこで管理するのが良いのか、考えたい。

定数の保管場所

定数を保管する場所、手段として思いつくものは以下のようなもの。Java 寄りな表現が多いかもなので各言語で対応するものに読み替えてください。

  • プログラム内に定数クラスを作る (Enum なり public static final なりの集合体的なアレ)
  • プロパティファイル (Properties なり XML なり YML なり)
  • DB にマスタテーブルを作る
  • JVM の起動オプションの引数として与える
  • OS の環境変数で設定する

さて、定数をどこで管理しようか。

先に結論

先に結論から話すと、全ての定数をどこか1箇所・1つの手段に集約することがベストではないと思う。定数と思っている情報の性質・適用範囲と管理方法の特性に合わせて都度人間が考えなくてはいけないものだと思う。

じゃあ、定数の性質とは、適用範囲とは、管理方法の特性とは何ぞや、とか、ベストプラクティスはあるんか?とか、そういうことを考えながら話したいと思う。

定数クラス

まず、public static final の羅列で膨らんだ定数クラスは止めるべき。どの定数がどの分野で使われるか分からないから。パッケージなどで区切り、その機能内でのみ使えるものにした方が良い。

で、定数クラスで持つのがベターな情報としては、

  • プログラム中で使うコード値や固定文言で、
  • 一度宣言したら二度と変更が入り得ないもの

に限定するべき、と思う。

例えば、ドルを円に変換する処理があちこちに出てくるような機能があったとしたら、日本の貨幣の単位は今後しばらく「Yen」という表記だろうし、金額の区切り文字は「, カンマ」から変更されることはほぼないだろう。そして、これらを変える必要が出た時 (日本の貨幣単位が変わるような時) は、計算ロジックも手が入ることになるはずだ。

定数を変えるような事態が発生する時は、同時に必ずプログラム修正が入らないと筋が通らない、といったものであれば、プログラム内に定数クラスとして保持しても良いと思う。

あとは、Enum を使ったり、大きめな定数クラスの中に子クラスを作ったりすることで、見た目使いやすくしてあげられればなおよし。

プロパティファイル

ファイルに定数情報を外出ししておく手法。Java 系だと .properties 形式のファイルを見かけることが多いだろうか?適当にデッチ上げたが、以下のようにコード名称とコード値を「=」で結んで定義したりする。

# エラーメッセージの定義
ERR_NOT_FOUND=データが見つかりませんでした。
ERR_TIMEOUT=接続がタイムアウトしました。

モジュール内にプロパティファイルを置いた場合は、グローバルな定数クラスとあまり特性が変わらず、変更の度にコンパイルが必要になるワケで、メリットというメリットがない。

しかし、プログラムモジュールから完全に外出しするにしても、プロパティファイルの位置を示すための情報はモジュール内に書いておかないといけないので、開発環境と本番環境とかでどうしても環境別にプログラム変更をしないといけない部分は出てしまいそう。

ただ、プロパティファイルがモジュールの外にあるということは、モジュールはコンパイル・デプロイし直さずとも、プロパティファイルの書き換えだけで、プログラムの振る舞いを変えられるというメリットがある。

例えば、DB の接続先情報なんかはプロパティファイルに持たせておけば、環境別に切り替えがしやすいし、本番環境で使用する URL 情報などはハードコーディングしたりモジュール内に定数クラスで持ったりするよりは、プロパティで管理した方が、管理構成上のミスが出にくく、影響も少ない。

プログラムモジュールを変えることなく振る舞いを変えられる、という意味で行くと、プロパティファイルは DevOps の文脈の中でフラグによる機能のオンオフを切り替えるために使われたりもする。プログラム内にはその機能を仕込んでおき、リリース時はプロパティファイルでその機能をオンにする、ということをしてやるのだ。

ということで、

  • 1環境の中では変更されることはないが、環境ごとには変えたい設定情報

であれば、プロパティファイルの外出しが有効であろう。

また、ファイルの書き換えで変更できるので、

  • 割と変更される頻度が少なくない情報

も、プロパティファイルに書いておくと良いだろう。

注意点は、ファイルのパスを示したりするためには、やはりモジュール内に手を加える必要があり、OS 環境が異なったりするとさらにモジュール内でプロパティファイルを取得するための考慮が必要になることだろうか。一度こさえておけばいいものではあるが、どんな環境でも万能なものではない。

DB 管理 (マスタテーブル)

定数チックな情報を DB で管理する手法。何かしらのマスタ情報を格納するテーブルを作っておき、ユーザ操作によって UPDATE が行われたりすることがないようにしておくのが基本であろう。

DB 管理のメリットは、マスタテーブルを、その定数値を使用する他テーブルと結合して使いやすいことか。部署名を管理するマスタテーブルと、ユーザ情報のテーブルを結合させれば、ユーザの所属部署名をマスタテーブルから引っ張ってこられる、というような感じだ。

定数クラスやプロパティファイルよりも、DB の方が追加・変更がしやすいだろうから、

  • コード値を変える可能性がまぁまぁある
  • 一つのコード名称で複数の値が拾えて、その値が時によって変更・追加されるような類

であれば、DB 管理が向いていると思う。

JVM 引数

アプリケーションサーバのヒープサイズ設定とかは環境別にすることもあるだろうけど、それはプログラム内で使う定数でもないだろうし、定数として管理することもない気がする。JVM 引数からプログラムに値を渡したりするのも乱暴な感じする…。

というわけで選択肢から外す。

OS の環境変数

DB の接続先情報はプロパティファイルでなくて環境変数にしたりするかも。でもやはり、あんまり使おうとは思わないなぁ。ファイルを置きさえすればどこでも動くようなアプリケーションでありたい気がするので、OS まで手を入れたくない感じする。

というわけでこれも選択肢から外す。

変更が発生しうる頻度

個別の特徴を見てきたので、ここからは用途別に考えてみる。

定数とする対象の情報について、変更が入りやすい順に、どの手法がいいか、というと、

  1. DB 管理
  2. プロパティファイル
  3. 定数クラス

だと思う。コードに近いほど、定数値が変えにくい感じ。

情報の種類別にオススメ

ここまで書いてきたもののまとめみたいな感じだけど。

  • ユーザに見せない、プログラム処理で使うモノなら定数クラス
  • プログラムは同じままで、環境ごとに動きなどを変えたい情報はプロパティファイル
  • 定数の内容に追加・変更が入ってもプログラムの振る舞いが変わらない情報は DB 管理 (マスタデータ、な感じに近い)

こんなふうにぼくは思います。

以上

こんな場合はどうするのがいいか、とか、こういう場合はこうした方がいい、とかあればコメントください。

参考