Mithrilでバリデーションをどこで行うか、という話ですが、戦略はいくつかあると思います。
バリデーションを書ける場所
<input>
タグの min/max/patternなどの属性値を使う
controller: function() {
var self = this;
this.message = m.prop('message');
},
view(ctrl) {
return m('input[min=3][max=6]', {
onchange: m.withAttr('value', ctrl.message),
value: ctrl.message()
});
}
メリット
- 入力前にチェックできる。後工程に想定外のデータが渡っていかないのでシンプル
デメリット
- タグで指定できるようなチェックしかできない
oninput
のコールバックの中で仕込む
controller: function() {
var self = this;
this.message = m.prop('message');
this.validateAndStore = (value) {
// 何かしらチェックしてから格納
self.message(value);
}
},
view(ctrl) {
return m('input', {
oninput: m.withAttr('value', ctrl.validateAndStore),
value: ctrl.message()
});
}
メリット
- 入力前にチェックできる。後工程に想定外のデータが渡っていかないのでシンプル
デメリット
- 中途半端な状態でもチェックルーチンが呼ばれてしまうので、「NGです!」みたいな表示がで続けてユーザのストレスになる可能性も
onchange
のコールバックの中に仕込み、エラー表示する
controller: function() {
var self = this;
this.message = m.prop('message');
this.validateAndStore = (value) {
// 何かしらチェックしてから格納
self.message(value);
}
},
view(ctrl) {
return m('input', {
onchange: m.withAttr('value', ctrl.validateAndStore),
value: ctrl.message()
});
}
メリット
- 入力した瞬間に実行。タグで設定できるよりも細かいバリデーションが行える。
- 入力が短く、エラーが明確な場合はプロパティに代入せずに単純に無視(入力内容は消える)
- 半角全角変換とかもやるならこのタイミングがベスト
デメリット
- ちょっとレスポンスが遅い
送信ボタンとかのタイミングで行う
メリット
- チェック箇所が一箇所にまとまる
デメリット
- フィードバックが遅い
- ダメだった時に、元の値に戻すとかの処理をサポートするといろいろ手間が増える
結局何処にかくべきか?
なるべく多くの所で書くほうがいいかなと思ってます。フィードバックが早いの大事。あと、ロボット的な更新がされることもあるので、クライアントでチェックしたとしても、サーバサイドのチェックは省略はできません。まあサーバサイドはバリデーションというかアサーションですかね。当然、クライアントとサーバのチェックは矛盾してはいけません。
あと、バリデーションはドメイン知識なのか?問題。DDDだと、ドメインは集約すべき、バリデーションはドメインのもの、分離するとドメインモデル貧血症になるぞ!という説明もあれば、バリデータークラスを作るみたいな説明もみかける。どっちかわからん。
バリデーションをドメイン知識だとして、ドメインレイヤーにおしこめてしまうと、フィードバックが遅くなったりするので、書けるところにはガンガンかけばいいかなと思ってます。
JSONスキーマを作り出すのはドメイン層かもしれないけど、JSONスキーマの確認を行うのは別レイヤーでいいじゃん、という解法もあるかもしれないけど、ユーザに親切なエラーメッセージ、特に具体的な解決方法を出すには自動チェックじゃどうしようもならないことも多いですよね。結局バリデーションにはロジックが必要になることが多い気がします。