0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

クエリ(参照系)設計の考え方:DBとAppの「責務の境界線」をどう引くか

0
Posted at

はじめに:なぜ参照系の設計は迷走するのか

システムの複雑さは、更新(Command)よりも参照(Query)に現れます。
「1件取得」から始まったクエリが、いつの間にか「集計・判定・評価」が複雑に絡み合った秘伝のタレのような巨大SQLに化けてしまうのは、現場の「あるある」です。

パフォーマンスを優先してSQLにロジックを詰め込めばユニットテストが困難になり、保守性を優先してすべてをAppで処理すればパフォーマンスが崩壊する。このトレードオフを乗りこなすための「クエリ・スタイルガイド」を提案します。


1. 参照系を構成する「4つの基本パターン」

まず、クエリの責務を以下の4つに分解して定義しましょう。これらを組み合わせることで、複雑な参照系を整理できます。

# パターン名 問いの性質 戻り値
1 Finder(取得) 「何があるか?」 Entity / List
2 Predicate(判定) 「~であるか?」 Boolean
3 Aggregator(集計) 「いくらか? 何件か?」 Number / Summary
4 Evaluator(評価) 「条件を満たすか?(集計+判定)」 Result / Enum

各パターンの詳細説明

  • Finder(取得): 特定の識別子や条件に基づいて、データを「そのまま」取り出す最も基本的な形です。
  • Predicate(判定): 対象が特定の状態にあるか、あるいは条件に合致するかのみを判断します。ロジックの「分岐」の根拠となります。
  • Aggregator(集計): 複数のレコードを足し合わせたり、平均を出したりして、データの「傾向」や「総数」を数値化します。
  • Evaluator(評価): 「集計した数字」と「ビジネスルール」を照らし合わせ、最終的なステータスを決定する最も高度なパターンです。

2. 核心:DBとAppの「境界線」をどう引くか

最大の争点は、「どこまでSQLでやり、どこからApp(コード)で書くか」です。これを決めるのは、以下の2つの評価軸です。

① DB(SQL)が担うべきこと

  • 対象: 大量のレコードを走査し、結果を絞り込む・数える必要がある場合。
  • 判断基準: Appに全データを送るとパフォーマンスが壊滅するなら、DBの出番。
  • 例: 10万件のデータから特定の条件で絞り込む(Filter)、全件の合計や平均を出す(Sum/Avg)。

② App(コード)が担うべきこと

  • 対象: 判定条件が複雑なビジネスルールに基づき、変更頻度が高い場合。
  • 判断基準: 「そのロジックのユニットテストを書きたいか?」。もしYESなら、App側にロジックを置くべき。
  • 例: 会員ランクやキャンペーン期間による割引の適用判定(Predicate/Evaluator)。

黄金律:DBは「事実」を作り、Appは「意味」を決める

最も推奨される分業モデルは、「DBから生の数字(事実)を受け取り、App側でビジネス上の意味を判断する」という形です。

  • DBの仕事: 「現在の回答数は102件である」という事実(Aggregator)を高速に返す。
  • Appの仕事: 「100件を超えているから、このアンケートは締め切り(Evaluator)である」という解釈を下す。

3. 実践:CTEを用いた「SQLのレイヤー化」

「混在して難しい」という問題への技術的回答は、SQL内でのレイヤー分離です。CTE(共通テーブル式)を使い、[集計] → [評価] のステップを明文化します。

WITH stats AS (
  -- 【Step 1: Aggregator】DBの得意分野:大量集計
  SELECT survey_id, COUNT(*) as cnt FROM responses GROUP BY survey_id
),
evaluation AS (
  -- 【Step 2: Evaluator】Appに送る前の「前判定」
  --  ※ ここでの判定は、WHERE句での絞り込みに使うものに限定するのが理想
  SELECT 
    s.id,
    CASE WHEN stats.cnt >= s.limit_count THEN true ELSE false END as is_full
  FROM surveys s
  LEFT JOIN stats ON s.id = stats.survey_id
)
SELECT s.title, e.is_full FROM surveys s JOIN evaluation e ON s.id = e.id;

4. この設計を支える「3つのバックボーン」

このスタイルガイドは、以下の著名な設計思想を現代的に解釈し直したものです。

① Specification Pattern (DDD / Eric Evans)

「あるオブジェクトが条件を満たしているか」という判定(Predicate)のロジックを独立させるパターンです。

「ビジネスルールなら、DBではなくSpecification(仕様)としてAppに置くべきだ」という強い根拠になります。

② CQRS & Projections (Greg Young)

更新系と参照系を分離し、参照系を「画面が必要な形」に合わせて再構成(投影)する考え方です。

「集計と判定が混ざった複雑なクエリ」は、単なるDB取得ではなく、表示専用のモデル(Read Model)を作るプロセスだと捉えることができます。

③ "Database is a Detail" (Clean Architecture / Uncle Bob)

「DBは詳細(保存先)に過ぎず、ビジネスロジックを知るべきではない」という原則です。

SQLにビジネスロジック(複雑なEvaluator)を詰め込みすぎないための、強力なアーキテクチャ上の警告となります。


まとめ:スタイルガイドへの記載案

チームで共有するためのエッセンスです。

  1. 判定(Predicate)が単純ならSQLの WHERE で、複雑ならAppの Logic で。
  2. 集計(Aggregator)はDBに任せる。ただし、結果の「解釈」はAppで行う。
  3. 命名規則を徹底し、戻り値が「単なるデータ」なのか「計算済みの評価」なのかを明確にする。

参照系は、ユーザーが意思決定を行うための「情報の窓口」です。単にデータを流すのではなく、そのクエリが「何を判定しようとしているのか」を整理することで、システムの柔軟性は劇的に向上します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?