ウェブパフォーマンスの最適化のためにできる事は何か、もしくは『Webフロントエンド ハイパフォーマンス チューニング』という本を書いたという話

Webフロントエンド ハイパフォーマンス チューニング

Webフロントエンド ハイパフォーマンス チューニング

技術評論社さんから『Webフロントエンド ハイパフォーマンス チューニング』を出版することになりました。題名通り、フロントエンド周りのウェブパフォーマンスについて書いた本です。

ウェブパフォーマンスというのは、昔はウェブページの初回の表示の速さのみを指すものでした。インタラクションを持たない静的なウェブページがほとんどであった頃には、一度ウェブページを表示し終わってからはパフォーマンス上の問題が発生することが比較的少なかったからです。ウェブパフォーマンスを改善するチューニングテクニックというのもこの初期のリソースの読み込みを改善するものが主でした。このようなテクニックは、『ハイパフォーマンスWebサイト』で語られている「ファイルをgzip圧縮して配信する」「DNSルックアップを減らす」「JavaScriptとCSSは外部ファイル化する」などが代表的なものです。

この状況は、複雑な振る舞いを持つウェブアプリケーションが登場する事で変わります。JavaScriptによる動的な振る舞いを持つウェブページでは、一度レンダリングが終わってからもユーザのアクションに応じてインタラクションを行う必要があります。その時に問題になるパフォーマンス上の問題とは、従来のリソースの読み込みに関する問題ではなく、JavaScriptやDOM操作の実行速度の問題であったり、CSSセレクタのマッチング速度の問題であったり、視覚的要素のレイアウトや描画の速度の問題であったりします。これらの新しく出てきたパフォーマンス上の問題は、これまで紹介されてきたリソースの読み込みの速度をチューニングするテクニックでは全く対応できません。例えば、アニメーションの描画をなめらかにするために初期表示のパフォーマンスの最適化を行っても意味が無いことは直感的にわかると思います。

こういった新しく登場したパフォーマンス上の問題を解決するには、ウェブパフォーマンスという言葉の意味を捉え直し、かつそれらの問題が起きる根本的な原理であるブラウザのレンダリングの仕組みを把握し、レンダリングの工程ごとに発生する異なる問題を解決するためのチューニングテクニックを正しく適用することが必要です。この本では、ウェブパフォーマンス上の解決すべき問題をGoogleが提唱しているパフォーマンスモデルであるRAILに添って説明しています。その上でブラウザのレンダリングの仕組みやウェブパフォーマンスの計測方法や様々なチューニングテクニックを紹介しています。この本では今現在のウェブパフォーマンスを扱う上で必要になる基礎知識やチューニングテクニックを体系的に解説しており、ここまでウェブパフォーマンスについて網羅した技術書は、日本語の書籍の中では現時点ではこの本だけです。

すでに書店などには並んでいるのでウェブパフォーマンスに関心のある方は一度手に取って読んでみて下さい。というわけで『Webフロントエンド ハイパフォーマンス チューニング』の宣伝エントリでした。

MastodonはP2Pではないという話、もしくはMastodonの脱中央集権の仕組みについて

Fukuoka.php vol22にてMastodonについて話してきました。

Mastodonは最近盛り上がってる分散型SNSですが、その仕組みに興味をもったので調べてみたのが今回の話になります。スライドの中で主に説明しているのは、Mastodonが実装している分散型SNSを実現するためのプロトコルOStatusについてです。

OStatusはAtomフィードを核とした仕様です。ユーザーのつぶやきをAtomフィードで表現し、さらにそれをコンタクト情報を形式化するPortable ContactsとSocial Network上の活動を形式化するActivity Streamsで拡張しています。フィードだけだと、リモートのサーバはポーリングする必要があるため、それを補うためにPubSubHubbubでAtomフィードの更新をほぼリアルタイムに受け取ることができるようにしています。また、FollowやFavやReplyやRetweetを相手先に通知するためにはSalmonを使っています。リモートフォローする際に入力する(ID)@(Mastodonのドメイン)という文字列からそのユーザーの情報を取得するためには、WebFingerを使っています。

日本国内ではP2Pと結び付けられて語られることのあるこのMastodonですが、こうやって見てみるとP2Pとはあまり関係がなく、フィード関係のプロトコルを使って分散型SNSを構築できる仕組みであることがわかると思います。

HTML5とか勉強会にて「大量の要素を高速に表示するバーチャルレンダリング入門」という題で話をした

第68回HTML5とか勉強会にて「大量の要素を高速に表示するバーチャルレンダリング入門」という題で話をしてきました。

ブラウザのレンダリングは、基本的にそのドキュメントに含まれるDOM要素の数が多ければ多いほどレンダリングが重たくなります。バーチャルレンダリングというのは、JavaScriptでDOM要素の数を調整して見えない部分の描画をうまくサボる仕組みです。

バーチャルレンダリング自体は結構いろんなところで利用されているにもかかわらずその仕組みやアルゴリズムの流れについて日本語での解説をあまり見かけなかったので、HTML5とか勉強会ではこれについて話すことにしました。

このテクニックは結構昔からあるテクニックで、知ってる人は知っているけれども知らない人は知らないままという感じになりがちなんですが、今回はHTML5とか勉強会という参加者が比較的大きな勉強会(180人ぐらい参加してる)で話せて良かったなと思いました。

JavaScriptのUIライブラリはどうあるべきかという話とOnsen UIのアーキテクチャ

Onsen UI Advent Calendar の12/9の記事です。

Onsen UIは、モバイルアプリのネイティブライクなUIをHTML + CSS + JavaScriptで簡単に構築することを目的としたUIライブラリです(UIフレームワークともたまに呼ばれます)。 ↓みたいなネイティブなモバイルアプリっぽい画面をサクッと作ることができます。

f:id:anatoo:20161209200818p:plain

私は数年前から開発メンバーとしてOnsen UIの設計開発を行っています。この記事では、Onsen UIに求められるUIライブラリとしての要件とそれを解決するためにどのようなアーキテクチャを取っているのかについて解説します。

特定のフレームワークに依存しない

jQuery UIやReactの上に乗っかっているUIライブラリなどのように特定のフレームワークの仕組みを使って実装されたUIライブラリというのはたくさんありますが、ある特定のフレームワークに依存することは避けるべきだという考えのもとにOnsen UIは開発されています。

ある特定のフレームワークに依存したUIライブラリを作ると、その他のフレームワークから使ったり素のJavaScriptから使うことが困難になります。例えばAngularJSに依存したUIコンポーネントは他のフレームワークから利用することは基本的にできなくなります。技術的にはできなくも無いでしょうが、それをわざわざやりたいと思う開発者はおそらくいないでしょう。

UIライブラリの提供者側にとっても特定のフレームワークに依存するのはリスクがあります。もしその依存しているフレームワークが使われなくなった場合に、UIライブラリを書き直すことになる可能性があります。

これは実際に起こったことですが、Onsen UIの1系はAngularJSのdirectiveとして実装されていたので、AngularJSと互換性の無いAngular2が登場した時にdirectiveとして実装されていたすべてのUIコンポーネントを書き直したことがありました。

フレームワーク非依存にするためにしていること

Onsen UIでは、特定のフレームワーク依存せず、かつどのフレームワークからでもある程度利用できるように次のような構成を取っています。

f:id:anatoo:20161211015934p:plain

CSS Components層は、Onsen UIが提供する最もレベルの低いコンポーネント層です。これは主にすべてのUIコンポーネントの見た目を提供します。CSS Componentsという名前のとおり、CSSファイルとして提供されます。

Web Components層では、Custom ElementsのAPIを使ってCSS ComponentsにJavaScriptで振る舞いを与えます。Custom Elementsを使っているので、素のJavaScriptからでも、フレームワークからでも同じように扱えるように設計されています。

Framework Bindings層では、各種フレームワーク用のバインディングを記述します。現在のところAngular1, Angular2, React.js,とVue2用のバインディングが記述されています。

CSS Components層

CSS Components層では各コンポーネントがCSSだけで完結するCSS Componentsとして実装されています。CSSだけで実装できるもの、すなわちコンポーネントの見た目はここで実装されています。

このCSS ComponentsはAdobe製の高速CSSフレームワークであるTopcoatをフォークして開発されたものです。CSSメタ言語としてStylus、CSSコンポーネントのドキュメントの記述にはtopdoc、設計規約としては高速なCSSセレクタを記述することができるBEM+MindBEMdingを採用しています。

開発者はCSS Components層が提供するCSSのみを使うこともできます。例えば、Onsen UIのリポジトリのCSSファイルを読み込んで、swtichコンポーネントのタグを記述するとiOSでよく見るSwitchのUIが表示されます。

<link href="https://unpkg.com/onsenui@2.0.4/css/onsen-css-components.css" rel="stylesheet" /> 
<label class="switch">
  <input type="checkbox" class="switch__input" checked>
  <div class="switch__toggle">
    <div class="switch__handle"></div>
  </div>
</label>

f:id:anatoo:20161209195916p:plain

リポジトリ的には次の場所に全て記述されています。

Web Components層

先ほどのCSS Components層の上に位置するのがWeb Components層です。CSSで記述された見た目に対してJavaScriptで振る舞いを追加します。

ここでは独自のHTML要素を定義することが出来るCustom ElementsのAPIを使ってCSSコンポーネントに振る舞いを追加するカスタム要素を定義しています。ドキュメントを見ると現在は約40程度のカスタム要素が定義されています。

例えば<ons-button>という要素があるのですがこれはCSSコンポーネントして実装したbuttonにCustom Elementsを被せたものです。

<button class="button">...</button> <!-- CSSコンポーネント -->
<ons-button>...</ons-button> <!-- ons-buttonカスタム要素 -->

Custom Elementsとして実装すると、そのDOM要素のプロパティやメソッドや属性などの振る舞いを定義することができます。これを使って素のJavaScriptやjQueryなどからでも扱える、かつAngular2やReact.jsやVue.jsなどのフレームワークからでも扱えるコンポーネントを定義することができます。

リポジトリ的には次の場所に全て記述されています。Custom Elements以外にも各種JavaScriptのAPIも提供しているのでこの部分をひっくるめてcoreとも呼ばれます。Onsen UIのonsenui.jsonsenui.cssはこのcoreから生成されます。

Framework Bindings層

この層では、各フレームワークごとのラッパーを定義しています。このラッパーはOnsen UIではバインディングと呼ばれています。現在対応しているフレームワークにはReact.js, AngularJS, Angular2, Vue.jsなどがあります。jQueryや素のJSから利用する場合には、このバインディングは利用しません。

開発者は、利用するフレームワークに合わせてこのバインディングも利用します。

なんでこのバインディングがあるかというと、Web Componentsを提供していたとしても、そのカスタム要素のプロパティやメソッドにアクセスできなければ意味がありません。各フレームワークごとにコンポーネントの操作をどのように行うかについても流儀が異なります。

例えば、React.jsではそもそもコンポーネントのメソッドを叩くといった操作はしないのが普通なので、Custom Elementsが持つメソッドに依る操作をReact.jsのコンポーネントのpropsやstateによって管理する必要があります。AngularJSやAnglar2の場合にはDOM要素が持つメソッドをDirectiveから叩けるようにする必要があります。

Framework Bindings層ではこのフレームワークごとに異なる流儀を吸収しながら、カスタム要素に対するインターフェイスを提供しています。

フレームワークによってどういうふうに書き方が変わるかというのは次の公式ブログの記事にも書かれています。

リポジトリ的には次の場所に全て記述されています。bindingsディレクトリ以下にフレームワークごとのnpmパッケージが提供されています。

まとめ

Onsen UIは様々なフレームワークに対応するために、Custom Elementsを使っています。その際のUIライブラリとしての大まかなアーキテクチャについてこの記事では説明しました。

「PHPに型推論を実装する〜入門編〜」という題でPHPカンファレンス福岡2016で話してきた

PHPカンファレンス福岡2016で型推論器ってどんな感じなのという話をしました。PHPカンファレンス福岡は去年も登壇したんですが今年は弊社もスポンサードしつつの登壇です。

参加者や運営スタッフの皆さんの対応含めて心地良い雰囲気だったので、ああ参加して良かったなと自然と思えるような素晴らしいイベントでした。参加者や運営のスタッフの皆さんお疲れ様でした!

JavaScript(ES2015)でvarやletを使う必要はほぼ無い

ES2015でvarやletを使う場面はほとんど無いので、まずconstを使う。constだとダメな場合にはletを使う。

背景

ES2015では、変数を宣言するための文法としてconstとletが導入された。

const foo = 'foo';
let bar = 'bar';

constは再代入できない変数を宣言できる。letは再代入できる変数を宣言できる。

const foo = 'foo';
foo = 'hoge'; // ERROR

let bar = 'bar';
bar = 'hoge'; // OK

あれ、じゃあvarとletは同じなの?っていうとそうではなく、letやconstはvarとは違って、関数スコープよりも細かなブロック単位のスコープを提供する。例えばconstやletを使うと、if文やfor文などのブロック中でのみ有効な変数を宣言できる。

で、プロジェクトにES2015を導入すると、「お、varじゃなくてlet使えばええんやな!」と言わんばかりにletだけを使う人を見かけるんだけど、実際にはletもほとんど使う必要なくて、多くの場合はconstで問題ない。また、他人が書いたソースコードの中でletを見ると、「これ後で再代入されるん?」って一瞬身構えるので、再代入の必要がないならconstを使う方が可読性も良くなる。

ES2015になって変数の文法が増えたわけだけど、開発者はまずconstを使って、再代入が必要ならletを使って、letも使えない特殊な事情がある場合のみvarを使う、というようにするといい。

varは別に非推奨になったわけではないので普通に使えるんだけど、プロジェクトで機械的にvarを使わせたくない場合には、ESLintでno-varを有効にする。

Airbnbが公開しているES6に対応したJavaScriptコーディング規約においても、まずconstを使うこと、varは避けることが書かれている。

追記: よくよく調べてみると、ESLintには再代入しないletに警告を出すprefer-constがあった。より厳格にしたい場合はこのprefer-constを有効にする。

まとめ

ES2015では、varやletを使う必要のある場面はそれほどない。変数の宣言にはconstを使う。再代入が必要な場合にのみlet使う。

factorでズンドコキヨシを書いてみた

連鎖性言語のfactorで今流行り(?)のズンドコキヨシ書いてみた。連鎖性言語って何?っていう方はここの説明を見てほしい。

IN: .
USING: random io kernel sequences math ;

"" [ dup "ズンズンズンズンドコ" tail? not ]
[ { "ズン" "ドコ" } random append ] while
"キ・ヨ・シ!" append write

実行する。

$ factor zundoko.factor
ズンドコドコズンズンズンズンドコキ・ヨ・シ!

昔触ってたfactorのこと完全に忘れててこれ書くのになんやかんやで1時間ぐらいかかったけど、たまにfactor書くとやっぱ面白い。最近の連鎖性言語をちょろっと調べてみたら、今はkittenというイケてる感じの関数型連鎖性言語も登場してるみたい。暇があったらまたこういうの触っていきたい。