レガシーコード生産ガイド

私に教えられることなら

Elm設計メモ

最近、どうにか中規模以上のアプリケーションをElmで組めないかと四苦八苦しています。ちょっとイケそうなアーキテクチャを思いついたのでその簡単なメモです。上手く行っても行かなくてもある程度書いたらまとめたいと思います。

モチベーション

ある領域の表示・非表示など、明らかにあるビューに閉じた状態を、グローバルな一つのモデル・メッセージで管理するのは面倒です。

そこでElmチュートリアルの合成の章を参考にしてコンポーネントを作り合成します。内部で完結したModel/Msg/Update/Viewを持つものをComponentと呼ぶことにします。(Viewは持たないこともあります)

これで、例えば簡単なログインフォームなら、各フォームの入力内容などはコンポーネント内のモデルに閉じ込めることができます。

しかし、ログインボタンがクリックされた事をどうやって伝えればいいでしょうか?

子のupdateで返す( Model, Cmd Msg )にクリックされた事を含めるやり方だと、例えばModelのレコードにclicked : Boolというフィールドを追加して、親でそれを読み取ったらfalseに戻して……となるでしょうか。かなり複雑になる予感がします。少なくとも、ローカルに閉じているはずの子のModelを親からいじるのは、絶対に避けたいです。

解決策

ElmディスカッションフォーラムでのEvan Czaplickiのポストを参考にします。

コンポーネントのupdateをMsg -> Model -> ( Model, Cmd Msg, Out )として、親コンポーネントからOutの内容を見て判断します。

これによって親は読み取るだけでよくなるので、子のModelをいじる必要はなくなります。

Outの内容は、

  • ビジネスモデルを知る、再利用不可能なコンポーネントは、API経由でグローバルなCmd Msgを
  • 絶対にビジネスモデルに関係しない、再利用可能なコンポーネントは、親から与えられたデータを

発行します。

所謂バケツリレー的な状態になってしまいますが、型があるので心理的には楽です。また本来なら再利用不可能なはずのコンポーネントを無理やり再利用しようとするから、バケツリレーが辛くなるのかもしれない、とも思い始めています。

依存関係

Modelがビジネスモデル、MessageがグローバルなMsgとメインのupdateも含むとして

  • Components => ( Model, API )
  • API => ( Model, Message )
  • Message => ( Model )

といった関係です。(Elmアーキテクチャに関係が無いモジュール群は省いています)

今後

依存関係や、モジュールを整理することについてもいくらか考えがありますが、まずは試してみてからですね。

他にも案があったら教えてください。(喉から手が出るほど欲しいです)

広告を非表示にする