仮想DOMと宣言性、Reactivityについて

VanillaJSでGUIを作る人間から見たSvelteの良さ

— はなだ のぶかず

大まかに話すこと

  • はなだ のぶかず
  • Lisp/Rust/Scala/Haskellが大好きです。
  • Visual Programming Languageをつくるのが仕事だったり趣味です
  • ダンスとボードゲーム
  • @nobkz

自己紹介

VanillaJSとGUI

とりあえず、Svelteの話をする前に簡単に

  • http://vanilla-js.com/
  • ただ「ライブラリやフレームワーク」を使わないJSのことではない。
  • それらをまず前提としない考え方。
  • DOM APIなどをちゃんと勉強しましょうよ
  • 根本的に作りたいUIの正しい設計について考えましょうよ
  • フレームワークをWebアプリをつくるための設計思想や実装技術を"プラグイン"として考える

VanillaJSとは?

  • 定番の難しいことや、面倒なことをやってくれる
  • フレームワークを使うことで、ある程度、設計の認識の共有ができる
  • 一定の品質担保

ライブラリやフレームワークの利点

  •  UIに関するフレームワークは基本的には、未だに抽象化されていない。
    • 設計の多様性
    • UIの多様性
  • ○○フレームワークをつかえばどんなUIでも可能になるわけではない。
  • ○○フレームワークで可能な範囲のUIに制限されている。
  • もし、範囲を越えたUIをつくるとしたら、その設計に合わない実装になり、苦しみを抱える。

フレームワークがUIを制限する

  • Visual Programming Languageは基本的には、GUIの範疇を越えることが多い。
  • ゲーム。これはそもそもゲームエンジンを利用するだろう
  • ワードや、Google Mapみたいな、ビジュアルなツール
  • 基本的には、Viewに強い独自ロジックが必要な場合、GUIフレームワークは適さない
  • ジェスチャーなど独自で状態管理をしないといけない場合など。

抽象化されてないUI

  • Viewに状態やデータやロジックを持たせることが悪だと言われやすい
  • 確かにビューに状態を持たせると、更新処理が複雑化したりする場合が多い
  • 実はDirect Manipulationの観点から考えると必ずしもそうではない。
  • 必要なのは、上手な状態管理である。ビューも状態を持つ方が良い場合もある。

Viewが状態を持つということ

  • DOMはグローバル
    • どこからでもアクセスできて変更できる
  • 構造が貧弱なフォームに合わせてデータ保持する必要がある
    • JSオブジェクトとの変換が必要になる

DOM(≠View)で状態を持つと辛くなる理由

  • Vanillaとして考える(フレームワークを使わない意味ではない。)
  • コードやチームなどの寿命を考える
  • まずはキチンと設計する
  • フレームワークのコードを断片的にも読むべき
  • フレームワークもメンテする
  • 全部捨ててスクラッチで作り直してもいいやと思えるぐらい

結局フレームワークはどう向き合うべきか?

  • レイヤーアーキテクチャ
  • Observer or Polling
  • 疎結合
  • コンポーネント
    • 汎化
    • 境界
    • 共通化
  • 状態管理

GUIに必要なもの

  • 抽象化
  • カプセル化、情報隠蔽
  • モジュール化
  • 関心の分離
  • 結合度と凝集度
  • 参照の一点性
  • 分割統治

GUIに必要なもの-ソフトウェア設計

  • MVC:モデル-ビューコントローラで分離する設計
  • Model : GUIアプリケーションの中核機能や中核データ
  • View: 情報をユーザに表示
  • Controller : ユーザ入力

GUIの設計  - MVCなど

勘違いされやすいMVなんとか

Original MVC

MVVM

Web MVC (MVC2)

Client MVC (Flux)

Original MVCもいろいろ

  • 素朴なMVC
  • 依存MVC
  • プラガブルMVC

とりあえず依存性のMVC

View

Controller

Model

入力

操作

通知

表示

参照

よくあるダメなパターン

  • 表示しかない
  • リストが何個あるか?
  • リストをどうやって削除するか?

なぜダメなのか。

モデルと通知

  • モデルとビューに分けられている
  • 分けることによって、追加や削除が実装しやすい
  • ビューは表示に集中できる。
  • すごく簡単な実装なので、実際はもっとちゃんとやる

モデルとビューの分離

No 仮想DOMについて

No仮想DOMについて整理するね。

そもそも仮想DOMとは?

Virtual DOM

update

Real DOM

最初の疑問

最初からこう書けばよくね?

  • 仮想DOMで目指したかったのはまずは宣言性である
  • UIの更新を直接書くのは手続き的になりがち(実のところ宣言的に書けないわけではない。)
  • データを入力として、仮想DOMを出力するという関数を定義することで宣言性を作り上げている。(render関数)

仮想DOMの宣言性

つまりこういうこと

Model

通知

Model

仮想Dom

仮想Dom

ここが状態を持たない関数になればいい!!!

=宣言的!!!

仮想Domの差分比較

実DOMの操作

もしリアルDOMだったら?

Model

通知

Model

仮想Dom

いやいや、Dom API呼びすぎて、

遅いでしょ?

実Dom

  • たしかに、そうやって宣言的に書きたいなら、そうかもだけど
  • でも、仮想Domの差分比較更新の分だけ、更新処理を地道に書いた方が速いよなー
  • また、Virtual DomやReactComponentのレイヤーのおかげでランタイムが大きくなる
  • あと、そもそもReactのやってる更新っての、枝刈りだしなー。

Vanilla JSerの気分

こっちの方がいいね!

Model

通知

View

通知メッセージに合わせて適切に更新!

差分検知の分だけ、更新するのだるい。

なんだったら、自分で枝刈りしてるし..

Viewオブジェクトを生成して、

  • とても宣言的に書ける
  • 無駄なViewの更新処理を書かなくていい
  • 更新処理はコンパイラが書いてくれる

SvelteはNo 仮想Dom

コード例

とても宣言的

<form on:submit|preventDefault={submit}>
	<input bind:value={text}>
</form>
<ul>
	{#each post as aPost}
		<li on:click={e=>{ deletePost(aPost) }}>{aPost}</li>
	{/each}
</ul>	

更新処理について

for (i = 0; i < each_value.length; i += 1) {
  const child_ctx = get_each_context(ctx, each_value, i);

	if (each_blocks[i]) {
		each_blocks[i].p(child_ctx, dirty); // リストの更新
	} else {
		each_blocks[i] = create_each_block(child_ctx);
		each_blocks[i].c(); // リストの追加
		each_blocks[i].m(ul, null); // リストのマウント
	}
}

for (; i < each_blocks.length; i += 1) {
	each_blocks[i].d(1); // リストの削除
}

書いてくれる!

  • SvelteコンパイラがVanillaJSにおける、Viewの更新を書いてくれる。
    • 掃き出したコードを見ても、悪くない
    • 若干VanillaJSで書くより、無駄な処理があるけど
  • 宣言的に書きやすい

Vanilla JSから見たSvelte

  • Reactiveの話は、Alan KayのReactive Engineから始まる
    • 式の構文木を持ち、入力が変化すると、式が再評価されるモデル
  • Functional Reactive ProgrammingはこのReactive Engineに対して、明示な連続時間変化の型を中心において、強い保証
  • SvelteのReactivityは、ちょっと異なっているような...(時間がない)

Reactivityについて

  • Reactを初めとするVirtual Domは宣言的に書けるける一方、でも遅い
  • Svelteも宣言的に書いてコンパイルしてくれる。
  • Vanilla JSerから見たらSvelteはとても、Vanilla JSの人達が書きたいViewの処理を出力している。
  • Reactivityについてはまたこんど

まとめ

仮想DOMと宣言性、Reactivityについて

By Nobukazu Hanada

仮想DOMと宣言性、Reactivityについて

  • 172