はじめに
前回の投稿 で詳しく書くつもりだったのが失念していました。
目的
SELECT 文を使って出力するリストの順番を、ユーザーが自由に制御できるように「表示順序」のようなカラムを持たせる場合があります。
完全に制御したい場合、ユニークキーを付けたいところですがジレンマがあります。例えば 1, 2, 3 と連続しているレコードの 1 と 2 を入れ替えたい場合、どちらのレコードを先に直すにしても(ユニークキーがついていますから)1 を 2 にすることも 2 を 1 にすることもできません。一旦「4」などの別の数字を入れなければならないのです。その時 4 が空き番になっているかどうかについても先に調べておく必要があります。これはいささか不便です。
それに本当は 4 にしたいわけではありませんから、嘘の数字を登録することになります。たとえ一時的にもシステム内に「嘘」が登録されるということを開発者は好みません。
またその嘘の数字を入力した状態で突然緊急の電話がかかってきて、担当者がその数字を本来の正しいものに直すことを失念してしまったら大変です。開発者はこうした状況も想定し「フール プルーフ」としてもシステムに嘘が登録される危険性を排除しておくべきなのです。
そこで、わざとユニークキーを付けないでリリースします。これなら上記のようなジレンマを解消できます。
アンチパターン
そして開発者は表示するリストのソートに、この「表示順序」カラムを利用します。
しかしユーザーは開発者が思いもしない使い方をするものです。なんと「表示順序」にすべて同じ数字を入れてしまったのです。
「全部同じ数字を入れたら名前の順番に並ぶんでしょ?」1
そんな仕様はありませんが、リストの並びも、順序を前提とした集計結果が間違っていることも、一見してわかります。
背の順
「背の順に並んで!」小学校の時、先生にそんな風に言われなかったでしょうか?これnなら背の高い人が邪魔になって前が見えないということがないので理にかなっています。校長先生の顔を見たいかどうかはシステム的には感知しません。
このとき同じ程度の背丈の友達と顔を見合わせ途方に暮れた経験はありませんか?(その程度のことで「途方に暮れる」というのは誇張がすぎるでしょうが)そのようなイメージで命名しました。
ユニークではない項目だけを使ってソートした結果は一定ではありません。そのようなクエリを書いたり、その結果が期待通りであることを想定したロジックを作ってはいけません。
アンチパターンが有効な場合
希に、システムルールよりも厳格はビジネスルールで窮屈な運用している企業があります。そういうところでは問題は顕在化しないかもしれません。
しかし上記の「緊急事態」の件も含め、想定しない利用をするユーザーはいるものです。このアンチパターンを正当化する理由はありません。
たとえユーザーが「表示する順序を明示的に決定する項目を設けて、その順序に従ってリストしてほしい」と言ったとしても、それがユニークでないのなら、開発者には「その次の優先キーを何にするか」提案し、同じ表示順序が登録されてしまった場合の「フール プルーフ」を実装する責任があります。
解決策
ユニークであるカラムを ORDER 句に含めればいいだけですので、この問題を解決する上での工数も少なく、躊躇する必要はないでしょう。
- 実話です。↩