Data元でデータの定義をはっきりさせておかないと、全システムが汚染される話
ヌルヌルしちゃう話。型定義やvalidはちゃんとしようという自戒。
TypeScriptを例に出している。
一部のシステムで正確にデータ定義がされていなかった場合、null許容である必要がない項目がnull許容になったり空白の考慮が必要だったり、想定されない値が入ることになったりといろいろ面倒になる。
例えば、{"id": 1, "name": "洗濯機" ,"price": 500}のようなデータを利用することを考えてほしい。
型にすると、{id: number, name: string, price: number}で定義できると思う。これが何でもかんでもstringやOptional(id:? number)で定義されてしまうと、idやpriceに数値以外が来ることを考慮するロジックを書かなければ安全にデータを保持できなくなる。
型定義の他には、valid処理を間に挟むことでデータの状態を定義することが考えられる。こちらも、実施されていない場合は、空文字が入るか入らないか/最長何文字まで入るのか/idはマイナスになることがあるのか等々…の考慮がなされないまま、データが格納されるため、参照次更に悲惨になる。
上記はどちらも、利用するときに考えることが多くなってしまうという点が問題になる。
なので、ここからは利用するときを考えてみる。仕様が以下のように定義されていたとする。
idや金額でマイナスになることはない
すべての値は必ず定義されている
名前はからになることはない
利用する際にはこれらの状態になっていることが担保されていないため、
取得した結果データが存在するはずなのに存在しない
存在しないデータは既に削除されている?
データの取得に失敗している?
商品名が空で表示される
空文字の場合はなにか特殊なことを表している?
idを確認してから商品を表示する必要がある
idがマイナスの場合、マイナスは商品の削除を示唆している?
等の余計な考慮が必要になってしまう。
このシステムの利用が1システム内で留まる場合はまだ問題ないが、WebAPIで提供されてしまった場合は更に面倒くさくなる。
システムAでしっかりとした定義ができていない場合、システムBでも何が送られてくるかがわからないため
案1. システムB側のvalidを細かく定義して、システムAからの汚染を防ぐ
案2. システムB側も定義をゆるくして、システムAの定義を受け継ぐ
のどちらかを選択する必要がある。
案1を採用した場合は、システムAの影響でシステムBの工数が跳ね上がり、更に未定義部分の洗い出しをシステムA側に問い合わせする必要がある。案2を採用した場合は、データの出力時にどこかの画面でデータの不整合が発生してエラー落ちしてしまう可能性が出てくる。
どちらにせよ、利用者側にデータ整合の責務を押し付けることになってしまうのだ。
大抵の案件ではスケジュールが優先になるので、案2が採用されているのをよく見かける。結果関連システムがすべてガバガバになる。
なので、データ入力やデータストアで厳格に縛るべきである。
ちなみに、これは一般生活でも同じことが言える。
例えば、食器棚には食器を入れるはずだが、ここにペット用の皿や掃除で使うための布を入れてしまうと、取り出すときに何で使うものかの確認が必要になる。皿を洗わずに入れてしまうと、皿を取り出すときに新しい皿を探して取り出す必要がある。
どこの世界でも、しまうときにはちゃんと一定のルールに従って整理したほうが良いのだ。