Webアプリの開発では、あるテーブルにステータスカラムを持たせるということはよくあります。
ここでは、実際に業務で遭遇した悪いステータスカラム設計を教材として、正しいステータスカラムの設計とは何かを考えていきたいと思います。
ステータスを区別しなければいけない理由
ステータスとは文字通り、何らかのリソースが持つ状態のことです。
開発では、リソース(ユーザーやサブスクリプションなど)のある状態に、名前をつけたり値を割り振ったりします。
例えば、扱うオブジェクトが記事であれば、「公開中」や「下書き」といったステータスで分けたりします。
ステータスをそのように定義しなければならない理由は、当該ステータスにおいてのみ実行させたい処理、もしくは実行させたくない処理があるためです。
ステータスを定義するときにはこの点に注意しないと、以下のような悪いステータス設計ができあがってしまうことがあります。
アンチパターンその1. ステータスを抽出する粒度がおかしい
仮にYahoo!ニュースのようなニュースを配信するメディアがあったとします。
このメディアでは、記者が書いた記事を運営事務局が検閲し、内容に問題がなければ掲載を開始するという業務フローになっています。
当該ステータスにおいてのみ実行させたい処理、もしくは実行させたくない処理があるかどうかを区別するという注意事項を鑑みると、ここでは下記の2点がその実行させたい処理・させたくない処理に該当します。
- 記事の検閲を行うため、記事が作成されたら通知する
- 記事の検閲が終わるまで記事を非公開にする
それでは、もしこのケースで以下のようなデータ設計がされていたらどうでしょうか?
※ステータスにフィーチャーするため、ユーザIDなどの外部キーや記事本文など他のカラムについては記載していません。
まず、edit_statusというカラムについてです。
抽出されているステータスとして「申請中・再申請中」というものがありますが、これらは区別する必要はありません。
なぜなら、「申請中」「再申請中」というステータスはいずれも"記事の検閲を行うため、記事が作成されたら通知する"という処理に必要ですが、それが初回であろうが2回目の申請であろうが事務局が行う検閲という業務フローには影響がありません。
したがって、「申請中」という一つの括りにしてしまったほうがいいです。
ステータスは抽出しようと思えば、いくらでも作れてしまいます。
例えば、人間のステータスに変えて考えてみると「新婚・風邪・食あたり・食事中・休憩中」などなど。
こうなってしまうと際限がなくなってしまいますので、粒度が細かいものはまとめなければなりません。
例えば勤怠管理のシステムにおいて欠勤理由などを保存する場合「風邪・食あたり」では細かすぎます。「体調不良」というより大きな粒度にまとめてしまうといいでしょう。
また、「新婚」というステータスは現実世界では考慮すべき事柄かもしれませんが、勤怠システムで「新婚の場合は特別休暇を付与する」などといった業務要件がない場合は、実装上定義する実益はありません。
このように特定の処理と紐付かないステータスがあると、混乱を招くことになります。
実装上利用しないステータスは無駄なのでどんどん省きましょう。
アンチパターンその2. ステータスカラムが重複している
その1はステータスの値の重複でしたが、次はもっと悪い複数のステータスカラムを跨いでステータスが重複しているケースです。
上記データ設計にはもう1点悪い箇所があります。それはステータスを保存するカラムが2つあることです。
まずこの実装でステータスを定義する目的は 「記事の検閲を行うため、記事が作成されたら通知する」処理と、「 記事の検閲が終わるまで記事を非公開にする」処理を特定のステータスで行いたいからでした。
2つに分けられたカラムにおいてそれぞれ定義されたステータスを比較したときに、これらを制御し得る値が完全に重複してしまっています。
表にしてみると一目瞭然です。
具体的に重複している箇所は以下の通りです。
*「下書き中」「未公開」はどちらかひとつあれば、記事を編集中であるかどうかは判断可能
*「完了」「公開中」はどちらかひとつあれば、記事を公開できる状態かどうかは判断可能
※「申請中」・「再申請」に関しては前述した通り
このケースだと、statusカラムは1つにまとめちゃって、値は「編集中・申請中・公開中」の3つにしてしまえばずっとシンプルになります。
あとがき
以上、ステータスカラムの設計についてでした。