DB設計で悩む区分データをテーブルとプログラムファイルのどちらで管理すべきか

DB設計で悩む区分データをテーブルとプログラムファイルのどちらで管理すべきか
2021年07月16日2023年10月10日

システム開発のDB設計をやっている時に悩むことがあります。
それはチェックボックス等で使用する複数項目をDBにマスターテーブルを作成して管理するか、プログラム内で定数として配列で管理するかです。

なに言っているわかりずらいので実際にサンプルで説明します。

項目をどのように管理すべきか

今回わかりやすいように契約タイプがあったとします。

  • アルバイト
  • パート
  • 派遣社員
  • 正社員
  • その他


まずDBで管理する方法で考えてみます。

DBで管理する場合は、契約タイプ用のテーブルを作成して、このようにデータを設定するかと思います。

mysql> select * from contract_types order by sort_number asc;
+----+-----------------+-------------+---------------------+---------------------+
| id | name            | sort_number | created_at          | updated_at          |
+----+-----------------+-------------+---------------------+---------------------+
|  1 | アルバイト      |           0 | 2021-07-09 00:00:00 | 2021-07-09 00:00:00 |
|  2 | パート          |           1 | 2021-07-09 00:00:00 | 2021-07-09 00:00:00 |
|  3 | 派遣社員        |           2 | 2021-07-09 00:00:00 | 2021-07-09 00:00:00 |
|  4 | 正社員          |           3 | 2021-07-09 00:00:00 | 2021-07-09 00:00:00 |
|  5 | その他          |           4 | 2021-07-09 00:00:00 | 2021-07-09 00:00:00 |
+----+-----------------+-------------+---------------------+---------------------+

プログラム側では契約タイプ用のテーブルをJOINして契約タイプ名を取得して表示する流れになります。

仕様によっては、契約タイプによって処理を変えたいということが出てきた場合は、分岐を入れる必要が出てきます。

例えばこんな感じにです。

// 契約タイプが正社員か
if($contractType == 4){
  
  // 正社員の場合の処理
}

マジックナンバーを防ぐために「4」を定数に切り替えてみます。

const CONTRACT_TYPE_PERMANENT = 4
------------------

// 契約タイプが正社員か
if($contractType == self::CONTRACT_TYPE_PERMANENT){
  
  // 正社員の場合の処理
}

ここでふと思うのです。「気持ち悪い」と。。。

DBでも管理して定数でもマジックナンバー防止するために定数化することでDBとソースコードの2重で管理することになり、気持ち悪い状況が発生します。

実際の現場でもたくさん存在します。

2重管理を防ぐには

このように2重で管理するのはプログラム上バグを生むことになるため、なるべく避けたい事象です。

ではどのようにしたらよいのか。

項目の内容で分岐が入る場合は、定数ファイルで管理する。項目の内容で分岐が入らない場合は、DBで管理すれば良いです。

もちろんマスタをメンテしたいとか、アソシエーションを組みやすいかなどでDBでの管理が良いはありますが、特段理由がない場合は分岐が入るか入らないかで判断すると良いです。

ファイル内で定数で管理する場合は、定数ファイルを作成して下記のように管理すると使いやすいです。

class ContractTypeConst
{

    const CONTRACT_TYPE_ARBEIT = '1';

    const CONTRACT_TYPE_PART = '2';

    const CONTRACT_TYPE_TEMPING_EMPLOYEE = '3';

    const CONTRACT_TYPE_PERMANENT_EMPLOYEES = '4';

    const CONTRACT_TYPE_OTHER = '5';

    const CONTRACT_TYPE_ARBEIT_NAME = 'アルバイト';

    const CONTRACT_TYPE_PART_NAME = 'パート';

    const CONTRACT_TYPE_TEMPING_EMPLOYEE_NAME = '派遣社員';

    const CONTRACT_TYPE_PERMANENT_EMPLOYEES_NAME = '正社員';

    const CONTRACT_TYPE_OTHER_NAME = 'その他';

    const CONTRACT_TYPE_LIST = [
        self::CONTRACT_TYPE_ARBEIT => self::CONTRACT_TYPE_ARBEIT_NAME,
        self::CONTRACT_TYPE_PART => self::CONTRACT_TYPE_PART_NAME,
        self::CONTRACT_TYPE_TEMPING_EMPLOYEE => self::CONTRACT_TYPE_TEMPING_EMPLOYEE_NAME,
        self::CONTRACT_TYPE_PERMANENT_EMPLOYEES => self::CONTRACT_TYPE_PERMANENT_EMPLOYEES_NAME,
        self::CONTRACT_TYPE_OTHER => self::CONTRACT_TYPE_OTHER_NAME
    ];
}

プログラム内はこんな感じで使用します。

// 契約タイプが正社員か
if($contractType == ContractTypeConst::CONTRACT_TYPE_PERMANENT_EMPLOYEES){
  // 正社員の場合の処理
}

// 契約タイプ名を取得
$contractTypeName = ContractTypeConst::CONTRACT_TYPE_LIST[$contractType];

DBもしくはファイルのどちらかで管理できるのであれば、どちらかに統一したほうがよいです。

さいごに

今回はデータの二重管理を防ぐ方法について紹介しました。

実際の現場ではマスターテーブルで管理していたものをクライアントから「〇〇の時だけこの処理をしてほしい」と言われ、結果二重管理になることが多々あします。この場合は、どうしようもないです(笑)

コメント

コメントを残す

お名前(任意)
コメント:新規