SQL の結合禁止は良いルールなのか
はい、どうもこんにちは佐藤です!
第二の故郷である X で、「SQL の JOIN 禁止現場がつらい」という投稿が流れてきました。JOIN を禁止されたせいで N+1 が発生して性能が出ない、実装もめんどくさい、という嘆きです。
正直、これは刺さりました。私自身も、過去に似たルールを課したことがあるからです。
ORM を経由しない SQL の直書きを禁止し、SQL を書きたければ View にして ORM から引かせる。アグリゲート同士の結合はアプリケーション層でやる。そういうルールを、私は現場に敷いていました。
理不尽に見えたかもしれません。でも……。
当時の状況では、あれは正しかったと思っています。
なぜそう言い切れるのか、順番に書いていきますね!
私が課したルールはこうだった
当時のシステムは、ORM で DB と接続する構成でした。メンバーはほぼ Jr クラス。書き込みも読み込みも、そこまで激しいシステムではありません。
その環境で、私はこう決めました。
- ORM を経由しない SQL の直書きは禁止
- SQL をどうしても書きたいなら、View にして ORM から引く
- DB(アグリゲート)同士の結合は、アプリケーション層で行う
パフォーマンスだけを見れば、明らかに損な選択です。SQL は大量データの取得に特化していますし、直書きすれば確実に速い。アプリケーション層でコネコネしなくていい分、データの正しさだって保ちやすくなります。
それでも、私は禁止しました。
なぜ速さより可読性を選んだのか
理由は、SQL の直書きには本来サービス層に入るべきビジネスロジックが紛れ込む危険があるからです。
業務システムは、速さより可読性と拡張性を優先すべきだと私は判断しました。
考えてみてください。10 年稼働するシステムで、メンテする人は頻繁に入れ替わります。そこに「この DB はこうなって、このサービスではこのステータスに更新して」というロジックが SQL の中に散らばっていたら、どうなるでしょうか?
特につらいのが、ステータス遷移です。画面ベースであちこちに SQL が直書きされていると、リバースエンジニアリングがとにかく難しくなります。全ての業務フローを頭に入れなければ、コードが読めない状態になるのです。
しかも業務アプリには、「ビジネスが変わったからすぐ直して」という暗黙の期日がつきものですよね。3 か月前に赴任したエンジニアが、そんな特級呪物を前にプレッシャーと戦う。それは、同じエンジニアとしてプライドが許しません。
呪詛師になる可能性だってあります。
「そこはコードレビューで防げばいいのでは?」と思うかもしれません。ただ、基本的にどの案件も燃えている前提を置くべきです。レビュー工程を挟む余裕なんて、現実にはなかなか無いんですよね。
だから私は、必要な SQL は View から自動生成し、SQL のコミットだけを見れば済むような最小限の運用に落とし込みました。
それでも N+1 は起きる
もちろん、代償はあります。ORM 経由に寄せれば、N+1 は発生しますし、パフォーマンスチューニングは面倒になります。実装も、素直に JOIN を書くより手間が増えます。
X で流れてきた嘆きは、まさにこの代償の部分です。そこだけを切り取れば、たしかにつらいルールに見えます。
でも、そのルールがどんな現場で、どんな理由で敷かれたのかまでは、短い投稿からは伝わりません。
ルールには、それが建てられた背景がある
ある程度の規模になったシステム開発は、正直なところ宗教に近い部分があります。現場ごとに正解が違うので、他人の現場に口を出すのは難しい。
ただ、背景を理解しないままルールだけを撤廃するのは危険だと、私は思っています。
10 年運用、メンバーの大半が Jr クラス、頻繁な人の入れ替わり、業務ロジックの散逸を防ぎたい。そういう文脈があって、初めて「JOIN 禁止」という判断が出てくるのです。文脈を抜きにして「JOIN を禁止するなんてナンセンスだ」と切り捨てるのは、少し乱暴ですよね。
過去の意思決定には、リスペクトを持ってほしい。そうせざるを得なかった背景が、必ずあるはずです。
AI 時代には、むしろ理にかなっている
もう一つ、今だからこそ言えることがあります。
AI にコードを読ませて改修させる時代になって、あらためて感じるのは、全ての画面遷移を頭に入れないと読めない構成より、ロジックがまとまっている構成のほうが、AI にとっても読みやすいということです。
SQL があちこちの画面や API に直書きされて、ビジネスロジックが散らばっている状態は、人間にとってもつらいですが、AI にとっても文脈を拾いきれない構造です。ロジックを 1 か所にまとめておくというルールは、結果として AI 時代の可読性にも寄与していたことになります。
というわけで、SQL の JOIN 禁止は、当時の状況では正しいルールだったよ!って話でした!
パフォーマンスの代償を払ってでも、可読性と拡張性を取る。それは決して理不尽な判断ではなく、10 年運用と人の入れ替わりを見越した設計判断です。
もし今、誰かが敷いた古いルールに「非効率だ」と感じたら、撤廃する前に一度、その背景を聞いてみてください。そこには、そうせざるを得なかった理由が、きっと眠っています。