株式会社LITALICOでエンジニアをやっている@kazuisです。
この記事は『LITALICO Engineers Advent Calendar 2024』の3日目の記事になります。
障害者福祉・介護領域でエンジニアリングを使って教育領域、働き方領域をよくするために、奮闘しております。
はじめに
データベース設計の入門書を読み、データベースの設計をはじめると疑問に思う事があると思います。
システム間のデータ整合性をどう作っていけばいいんだと?
そんな人向けにヒントになればいいと思って書いてます。
データベース設計
データベース設計は、制約を設定しデータの整合性を担保するために行います。
未来に設計書を見る方に意図が伝わるようにするものです。
制約とはデータの構造であり、制限でもあります。
制約とはビジネスルールや意図なので、あれも、これも設定すると意図が伝わらなくなります。
そこで重要なのは以下の概念です。
強い制約 = DBの機能を使ってリレーションに制約をつくる
弱い制約 = コード値を使ってアプリケーションで誓約をつくる
強い制約と弱い制約を使い、変更容易性があるデータベースの設計するとよいと考えています。
これによりマイクロサービス化などのシステム構造の変更にも対応しやすいシステムになっていくと
ともに、データの整合性を担保しなければいけないデータ構造と、そうではないところと柔軟に対応することができます。
設計の変化
10年前のDB設計のトレンドはデータ主体で構造を定義するものでした。
これは正規化です。これは今でも基本です。最近のデータベース設計は、ドメイン主体で構造を定義しましょうという流れがきていると思います。
クラウド化やスクラムなどの開発手法でビジネスの変化がより激しくなり、変更容易性が更により求められるようになりました。マイクロサービス化やサーバレス化など、変更される範囲を絞ることが重要になってきます。ドメイン主体のコンテキストベースで設計されるよになったとも言えます。
ある日、システム構造を変えたいよっていう要求の変化が発生したとします。
そのときにボトルネックが発生します。
それがなんとなく付けてしまったデータベースのリレーションの制約です。
データは関心事(以下、コンテキスト)によって変化します。
商品が、在庫になったり、輸送対象物になったり、陳列された商品になったりです。
データの変化を構造化する必要がでてきました。
なんとなく付けてしまったデータ制約をあとから外すのはコストかかります。
(外していいんだっけ?ってなる)
制約を最小限にして、変化に強いシステムを作ることが求められています。
モノリシックとマイクロサービスの設計の違い
商品テーブルに、在庫フラグとか陳列済みとかデータ主体で構造だったり、
正規化して在庫テーブルと商品の関係を定義する手法になります。
ある日、在庫管理の業務に変化がありました。
陳列してものを戻して在庫にする業務が新たに追加になりました。
- 陳列済みというカラムをいらないと思って削除したら、事故発生
- 商品テーブルに変更いれたら、陳列業務に影響があって、事故発生
在庫管理の業務を変えたいのに陳列業務などの他のビジネスのルールまでも知らないといけない状況になってしまいます。
モノリシックの設計はデータ主体で設計されデータ整合性を担保するために行われます。
データ整合性に視点が集まりすぎて固くしすぎるために、ビジネスの変化についていけなくなることが問題だと考えてます。
(この場合、在庫管理業務も変更される可能性は十分に予見できると思いますが...。実際の業務はもっと複雑なので難しい)
また、コンテキストを横断した設計をしてしまいがちになりますので、システム全部を知らないといけない状況が生まれます。これは認知負荷が高まり、コードを書くまでに時間がかかり開発スピードの鈍化に繋がります。
そこで大事にしたい原則が以下です
ETC原則(Easier To Change) - よい設計は悪い設計よりも変更しやすい
下記は全てETC原則に繋がる。
・結合を最小化
・責務を単一化
・正しい名前を付ける
達人プログラマではDRY原則が有名ですが、ETC原則という原則も説明されております。
責務を単一化して正しい名前をつけるというのはマイクロサービス化だったり、システムの分離に必要な原則です。
そこで結合を弱めるために、強い誓約と、弱い誓約という概念が登場します。(ワタクシ流)
マイクロサービス化しないシステムでも強い誓約と、弱い誓約という概念を使ってコンテキスト主体でデータ設計をするというのは、変更容易性をつくること、認知負荷を下げることにつながるので重要だと思っています。
強い制約 = DBの機能を使ってリレーションに制約をつくる
弱い制約 = コード値を使ってアプリケーションで誓約をつくる
チラ裏1
昔々、モノリスでインピーダンスミスマッチという名前で問題がありました。
ユースケース(オブジェクト)とデータリレーションの腐敗防止層としてORMが解決策として登場しました。ドメイン駆動でコンテキストをシステム化してシステム分離コストを解決する方法としてマイクロサービスがあるのかもしれません。
強い制約と弱い制約
強い制約はデータベースのファンクションキーだったりするので、わかりやすいかもしれません。
弱い制約はどう実現しましょうか?
例として、さっきのスーパー業務SaaSをイメージしながら書きます。
マイクロサービス化でサービスが分離されており
- 商品サービス
- 在庫管理サービス
- 陳列業務サービス
このように、システムが別れて作られているという前提で書きます。
図を参照してください。商品コードというカラムが追加されています。プライマリーキーにしいている商品IDとは異なります。これはいわゆるID生成器・ユニークIDジェネレータで作られた文字列が格納されます。
商品IDはサロゲートキーです。フレームワークでよくあるテーブルのIDカラムはプライマリーキーでテーブルユニークになるというものになります。テーブルでユニークであるものはサロゲートキーに任せます。
特定の場合を除いて(ex.社会保障番号やISBNなど)ナチュラルキーは、変更の可能性があるので、プライマリーキー等には使わないことをお勧めしています。もし、変更があった場合、PKを変更しないといけないという重労働が待っているためです。変更容易性が危ぶまれてしまいます。
マイクロサービス化したシステムの場合、複数のデータベースを使いコンテキストを分けて設計させれる事が多いと思います。なのでテーブルはもちろんですが、データベース内でデータ整合性をつくるのが難しくなるのです。
そこで、分散システムにつかわれるユニークIDジェネレータを採用します。
ID生成器で作った商品コードのイメージ
7c1d0be57dc200cd418c
商品1テーブルを見てもらうと商品コードにユニークコード(AK1)をつけてあります。
マスタ的なテーブルにコード値が設定されれるのでユニークコードを付けて置くことを推奨します。
アプリケーション間・サービス間はこの商品コードを使ってゆるい制約をつくるのが弱い制約
になります。強い制約
は、請求書と明細書の関係だったり、データ整合性が強くビジネス的にも止められるところで設定します。
これはシステムがわかれるからコード値を使っているわけではなく、コンテキストが分かれるからコード値で制約をゆるく作っています。データベース設計を見る方は、これでコンテキストが違う事を理解できます。また強い制約があるところは、ビジネス的に整合性を担保しないといけないデータだと理解できます。
システム間・コンテキスト間はAPIのインターフェイスでコード値をやり取りすることによってアプリケーションで担保する誓約をつくり、データ整合性を作っていきます。
例のERDだと商品サービスと陳列業務サービスはコンテキストが違いますが、同じデータベースに入れています。ただ、コンテキストが違うのでリレーションは貼ってません。もしAPIをつくるとしたら、同じデータベースでもコード値指定してデータ取得などができるとコンテキストを分離できていると言えるんだと思います。
データ整合性からリレーションを貼る手法とのコンテキストを中心にリレーションを貼る手法の違いを説明してみました。このようにコンテキスト中心のデータベース設計をすることによって、変更容易性と、認知負荷を下げることによってビジネス変化に強いシステムを作っていくのはどうでしょうか
チラ裏2
モジュラーモノリスをデータベース設計の違いでみるとこのような違いがあるかなっと思います。
モジュラーモノリスの場合は1つのシステムでパッケージを分けてっていう話はよく出てきますが、こう整理してみると、設計の視点が大きく違う事に気づかされます。モジュラーモノリスでやってますと行ってもデータ主体で設計していれば、それはモノリスに近づいていってしまう可能性があるのです。
モノリス = データ主体で構造化されてる
モジュラーモノリス = コンテキスト主体で構造化されてる(場合によってはデータ主体になる時もあるが)
マイクロサービス = コンテキスト主体で構造化されてる
終わりに
データモデルの設計方法が、たくさんあるので1つの題材をいろんなやり方で設計してみて設計を楽しんでいます。なんで時代によって設計手法って変わっていきますよね。GPTやo1やAIがでてきて、どんな設計手法がでてくるのか楽しみにしてます。
#設計好きな人と繋がりたい