2018-05-06

ViewModel ComponentにModelを通じて世界の覗き窓を作る

先日来 JavaScript の ViewModel 系フレームワークで監視対象外のデータをどう扱うかというところに注目しているのだけど、これには理由があって、

  • VM Component の単位で影響を閉じ込めるという発想はGood
  • 単方向のデータバインディング、データフローもGood
  • VM Component が UI を司るのでどうしても VM Component が Model を mount するという形になり、かつモダン JS の世界では Rails 的にすべての Model が global に展開されるという考え方は NG
  • VM Component のどこかに Model を mount しつつ「すべてのデータを監視対象とするわけではない」という形が扱いやすそう
    • Angular で Change Detection を打ち消しまくろうとするアプローチは「気にしたくないものを網羅する」という形になるので現実的な感じがしない(まず漏れると思う)

ということで MobX にたどり着いたわけだ(Vuex Store が State 前提すぎるので)。ただし、MobX ですべて解決とは思っていなくて、自分の感覚としては

  1. VM Component が世界のすべてを知っている必要はない(むしろユーザーとのインタラクションと直接関係しないロジックで世界は満ちている)
  2. Component の外の世界はいきなり HTTP とは限定できない
  3. Component を司る Parent Component で Model を通じた外の世界の覗き窓を提供する

くらいの感じがいいのかなと思っている。

Modelを管理するModelからParent ComponentがChild Componentに世界の覗き窓を教えてあげる関係図

いったんのイメージとしては図のような感じ。

ここでロジックとして「掌握する世界がより広い」のは Model > VM Component であり、Parent Component > Child Component である。

Parent Component の初期化の際に(Vue + MobX なら fromMobx のような方法を通じて) Model を持ち、さらにこの Parent Component が Child Component を生成する際にも(例えば v-for などの記述の際に)Parent Model の「機能」や「State 相当の data」を props で渡してあげるようにすることで、より広い「世界」に対する「覗き窓」を手に入れるという具合である。

「覗き窓」というのが肝心なところで、props で渡されたものを監視しないのは無理だし、Child Component の責務は基本的には Model への直接の介入ではなく Parent Component への Event Bubbling に留めた方がよいという判断。

本当は Child Component からうまく Model の一部の機能にタッチすることができた方が便利だなと思っていたんだけど、それをやるにはやはり独自の名前空間を切って plugin として Vue Component に inject してやらないと無理っぽいので、いったんは「覗き窓」の部分だけを明文化しておこうと思った次第。

今回の話は特に目新しい話もなければ包括的な設計指針でもない。そういう話は メンテナンスしやすいVueComponentを設計するために気をつけていること などを読むとよい。

ちなみに上で言っている Parent と Child というのは React を参考にしつつ用語を整理していくとどうも

Container か否か

という切り方をするっぽい。

ここで言い方を変えると Container が Coponent 生成時に Model から覗き窓を props で渡す という感じか。

なるほどなるほど。

順番が前後したが、なぜわざわざこれを書き起こしているかということを整理しておしまいにしようと思う。

React 以降の VirtualDOM 前提の ViewModel フレームワークはあくまで VirtualDOM というごく限定的な世界のことをうまく扱うように特化しており、ViewModel フレームワークの強い制約はその中で破綻しないようにするためにはよい工夫ではあるが、ユーザーとのインタラクションは生DOM や Window, Canvas など VirtualDOM ではどうしようもない部分も含んでいるし、Model 自体は ViewModel Framework の制約とは独立して考えてよいというか独立して考えるべき、そうでないとどうしても無理が出ると言ってよいと思う。

極端な話、ViewModel Framework は Model の全体像など知らなくてよい「あくまで VirtualDOM へマップしやすい情報だけを扱っているのだ」くらいの認識にしておかないと Model 設計の際に VM Component の制約で頭が固まりそうで怖いな、と感じたので、選択肢を作り1、それを文字に起こしておくことにした。

あとはねぇ、Rails の ActiveDecorator みたいなことをやれれば Model はさらにすっきりするんだけどねぇ…。Model に View 向けの変換が入っていると邪魔だし、かと言って Component で持つと似た記述があちこちに散らばるし、mixin を使えばできなくはないんだけど、Model をどう Component 内に持つかは Component 次第なので mixin で解決しきるのはとても厳しいわけですよ。ね。

参考

Getterの辺りに異論はあるのですが、よくまとまっていて非常に参考になります。

  1. 監視しないデータとロジックの置き場所を確保すること 

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm