RDBの制約とRailsのModelのバリデーションについて考える
Updated Date: 2024/01/01 14:47
はじめに
僕は長年RDBしか使ってきていないSEマンだったので、 「RDBの制約は絶対である。エラー処理は単体テストで境界値・限界値・異常データをぶっこんでしっかり検知し正常動作を保証することが重要である」 っていう思考で仕事をしてきた人間である。 その流れでイケイケのベンチャーみたいなとこに参画した3年くらい前、Railsのバリデーション書くのサボってRDBに入ってきたデータが桁数オーバーで死ぬみたいな バッドエンドに出くわすことも多々あって、本当にこういう世界があるんだなと実感したのを覚えている。 しかもエラーハンドリングもフリーダムで、StandardErrorに発生したエラーメッセージをぶっ込むみたいな部分もあって、 誰が見てもSQLのエラーですってことを明示しちゃうほどの危うさを含んでいた場面もあった。 まぁ、こっちはSIでもあるあるなのでそこはきちんと例外処理の設計をしようという話で終わるものではある。
問題はRDBで制約書くほうがいいのか、Railsでバリデーション書いて弾けば問題ないのかっていう部分である。
問題の深掘り
RDBの制約とRailsのバリデーションをどう書くかっていう話は、個人的には卵が先か鶏が先かみたいな話じゃないかと思っている。
RDBもそれすなわち制約と設計で出来上がるものであって、制約なきRDBはRDBにあらず。 それが不要ということはそもそもRelationalであることをRDBで保証する必要はないということである。
RailsはRailsでみなも知っている通り設定より規約なわけで、規約なきRailsはRailsにあらず。 それが定義されていないのであればRailsじゃなくて別の言語でも問題ないということである。
今回の問題を別の言葉で表現するとすれば「制約と規約」ってどっちを優先して定義すべき?ということになると思う。
制約を優先するのであればRDBの制約を必ず書いてエラーハンドリングを単体テストで担保することが必要で、 規約を優先するのであればRails(Model)のバリデーションを必ず書いて単体テストで担保することが必要。
解決策
どっちもあったほうがいいのでは?というのが親子丼的な解決法。 肉(鶏)だけあれば困らないのはRDBでの解決法。 卵だけあれば困らないのはRailsでの解決法。
将来的にRDBを切り離し、様々なサービス(プログラミング言語もいろいろ)なものから利用されることを 前提としたマイクロサービスとかシステム冗長化構成を取る場合、 個人的には親子丼がベストかなと思っている。 これは他のプログラミング言語でも「同程度の品質を担保するため」の手段となり得るからである。
例外処理は重要。エラーハンドリングができてこそ一流みたいな考えならRDBで制約作って、 Railsもそれに従わせるという規約を作るのも一興。
RDBをいずれ捨て去るということがぼんやりとわかっているのであれば、 無駄に頑張る必要はないのでModelのバリデーション作って、 RDBは正しい関連しか(正攻法では)作れないという制約を作るのも一興。
まとめ
まとめると、今現状よりも将来的なアーキテクチャを想定しながら考えたほうが、 場当たり的な対処よりかは「あのときちゃんと考えてよかったね」と言える日が来るんじゃないかと思う。
余談
この話にフロントエンド(JS/erb)が入ってくると余計ややこしくなるので今回は割愛している。