1. はじめに
初心者の場合だと、バリデーションは特に何も考えずにモデルで定義しているという人は結構いるのではないでしょうか。ただ業務で開発していたり、自主アプリの規模が大きくなってきたりすると、「モデルで定義する方法が最適解なのか?」という疑問が湧いてくる場面があると思います。
私も業務で開発していて、この辺が気になり始めた1人です。せっかくなので今回バリデーションレベルについて調べて、あれこれ考えたことをこの記事に残しておこうと思います。同じような人の役に立てばと思います。
※以下はRailsの想定で話を進めています(考え方自体はフレームワークを超えて共通した内容かと思います)
2. 4パターンのバリデーションレベル
さて、そもそもバリデーションレベルは4パターンあります。それが以下の通り。
① モデルレベル
② データベースレベル
③ コントローラレベル
④ フロントエンドレベル
1つずつ詳しく見ていきます。
3. ①モデルレベル
メリット
- データベースに依存しない
-> バリデーションの仕組み(データベース制約等)がDBに依存するみたいなことがない - エンドユーザーがバイパスできない
-> フロント側でバリデーションをOFF(ブラウザでJavaScriptをOFF等)にしてスキップさせるみたいなことができない - テスト・メンテナンスがしやすい
-> 1と関連する話だが、DBに依存するようなことがないため保守がしやすい
デメリット
- メソッドによってはバリデーションがスキップされてしまう
- バリデーションがかかるメソッド
create, create!, save, save!, update, update!
- バリデーションがスキップされるメソッド
decrement!, increment!, insert, touch, update_all, update_column, upsert etc...
- バリデーションがかかるメソッド
補足
最も馴染みがあるのがこのパターン。
Railsガイドには正しいデータのみDBに保存する場合は、モデルレベルでバリデーションを実行するのが最適と示されています。
4. ②データベースレベル
メリット
- 安全性が他のパターンと比べて最も高い
-> 結局、アプリケーション層でバリデーションをかけてもすり抜けられたら意味がない - 利用頻度が非常に高いテーブルの一意性バリデーションをかけることができる
デメリット
- テストや保守が面倒
-> バリデーションの仕組みがDBに依存する場合があるため
補足
他の3パターンと異なり、唯一のDB層。
ここを通り抜けることはできないので、バリデーションの強さとしては最強です。
5. ③コントローラレベル
メリット
- 特定の場合に限ってバリデーションをかけるみたいなことができる
デメリット
- コントローラが複雑化して、テストや保守が困難になる
補足
コントローラレベルでのバリデーションを考える時、よく話題に上がるのがForm Objectパターン。
6. ④フロントレベル
メリット
- ユーザビリティ向上につながる
-> フォーム送信で考えると、ユーザは送信を待たずににフィードバックを得ることができる
デメリット
- セキュリティレベルが低い
-> ブラウザでJavaScriptをOFFにされていた場合、直接コンソール上で実行された場合などはバリデーションをすり抜けることができてしまう
7. 4パターンの関係図
4パターンのバリデーションの関係を図にすると下記のような感じになります。
バリデーションの強さだと、フロント < コントローラ < モデル < DB になります。
結局、DB以外のレベルはバリデーションを何らかの形でスキップされたら、DBに誤ったデータが登録される可能性があることは意識しておきたい点です。
8. 考えたこと
上記それぞれのパターンのメリデメと関係性を踏まえた上で、個人的には下記のような考えに落ち着きました。
-
アプリケーション層でブロックしたとしても、何らかの形ですり抜けられてしまったらDBに正しくないデータが保存される可能性がある。DBレベルのバリデーションは積極的に検討したい
-
モデルレベルも基本的には保守のしやすさ等から積極的に検討したい。モデルレベルのデメリットである「メソッドによってはバリデーションがスキップされてしまう」件については、まずは「そもそもバリデーションがスキップされる更新系のメソッドをどうしても使用する必要があるのか?」の方に目を向けたい
-
コントローラはなるべくスッキリした実装にしたい(複雑な処理を増やして保守を大変にしたくない)ので、コントローラレベルは基本使用しない。特定の条件の場合にバリデーションを通したい時やモデルでその条件を指定するとファットモデルになりそうな時に初めて検討してみるというのが良さそう
-
UXにこだわるのであれば、モデルレベルやデータベースレベルとの併用であればフロントレベルを検討してみても良いかも
9. さいごに
バリデーションレベルのトピックは、大枠の良し悪しはあれど、一概にこれが正解といった明確な答えはない奥深いテーマのようです。
「モデルのバリデーションかけとけば大丈夫でしょ!」みたいな安易な考えは捨てて、さらに開発経験を積む中で、その場にあった最適解を出せるよう今後も追求していきたいと思います。
参考