「現場で役立つシステム設計の原則」読書会レポート vol.6

株式会社リゾーム システム企画・開発部 第1グループの小田です。

読書会の第6回目のレポートです。

前回のレポートはこちらです。

tech.rhizome-e.com

6回目レポート

今回は、第6章「データベースの設計とドメインオブジェクト」で参加者は5名でした。

それぞれの感想・意見交換

制約について
  • NOT NULL制約、一意性制約、外部キー制約を徹底すると自然と正規化が進む。
    • 適切なDB設計をするための指標としてわかりやすい
  • ここに書いてあるNOT NULL制約、ユニーク制約、外部キー制約などは基本的なものなので、出来る限り使う。データベース側の機能のチェック制約やenumなどを使うと、更にデータを守ることができる。
  • 原則としてNULLを許容しない。
    • もしNULL値がどうしても必要なカラムを見つけたら別のテーブルに分ける。
  • NOT NULL制約を使っていないカラムだとプログラム側でnullが来ることを考慮しなければならない。
  • 以前の勉強会で「データベースには事実を記録する。事実にはNULLなどない。基本的にNOT NULL制約を付けなければならない。」と言われて納得した。それ以降はNOT NULL制約を必ず付けるようにしている。レビューのときにも「NOT NULL制約を付けろおじさん」になっている。
  • (NOT NULL制約、普段はほとんど使ってない...)
コトに注目するデータベース設計
  • コトを記録するという発想がないと、モノに関連するもので一緒くたに詰め込んでしまおうと考えてしまいがち。
  • コトに注目するデータベース設計は楽々ERDレッスンでも言われていた。
    • 導出項目の排除につながる。
    • 導出項目はSQLのビューで状態を表現する。
  • 記録のタイミングが異なるデータはテーブルを分ける、というところ。マジでそれ!と思った。今の仕様がそうなっていなくてかなり辛い。
  • カラムを追加するのではなくテーブルを追加する。
    • そのカラムには過去データが存在しないので、NULLを許容するか偽データを登録するかの二択になるから、別テーブルに分けたほうが良い。
    • 確かに副作用がないけれど、テーブルが増えるしJOINが大変になりそうな気もする…。プログラムへの影響は少ないし、事実を記録する観点だとそっちのほうがいいのかな。
    • JOINが増えると性能面が不安
      • コト(口座への入出金データなど)を記録するテーブルとは別に、集計結果(口座残高など)を格納しておくテーブルを用意してあらかじめ集計しておくと良いらしい。
  • コトの記録の変更を禁止する(updateではなく、取り消しデータをinsert→修正後の新データをinsert)
    • 記録をupdateするのはupdate前の記録を削除することと同じ。updateせず「記録を修正した」というコトを記録する。
    • なるほどと思った。取り消しを記録する。元データ、取り消しデータ、新データ。INSERTだけで実現可能。
参照をわかりやすくする工夫
  • 状態の参照。コトの記録を徹底すれば、状態の算出は可能。動的に出力するのはパフォーマンス的に辛い場合もあるので、この辺りはRailsだとカウンターキャッシュを使ったり、DBのマテビューを使ったりしている。
  • 残高更新は同時でなくてもいい、一か所でなくてもいいという考え方は、柔軟性が生まれる。事実はDBに保存し、状態はKVSに持たせるようにすると良さそう。状態の参照は頻繁に行われると想定すると、KVSのほうが向いている。
  • モノの記録を行うからそこに状態を持つ必要が出てくるのであって、コトの記録に徹底するからこそ状態の更新をコトの記録と分離することが可能になるのだろうか
オブジェクトの設計とテーブルの設計
  • コトを記録するテーブルとドメインオブジェクトがほぼ1対1に対応することがある。しかし、似て非なるものという意識を持っておくべき。ドメインオブジェクトとデータベースのアクセスは、基本的に疎結合にしておいたほうがいい。そうでないと、互いに引っ張られ過ぎる。ドメインオブジェクトには業務ロジックを、データベースには事実の記録を。関心事が異なる。しかしそうなるとやはりRailsだと難しい。RailsActiveRecordドメインオブジェクトでもあり、データベースへのアクセス手段でもあるからだ。

まとめ

本章を通じて、コトに注目したデータベース設計を行うことで柔軟性が生まれ、データの管理やプログラムの修正が容易になることを理解することができました。 本章で書かれている内容と自身のプロダクトのデータベース設計を見比べ、どの辺りに改善の余地があるかを参加者全員が意識することができたと思います。

私は「原則として全てのカラムでNULLを許容しない」「カラム追加時は既存テーブルに追加するのではなく、新規テーブルを作成する」といった内容は想像したこともなかったのですが、そのように設計されたデータベースはデータの整合性や信頼性が高まり、定義の変更時にプログラムへの影響を最小限に抑えられることを理解できました。

また、読書会の中で「楽々ERDレッスン」という書籍を紹介頂きました。本章の内容についてはもう少し深掘りしてみたいと思ってるので、そちらも今後読んでみようと思います。