#ディレクターと喧嘩しないためにデータを設計するときに気をつけてほしい10のアンチパターン
iOS、Androidのアプリケーション開発が目立つ昨今でも。
DBを始めとして、システム開発では2次配列で取り扱うデーターこそがシステムの根幹でありもっとも重要な処理対象であるのはいまさら言うまでもありません。
特にtoCサービスにおいては柔軟な対応を求められることも多く、データー構造の設計の良し悪しは改善スピードにダイレクトに影響します。
クライアント側のアニメーションの処理やイケているUIの実装は大変楽しいですが、サービスの根幹は2次配列で表現されるデーターの取り扱いだというのは変わらない事実です。
つまらないバッチ処理こそが業務の根幹を握っているかもしれないよ。そのバッチ止まったら請求書出せなくて会社詰むかもよ的なところを意識したいまでいかなくても、サービス運営上でボトルネックとなることが多いのがデーター構造に起因するあれこれのできる・できない・時間がかかるあたりな印象があります。
ということで、最近はディレクションサイドで働くエンジニアとして。
こういうの困るというアンチパターンを無理矢理上げていこうとおもいます。
##1.外部のマスターはそのまま利用するかAPI利用する
- プライマリーキーを勝手に改変しない
- 後日の更新や仕様変更時に対応し難くなるのが想像できる
- 必要であれば参照キーを別途付ける
- 不要でも全部のカラムを乗せておく
- APIが用意されていて、要件的に問題ないならAPIアクセスする。
- 路線別の駅レコードなど冗長なデーターがあっても元のマスターのIDを紐付けるテーブルを別に用意するなどするべき
- 1(サービスの要件):n(マスター)ならば1を無理やりつくるのではなく、1:1:nとなるように変換テーブルを実装する
- じゃないと元のマスターで駅名の変更や改変があった場合に手動でひもづけ対応する羽目になる。
##2.集計を前提として通し番号を用意しておく
- 一度の操作で複数レコードを作るようなシステム
- 例:個人毎宛のメッセージ送付を1ユーザーID毎にレコードをInsertするみたいな仕組み
- 通し番号を準備し、各レコード間の紐付けが可能なようにする。
##3.拡張性を考えたテーブル構成にしておく
- トランザクションデーターを扱うテーブルをカテゴリー別に持つみたいな実装はよっぽど理由がない限り避ける。
- カテゴリー増やしたり廃止したりするたびにテーブルを増やすとかJOINの実装変更だとか、ゴミテーブルが出るとかは正直なところよっぽど意味がない限り必要性がよくわからない。柔軟なサービス運営のためにもカテゴリーIDとのセットで1テーブルで済ませるべき。
##4.重要なコンテンツのマスターはDBで管理するべき
- 重要なデーターはマスターデータとリレーション張れるようにしておこう。
- こちらもカテゴリー別に別テーブルでプライマリーキーがそれぞれローカルとか意味がわからない。
- カテゴリーマスターと項目マスターをもって、項目マスターには通しの連番を付与し、カテゴリーはカテゴリーマスターのプライマリーキーで参照できるようにしましょう。
- DBで管理してないと管理画面も作りづらい。一番いいのはマスター修正依頼など出さずに管理画面でメンテできる状態が理想。
##5.むやみな浮動小数点型は使わない方がいい
- DecimalとかFloatとか
- 丸め処理にちゃんと対処できる人って意外といないので、int型でもっておいて使う時に加工したほうが安全というのが僕の経験則です。
- クライアントの環境で取り扱いかわったりするかもしれないから、整数で渡して実行環境側で処理してもらう。
- 各種レートとかは0.111とかじゃなくて111とかで持つ。
##6.レート処理はむやみに100分率使わない
- 5のあたりとかぶる理由
- 30%、20%、40%、 10%みたいな割合を表現したい場合
- 30,20,40,10で合計100みたいなデーターをもってもらう。
- 30,20,40,10,50で合計150とできるようにして、1/3は新しいものがあったって、のこりの2/3から従来のレートで割り当てるみたいな実装が柔軟にできて企画側としては扱いやすい。
##7.属性情報は必ずIDをフル
- まともに運営していく予定があるサービスであれば店舗住所とか種別等カテゴライズ等のサービスにとって重要な属性データはCode化できる前提で設計する。
- SEO対策とかが当然の現在において、属性が文字列でいいからなんてことはない。後日面倒な変換バッチを実装したくなくれば考慮した設計にするべき。
- 最低限度コード化はともかく、後日コード化可能なレベルでのバリデーションを
- ユーザーにとっても有益
- 後日バッチで紐付けできない使えないデーターばっかりでしたということも少なくなる。
- コード化できないとSEO対応など後日サービスを拡大させていく場合に不利になりやすい。
##8.ユーザーの環境属性は保持する前提で
- どのプラットフォームを利用しているかなどの情報は必ず持つ
- iOS・Android・Web・ガラケー各キャリア
- 複数のサービスで共有するデーターベースであれば、どのサービスからのアクセスか
- etc
- 当然ながら、サービス・プラットフォームによってユーザーの性質が違う分けられるの大前提。
##9.ユーザーの履歴をちゃんと保持する別な用途でDeleteやUpdateするような実装を入れない
- ゲストユーザー・仮ユーザー・本ユーザーなどでAccessTokenがかわったりする場合でも履歴を追える設計になっているべき
- ユーザーの行動ログはとれるだけとる。特に会員状態の変化みたいな情報は必ず履歴を残す。貴重な情報源という意識で。
- AccessToken的なものの払い出し履歴を保持するテーブルなどを端末の管理に使い回すなどして、Update・Deleteするような使用はくまない。そういうデーターはログデーターとはべつに管理用のテーブルを別途設計する。
- というかそもそも初期の意図をみたせなくなるような機能性を無理に持たせるは絶対やめる。レビューを受けて慎重な設計変更を
##10.抽象的で冗長性のあるテーブルを嫌うのではなくそういう仕様として取り扱うと気持ちが楽
- だいたいのイベント実装はユーザーIDとなんらかの値の保持と、参照用のキーをいくつか保持できるテーブルで対応可能です。
- 毎回別テーブルを設計する必要はない
- 毎回イベント実装のたびにテーブルを新規設計してモデルを実装してみたいなのは正直時間もかかる。
- ユニークIDとイベントID、参照用のIDや値を格納できる抽象的な値カラムを10個くらいもてるイベントテーブルを実装してしまった方がいい
- Eventの種別を判別するIDとイベントで使う値を上限N個もてるテーブルという仕様として考えて柔軟に対応いただけると助かる。
- 思いついたイベントをイベント自体の実装のみで2〜3日後には実施可能になるとかそいうメリットは運営上大きい。
- 通常のトランザクションデータテーブルに冗長で抽象的なカラムを持つことを推奨しているわけではなく、そういう役割のテーブルを仕様として用意しましょうという事。役割が場合によっては変わるのが気持ち悪いのは理解します。
#まとめ
10個思いつくのに苦労したので、無理やりなところもあります!
わかりやすい図を用意しようと思ったのですが、Adventのルール、前日まで投稿していないとランキングにのらないがあるので、文章のみで失礼します。
あとあくまで個人の感想ですので!