EmberFest 2017 参加レポート day 1

EmberFest 一日目のまとめです。 EU 圏では Ember ユーザーが比較的多く、プロダクション投入している企業も多いようです。 今回の EmberFest では地域コミュニティだけでなくコアコミッターも多数参加しているということだったので、実際にお話してみたいなと思って参加してきました。

f:id:tricknotes:20171017214224j:plain

参加できなかったけど、ぜひ内容知りたい!という方のためにまとめます。

Opening Keynote — Ember.js in the year 2020

ここ最近、Ember core / CLI からドキュメントまで幅広い守備範囲をカバーしていくれている @locks の発表。 2020年(というよりかは少し先の未来)に向けた Ember のやっていきの話でした。

バージョンアップに伴う API の変更を、ユーザー / ライブラリ開発者にとっても極力影響の小さいものにしつつ、着実に進化しているんだなぁというのがよくわかる発表でした。 ここ最近は目に見えてインパクトのある機能は追加されていないように見えますが、内部構造は大きく改善されているというのがよくわかる内容でした。 Glimmer については、後述の"Compile-time optimizations for you and me"で踏み込んで解説されているのでご参照ください。

Designing Immutable data flows in Ember

例えば React のような不変なデータ構造を Ember に導入するとどういう状態になるか、というパターン実装の話。 Ember のアプリケーションステートは得てして複雑になりがちで、そこに不変データ構造を持ち込むとどれくらいシンプルになるかという思考実験。(と言いつつ、彼はおそらくプロダクションでも使っていると思われる)

  • Ember.Object (Ember Data を含む) は大変ステートフルだよね、という前提がある。
    • Ember は observer パターンで DOM 変更の要・不要を検知しているので、基本的にはオブジェクトのプロパティの変化に興味がある。
  • そこで、immutable data flow を導入してはどうか、というご提案
    • data tracking が簡単になる
    • 状態管理がシンプルになる
    • 2 way binding とか、結構大変…
  • 例えば、this.set('name', newName) する代わりに、this.set('user', newUser) するのだとどうか1
  • Immutable Component のコンセプト
    • 引数のプロパティを更新したくなるような場合、コンポーネント生成時に受け取った引数と同じ型のデータを生成して親のアクションを呼び出す
    • データの生成は Object.assign や Spread object properties を使う
    • このコンセプトは、composition が深い場合もうまくいく
    • "data down actions up"
  • これを徹底すると、データフローがわかりやすくなるだけではなくコードもシンプルになる
    • ネストの下層のものだけ監視したいようなコードを書く場合、とても上手く機能する すべての状態が更新されるので、トップレベルのオブジェクトだけ監視するので十分になる
    • 例: @computed('user.{firstName,lastName}') -> @computed('user')
    • そしてこれは、Ember だけではなく Glimmer の場合も上手く機能する

Ember の CoC から少々逸れているように思われたのが気になりましたが、内容としてはとても理にかなっていると思いました。 原理主義的なアプローチ…というだけでもなく、状態管理+コードが実際にシンプルになる点は興味深かったです。 いまだとコーディング規約と思想で実現するしかないので、もう少し具体的な何か(例えば Lint ?)がライブラリとして提供されるようになる採用しやすくなるのかもしれません。

Treeshaking in Ember CLI

  • 話者 : Alex Navasardyan - @twokul

Ember CLI チームでとてもアクティブなコアメンバーである @twokul の発表。 長年の課題であった Tree-shaking のご提案。(参考: https://dockyard.com/blog/2014/11/28/ember-wish-list)

  • ビルド後の最終成果物に、利用されていないコードを含めないようにするためのアプローチについて。
    • 現状は、すべてのコードがビルド後の JS に含まれている。たとえアプリケーションから使われていないコードがあっても。
    • 実はこれはなかなか根が深い問題で、Ember の本体が DI によって動的にモジュール解決する仕組みを導入することに起因している。
      • Ember 自体は古くから開発されていることもあり、いまとなっては Legacy だと思われる部分のひとつである
    • しかし、これは module API によって解決可能となる2
  • いまは最初の実装を試している、という段階

多くの部分を聞き逃した可能性がある(ほんとはもっと喋っていた)ので、資料が公開されたらもう少し深掘りして内容を更新したいと思います。

How to start loving Acceptance Tests in Ember.JS

Acceptance test の重要性と、いかにそれを上手く書くかというテクニックの話。

  • SPA ではユーザーの入力を起点に複数のコンポーネントが状態を変更する。
    • もちろん、Unit test が大事だということを否定はしないが、コンポーネント間のつながりの部分のテストが漏れがちなので、Acceptance test を書きましょう。
  • いくつかのポイントを紹介する
    • Mirage + faker を使って、テストデータの定義を管理する
      • 最近の Mirage は Ember Data のモデルを勝手に見つけてくれて便利(以前は、Mirage と Ember Data のモデルの対応を表現するクラスをいちいち作る必要があった)
    • ページオブジェクト(ember-cli-page-object) を使って、シナリオ中の CSS セレクタへの参照をカプセル化する3
    • CSS セレクタの重複が省けるし、テストシナリオの可読性もよくなる
    • andThen はネストさせる必要はないので、テストがシンプルに保てる
  • メンテナンス可能で可読性の高い Acceptance test を書いていきましょう

Ember の開発でいまどきのスタンダードと考えられているテストの書き方を紹介してくれていたのかなという感じでした。 目新しい話ではなかったけど、introduction としてはたいへんよくできたチュートリアルだと感じました。

そういえば、Acceptance test の抽象度を上げるという観点だと Cucumber を利用するのもアリなのかな…という気がするのですが、その利用例はあまり聞いたことがないですね…。

スポンサートーク

  • Simplabs
    • Ember.js + Phoenix をメインのツールとして採用している
    • ソフトウェア開発(受託) / コンサル / トレーニングをやっている
    • 興味あれば、あとで話しかけて!

Ember @ Netflix

Ember を積極採用して、これまでに20個程度のアプリをプロダクション投入した Netflix の実例について。 Netflix ならではの技術スタック・パターンをご紹介。

  • Authentication
    • BOLT UI -> Meechum -> JWT
  • Mixin の生成パターン
    • Ember の Mixin 生成をラップした簡単なコードがある
    • これを使うと、動的な Mixin 生成が簡単に書ける4
  • Query params
    • 素の Query params だと controller と route に似たようなコードを書くことになるので、alt 実装を作った
    • これを使うと、ユーザのテキスト入力の変化の度に検索クエリを発行するような UI がきれいに書ける
  • テストデータ
    • 安定の Mirage を使っている
  • Data Table
    • 大量のデータを扱うグリッドレイアウトを実現したかったので、専用のライブラリ(?)を作った
    • "Ember X Table" 5

20 個も Ember アプリを本番リリースすると、いろいろとパターンが見出されてくるんですね…! これも資料の内容がわかりやすかったので、公開されたらもう少し深掘りします。

Building the Progressive Web App for HackerNews.io in Ember

https://hackernews.ioProgressive Web App (以下、PWA) として作った話。

  • いくつかのポイントとその実装について
    • Service Workers + Metadata でオフラインでも使える
    • Postcss + BrowserTargets でクロスブラウザ対応してる
    • Ember Route で、任意の画面をエントリポイントにできるように URL をサポートしている
    • モデルの適切なマッピング
    • 初期ロードのパフォーマンスを改善するためにいくつか工夫をした
      • 素の状態だとファイルサイズがめちゃくちゃ大きく表示に時間がかかるので、せめて React と同等程度のパフォーマンスを出したい
        • 特にモバイルで影響が大きい
      • まずは jQeury を dependency から外す
      • つぎは vendor.js + app.js で concat して async でロードする
      • rel=dns-prefetch / rel=preconnect / rel=preload meta link を CSS の読み込みに使うと、ダウンロード開始までの時間を短縮できる
      • とくに初期表示に必要な CSS を inline 化する -> - ember-cli-critical
      • CDN を使う
      • ここまでやって、画面表示に必要な時間が 12s -> 4s (話者の環境で、React と同等)になった

とても実践的な話しでした。 "PWA" とはなにかを話者自身がしっかり定義してその実装を工夫した話で、すぐに使えるテクニック集という観点でも参考になりました。

Promoting Ember's best practices by linting code

Ember アプリへの lint 導入の話。

  • Link の種類と Ember でのアプローチ
  • また、Lint の実行タイミングについても、いろいろあるので各自工夫してほしい
    • CLI
    • text editor
    • Git hooks
    • CI
  • Ember の blueprint には ESLint の設定が含まれているので、テスト実行時に ESLint が一緒に実行される
  • また、もし lint がチームで上手く機能していない(毎回 disable にしたり、修正に使う時間がかかりすぎていたり…)場合には lint をやめるということを考えてもよいかもしれない

いくつかのツールは話者が開発したということもあり、話者の Lint への愛を感じました。 JS は曖昧な書き方ができてしまいそれが混乱の原因になりうることが多いので、Lint を強化するというアプローチには正しいように感じられます。

Deep Dive on Ember Events

Ember での Events の仕組みを理解しよう、という話。

  • 前置き
    • 実は Ember の世界では、DOM Events をフレームワークが受け取ったあと、各 Component にディスパッチするというイベントモデルと採用している
    • DOM Event -> Ember Event の順番で、それぞれ子から親にイベントが伝搬していく
      • どこかで propergation を止めることができるが、そうすると以降にイベントは伝搬しない
  • イベントハンドラの書き方と、DOM / Ember Event の対応について6
  • 続いてパフォーマンスの話
    • DOM Event は要素に対してハンドラが生成されるので、ハンドラの設定数に比例してレンダリング速度が像以下する
    • 一方、Ember Event はバブリングを利用しているのでレンダリング速度は一定
    • 実行速度はどちらもあんまりかわらない7
    • また、アプリの書き方によっては DOM Event でも Ember Event でもハンドルすることができる
  • 次は、条件によってハンドラの内容が変わる場合
    • 書き方によっては意図通りに動いたり動かなかったりする8
  • いろいろなイベントハンドラの定義方法があるけど、仕組みを理解したうえでイベントハンドラ使ってね

たしかに Ember の Event の仕組みは概要を理解していないと難しいと感じることがあります。 資料ではとてもわかりやすくハンドラの違いが説明されていたので、ハマったときには読み返してみたい発表内容でした。

Compile-time optimizations for you and me

Glimmer 最適化のアプローチの話。

  • Glimmer を最適化することによって、ビルド時間・実行時間をもっと高速にできる
  • "Flexibility and Optimizability are oppsites"
    • テンプレーティングの柔軟さと最適化可能度は相対する概念である
    • (Less Power) << Ember / Vue / Angular / React+Webpack >> (More power)
    • Ember のテンプレートである Handlebnars が制約が強いため、コンパイル時に最適化が効かせやすい
  • Glimmer VM でのいくつかのアプローチ9
    • 例えば div とか href といったよく使われる文字列(HTML の文字列だけでなく、アプリケーション固有の文字列も含む)を事前に定数表として組み立てておいて、VM ではその表への参照を使う方法
    • 現在はテキストベースの命令を採用しているが、これをバイナリに圧縮するという方法
      • VM がバイナリのまま実行できるようになると、ファイルサイズを圧縮できる
    • 変数のインライン展開
      • コンポーネントへの引数として固定値が渡されそれをテンプレートで参照しているような場合、コンパイル時に引数を定数として置き換える方法
  • Glimmer 単体だとこれらのアプローチは上手くいくことが期待できるが、実は Ember だとまだ課題がある
    • 例えば、Computed Property にはロジックを置けるので、その部分については Glimmer VM では手が出せない
    • もし Handlebars で表現されていれば Glimmer VM で最適化できるが、これについてはもう少し検討が必要

他のライブラリではあまり聞いたことがないアプローチでとても興味深かったです。 もしこれがよいアイディアだと認知されたらきっと他のライブラリでも実装が進むことになると思うので、Ember だけでなく他のライブラリも良くなることが期待されます。


以上、ざっくりとしたまとめでした。 なお今回のレポートは、日本では数少ない Ember コミュニティである Ember.Sapporo のメンバーの協力の元作成されました。

二日目の発表内容についてもまとめ次第公開予定です。


  1. このあたり、スライドがあるととてもわかりやすいので、公開され次第追記予定

  2. コンセプトと API は見通しが立ったので、あとは実装を頑張ればよい、という状態なはず

  3. Ruby の Capybara でも page object を実装したライブラリがあるので、これがアイディアの起源と思われる。 https://github.com/natritmeyer/site_prism

  4. 資料が公開されたら追記予定

  5. 詳細が不明なので、わかり次第追記予定。資料を見た感じだと、@ebryn(Ember のコアコミッター)も参加しているようだったので、かなり力をいれた何かだと思われる

  6. コードを見るととてもわかりやすいので資料を参照のこと

  7. 発表資料中ではグラフで比較されていてわかりやすかった

  8. 資料中にクイズ形式で例がでてくるので参照のこと

  9. Glimmer はテンプレートの描画に独自実装の VM を導入している https://github.com/glimmerjs/glimmer-vm