イベントエンティティを意識したデータベース設計について考えた
はじめに
株式会社ウェイブでCoolmicのエンジニアをしている布施です。
Coolmicは日本のコミックを海外向けに配信するWEBサービスです。
社内の勉強会的な場で、良いデータベース設計とはどのようなものなのだろうという話をしました。
イミュータブルデータモデルの話をする中で、なんとなくイメージができてきたので少し書きます。
イベントエンティティ
イミュータブルデータモデルは一度保存したデータを変更しないようにする考え方です。
データの全ての変更履歴にアクセスすることができるなどのメリットがあります。
保存するデータ量が増えてデータベースの規模が大きくなってしまうなどのデメリットもありますが、ストレージ等のリソースの料金は今どきそこまで大きな問題でもない気がします。(プロダクトによる)
このイミュータブルデータモデルの文脈において、イベントエンティティという言葉が登場します。
まずビジネスロジックからエンティティを洗い出して、それをリソースとイベントに分けましょう、とよく言われていると思います。
イベントエンティティは「動作」を表すエンティティと考えられますが、その抽出の仕方にはさまざまなパターンが考えられ、それにより良い設計にも悪い設計にもなってしまうようです。
イベントエンティティの捉え方について、このポッドキャストがとても勉強になりました。
ここから具体例を挙げてイベントエンティティについて考えます。
具体例
前提
あるECサイトにおいて下記の要件を満たすことを考えます。
- ユーザーはサイト内通貨(チケットと呼ぶ)を購入し、チケットを使用してコンテンツを購入することができる。
- ユーザーが持つチケット枚数の変化を追跡できるようにしたい。
とある設計
ユーザーは「チケット購入」の動作と「コンテンツ購入」の動作を行うと考えると、下記のテーブルを作成する設計が考えられます。
users
-
ticket_charges
(チケット購入) -
content_purchases
(コンテンツ購入)
この時、下記のような計算をすれば特定のユーザーの持つ現在のチケット枚数を取得することができます。
SELECT SUM(ticket_charges.tickets) - SUM(content_purchases.ticket)
FROM users
JOIN ticket_charges ON ticket_charges.user_id = users.id
JOIN content_purchases ON content_purchases.user_id = users.id
GROUP BY users.id
WHERE users.id = 42
この場合、現在のチケット枚数を取得するために2つのテーブルにアクセスしなければなりません。
また、「ボーナスチケットを取得する」など、チケット枚数の変化に関わる新しい動作を追加することになった時に、新しくテーブルを追加するのかどうかを検討する必要が出てきます。
別の切り口でイベントエンティティを抽出した設計
ユーザーは「チケット枚数が変わる何かしらの取引」の動作を行うと考えると、下記のテーブルを作成する設計が考えられます。
users
-
ticket_transactions
(チケット取引)
ticket_transactions.tickets
がプラスの時はチケットチャージを、マイナスの時はチケット消費を表すと考えると、下記の計算で特定のユーザーの現在のチケット枚数を取得することができます。
SELECT SUM(ticket_transactions.tickets)
FROM users
JOIN ticket_transactions ON ticket_transactions.user_id = users.id
GROUP BY users.id
WHERE users.id = 42
この場合は1つのテーブルにアクセスするだけで欲しい情報を取得することができます。
また、ticket_transactions.type
のようなカラムを追加して、charge
(チャージ)、present
(ボーナスあげる)、purchase
(コンテンツ購入による消費)、refund
(返金によるチケット無効化)などを設定するようにすると、余計なテーブルを作成せずに済む可能性もあります。
おお〜 やるじゃん
最後に
今回データモデリングの勉強をしてから自社プロダクトのデータベースを見たら、ここもっといい設計できたかも!という箇所を何個か見つけることができました。
データベースの修正はかなり大変だと思うので実際やるかどうかは別ですが、新しく追加するものに関しては、設計の段階でこのイベントエンティティの捉え方は十分か?と自問しながらやっていきたいと思いました。
みなさんもレッツイベントエンティティ
株式会社ウェイブのエンジニアによるテックブログです。 弊社では、電子コミック、アニメ配信などのエンタメコンテンツを自社開発で運営しております! ve.jp/service/
Discussion