必要最低限がウリのMithrilにおいて「これいらなくね?」と言われる筆頭がm.prop()
のプロパティです。もちろん、これがある方がコードがシンプルになるのであえてMithrilはこれを残しています。1.0からは高機能化された上で別パッケージに別れる模様です。
ポインタのメタファ
プロパティは以下のような機能を提供するシンプルな変数です。
var a = m.prop(1);
a(); // 1を返す
a(2); // 2を格納する
a(); // 格納された2を返す
C/C++を使ったことがあるのであれば、ポインタと言い換えると伝わりやすいかと思います。この変数aを持ち回れば、別々の場所から同じところにデータを書き込んだり読むことができます。次のような単純なオブジェクトだと、「変数」と「名前」の両方を渡さないと書き込みができません。
var todo = {
description: '説明'
}
プロパティを使えば値単体での読み書きができるようになるため、イベントハンドラで双方向バインディングを書くのが楽になります。プロパティ単体だけ渡せばよく、結合を疎にできます。
function createInput(description) {
return m('input', m.withAttr('value', description), description());
}
プロパティをいつ使うのか?
いろいろなところから読み書きしないのであればプロパティにする必要はありません。オブジェクトに直に変数を代入してしまえば十分です。必要最低限をねらうなら、上記のようなビューから直接変更するような要素にしぼってプロパティにしておきます。変更が発生するかわからない or まだ細かいところまで定まっていないのであれば、とりあえず、エンティティクラスの末端のプロパティは全部プロパティにしておく、という方針でも良いでしょう。
それ以外だと、サーバからのレスポンスを格納する場所ですね。こんな感じにしておくと、ビューから参照されるときにデータがなくてもエラーになりません。
this.data = m.prop([]);
m.request(サーバリクエストの引数).then(this.data);
ビューとモデルの変換レイヤーを追加する
プロパティのインタフェースは単なる関数呼び出しです。最初は単にm.prop
にしておいて、その後にバリデーションやサニタイズを足すことができます。例えば、日付の入力は<input type="date">
を使うとします。この入力フォームは「年-月-日」という形式の文字列を読み書きします。モデル内ではDate
型にしておきたいですよね。最初はthis.dueDate = m.prop()
としておいて、きちんと実装したくなったら同じインタフェースを維持したまま、次のように書き換えます。
class Todo {
constructor(data) {
this._dueDate = m.prop(data.dueDate);
}
dueDate(value) {
if (value) {
this._dueDate(new Date(value));
} else {
const d = this._dueDate();
return `${d.getFullYear()}-${(d.getMonth() + 1)}-${d.getDate()}`;
}
}
}
まあ、本来ビューのためにモデルがデータ加工するのはどうなの的なこともあるかもしれませんが、サーバMVCではなくて、JSレイヤーのモデルなんてのは、サーバからしたらビューのための変換レイヤーでしかないので、個人的には別に悪くないかな、と思います。もちろん、モデルが太ってきたらビューモデル側に持っていってもいいと思います。
プロパティが設計上優れているポイント
Mithrilに限らない話ですが、アプリケーションの設計って規模によってどんどん変わっていくんですよね。最初から「レイヤー化アーキテクチャだ」「ここはドメイン層だ」「ドメインロジックは分離せよ!」みたいな設計方針でコードを書いていくのもいいかもしれないけど、それだと動くものができるまで時間がかかる。
最低限の機能を動かすだけであれば設計というタスクすら必要ないかもしれません。最小機能のセットからイテレーティブに開発していく手法は大分広まっていますが、どこまで最初から発展の方向性を見据えて手を動かす必要があるか、というのはまだ諸説あると思います。
そういう意味では、イテレーティブに開発する時の設計手法というのは、Aという機能を持ったコードに、A'という機能を足したら、そのままではごちゃごちゃになっちゃうから、こういう指針で分けましょう」というような差分をマネジメントする手法を取るものだと思います。つまりパターン・ランゲージやリファクタリングこそが設計手法。アーキテクチャは結果的にそうなるものであって、最初から目指してはいけないものなんじゃないかと最近思っています。
リファクタリング本はA→BとB→Aの両方をパターン化していてすごく良い本です。といっても、基本的には機能が増えて分割する方向で発展する方向が多いでしょう。プロパティは小さく初めて、同じインタフェースを持ったままロジックを後から追加することが容易になります。複雑化した後に徐々にレイヤーわけをしたりも簡単にできます。