ISUCON 9 予選に isucon_friends として参加し、予選総合3位でした。

久しぶりの本戦出場

ISUCON3 以来なので 6 大会ぶりですね。。。思えばずっと予選で負け続けてきたものです。

yosuke-furukawa.hatenablog.com

結果どうだったか

予選3位通過でした(棄権含む)。最終スコアは 27,470 ですね。 isucon.net

1位 nil 1 [1] 52,440
2位 にがり 1 [1] 36,270
3位 isucon_friends 3 [0] 27,470 ★
4位 いんふらえんじにあー as Code 3 [0] 26,460
5位 ようするにメガネが大好きです 3 [0] 25,200

僕らよりもスコアが跳ねている、にもかかわらず、学生が1名でやっている、nilにがり は本当にすごいと思います。

何をやったかまとめ

言語は Go でした。 (Node.js ではありません。)

  • Index貼ったり、OR検索をUNIONに変えるなどでチューニング 2100点 => 2800点
  • キャンペーン還元率を 0 => 1 に。 この時点では3300点前後になるも、ボトルネックがログインに移った。
  • 3台構成にして、 nginx, app, DB にした。 この時点で 8800点程度、ただこの時点ではボトルネックはログインのまま。
  • bcrypt 剥がして SHA256 に rehash することに。ベンチマークを何度も回してその都度 rehash された password の結果をdumpし、パスワードハッシュ部分だけ書き換えるように。ベンチマーク流すたびに 10000点から少しずつ伸びていくので楽しかった。この時点で14000点
  • キャンペーン還元率を 1 => 2, 3, 4 と一気に変えていった。16000点に。
  • /buy 内でAPI 呼び出ししてる所を並列処理化、また同時に /users/transactions.json 内で API 呼び出ししてるところを並列処理化。25000点に一気に伸びた。
  • もう後は Lock wait 待ちが多くなったので、 N + 1 を改善しようとするも断念。Transaction Levelを REPEATABLE READ から READ UNCOMMITTED に変えてみたりして、悪あがき。 26000点になった。 (fail されないかビクビクしてた)
  • 最後にすべてのログをオフにしてレギュレーション確認しながらベンチマークを実行、 27420点 が出たところで終了

細かく効いたかは定かではないがやったこと

  • nginxのエンドポイントを HTTP/2 にした
  • Accept-Encoding が gzip だったら gzip 返すようにした (JSON のサイズが劇的に下がってた)
  • キャンペーンテーブルをインメモリに持った
  • 外部 API へのリクエストをする際に HTTP Agent の MaxIdleConns と MaxIdleConnsPerHost を拡張、1 ホスト 3000 コネクションまで持てるようにした。

やってみようと思いつつもできなかったこと

  • N+1 の解消
  • API のレスポンスが done status ならキャッシュする

この辺が思いついてはいたものの、残り時間で実装しきれず、断念した所です。 N+1 を IN 句に変えるだけでもやってもよかったかも。 この辺をやれていればもう少し伸びたかもしれません。

ISUCON9の感想

まずは予選突破できて本当に良かったです。若手や同僚にパフォーマンスの考え方を教えている身でありながら、本戦突破がそもそも1度しかできてなかったことを歯がゆく思ってました。

突破できて安心しました。

余談ですが、社内でR-ISUCONというISUCONを自分たち向けにカスタマイズした問題を作って会社全体で合宿しながら半年に一度のペースで会社全体で競っています。

今回、予選を突破している同僚が毎回社内ISUCONで一緒にしのぎを削ってるチームで、とても嬉しく思いました

・theorem 3 [0] 12,360
・ふんばり温泉チーム 3 [0] 12,060

R-ISUCONという社内ISUCONをやっていた結果、自分たち含めて3チームも予選を突破した事を本当に嬉しく思います。 このスタンプを社内でも使っていこうと思います。

f:id:yosuke_furukawa:20190908230806p:plain
本戦であいましょう

R-ISUCONについては今年の初めに 941さん と一緒にデブサミで登壇したのでその時の資料を展開しておきます。

logmi.jp

JavaScript Registryの今後

さて、前回は tinkyarn v2 における CLI 戦略の話でした。次は JavaScript Registry についてです。

ちなみにこの内容が今回 JSConf.EU 2019 で一番盛り上がったトピックです。

JavaScript Registry とは

JavaScript Package をバックエンドで管理しているサービスです。 npm が管理しているものがいちばん有名です。他にも GitHub が管理する Registry が公開される予定です。

The economics of Package Management

f:id:yosuke_furukawa:20190611135113p:plain
the economics of package management

slide:

github.com

video:

www.youtube.com

「Package Managementの経済」というタイトルです。 聴講者からすると、何話すのか不明でしたが、惹きつけられるものがありました。終わったあとはこれぞ「Tech Talk」という発表でした。是非時間があれば全ての動画を見てみるとよいかと思います。

筆者はここで語られていた内容を基に entropic について紹介し、最後にこの Registry で何がやりたいのかを話します。

Successful JavaScript Registry is hard

npm のパッケージは大きくなりました。いまや100万パッケージを超えるほどです。

一方で、 npm inc は営利を目的にした団体です。これだけ多くのpackageがあると管理コストも高くなります。 npm inc の経営状況がどうこうは色々な話がありますが、実際に公開されてる情報があるわけではないので、特に何かをここで言うつもりはありません。

ただ、 Registry の管理をビジネス的に成功させるのは難しい、ということです。

npm inc の Registry は基本的に無料で使えます。無料で使う場合、すべてのライブラリは public として公開されます。 privateenterprise でグループを作るなど、特別なアクセスコントロールをするライブラリを作る時には有料版を契約するというビジネスモデルです。

npmpublicOSSのライブラリが増えれば増えるほど、 運用コストがかかります。その運用コストを private ライブラリや enterprise Registry の売上で賄います。小さいサイズの Registry は運用コストがあっても寄付金で調整するのはそこまで難しくありませんが、大きなサイズになってくると寄付金だけで運用するのはやはり難しくなってきます。これをなんとかするために、 npm inc は Venture Capital からも出資を受けています。 

Venture Capital の意向が変わったら方針も変わりますし、結果としてコミュニティにとって最適な運営が行われるとは限らないわけです。

この話は npm に限りません。 RubyGems でも Perl CPAN でも運営コストの話はあります。ただ、 npm が管理している package の数は膨大で、他の Registry よりも遥かに難しい状況になっています。

f:id:yosuke_furukawa:20190617182135p:plain
module counts

http://www.modulecounts.com/

じゃあどうするか

Registry を分散して管理できるようにしていこう、というのがこの発表の内容でした。

一つの団体が一つの Registry を集中管理している状況をやめて、分散管理するシステムを作れるようにして、みんなでちょっとずつ運用コストを分散できるようにしていこうという話です。

これの構想の基になっているのが、JSConf EUトークの中にある、 Entropic です。

github.com

Entropic: a federated package registry for anything but mostly JavaScript

Entropic は 新しい Package Registry です。 npmyarn ではなく、新しい CLI である ds も持っています。

entropic/cli at master · entropic-dev/entropic · GitHub

dsentropicregistry につながることはもちろん、 npm の Registry も read only でつながります。read onlyなので、publishはできませんが、 npm に登録されている package もダウンロードできるようになります。

ちなみにまだ experimental なので変更される可能性も大いにあります。

どうやってpackageを指定するか

dsdomain , namespace , package name すべてを指定して、ダウンロードします。

namespace@example.com/pkg-name

こういう指定方法で Package.toml に記述があると、 package がダウンロードされます。例えば、 ds 本体をdownload したい場合は chris@entropic.dev/ds と指定します。

ドメインを指定するので、別サーバで別DomainのRegistryであっても package の指定ができます。 (逆に言うと Domain を失効したらダウンロードができなくなるということですね。)

もしも npm に接続したい場合は、 legacy@entropic.dev/<pkgname>legacy ネームスペースを指定し、 entropic.dev ドメインpkgname にアクセス先の package を指定すれば npm からダウンロードできるようになります。

(おそらく entropic.devlegacy ネームスペースは npm への alias になってるんでしょう)

Docker の実行環境さえあれば、 Registry を構築することは簡単にできます。

https://github.com/entropic-dev/entropic/tree/master/services/registry#running-your-own-registry

Entropic は自分たちの手元で起動し、対象となる package ダウンロード先のhost を指定してダウンロードします。その host に自分たちが使う package のキャッシュが構築され、初回は Package.toml に記述したドメインのホストからダウンロードされますが、 2回目以降は自ホストのキャッシュを利用します。

f:id:yosuke_furukawa:20190617185414p:plain
entropic download chart

アクセス権

すべての package は public となり、誰からでも install し、誰からでも閲覧できる形になります。 private のアクセスをしたい場合は GitHub の Registry を併用する形になると思います。

また、一緒にライブラリを編集したい場合は publish 権限を他のユーザーに付与することも可能です。

https://github.com/entropic-dev/entropic#overview

Entropic のゴール

ここからまた少しエモい話ですが、 Entropic全ての JavaScript package を Entropic 上で扱おうとしてはいません。つまり、これで npm を倒すという話ではありません。

じゃあ何がゴールになるかというと、

1. 「何もしないでnpmが倒れるか、有効策が出るまで待つ」以外の選択肢を用意したい

2. 「分散管理するRegistryの運用知見」を広めたい

3. 「中央集権から分散管理」に振り子を戻したい

という話です。 npm を倒すのではなく、 npm 以外の選択肢を用意し、その運用知見を全体に広げ、分散管理していくという話は非常に分かる話で、特別な専門知識がなくても管理できるように 共通理解をみんなで深めていこうという深い話でした。

f:id:yosuke_furukawa:20190617184648p:plain
take back the commons

まとめ

1年前、 JSConf EU 2018 で、 Ryan Dahl は module や package について、深く色々な反省をしていました。

yosuke-furukawa.hatenablog.com

その中でもあったのが、「Nodeのモジュールの管理運営自体を private controlled にしてしまったこと」があげられていました。

1年後、 JSConf EU 2019 は節目の年です。コミュニティを代表するようなカンファレンスで Entropic のような発表があったことは一つの epoch making な話だったと思います。来年は一旦 JSConf EUはありませんが、数年後にどうなっているか確認する、というバトンを渡されたような思いでした。

今年 JSConf JP をやる予定ですが、この辺の話もできれば幸いです。

npm, yarn による zero install 戦略

jsconf.eu 2019 に行ってきました。 特に npm や yarn の今後の話とそもそも Registry をどうしていくか、の話があったのでお知らせします。 そもそも Registry をどうしていくかについては次のエントリで話します。

tink: A Next Generation Package Manager

npm の次のコマンドラインツールである tink が紹介されていました。

github.com

presentation: github.com video:

www.youtube.com

そもそも npm の仕組み

  1. ローカル依存ファイルを読む (package.json, package-lock.json, shrinkwrap.json)
  2. 存在しないパッケージのメタデータをfetchする
  3. 木構造を計算して、実行する(npm v3 以降だとflattenする)
  4. 実際に存在しないパッケージをダウンロードする
  5. インストールスクリプトを実行する

今のどこがダメなのか

npm は tar ball を fetch して、そこから gunzip して、最後にできあがったファイルをnode_modules以下にコピーするという非常にピーキーな処理をしています。最初のfetchは network IO に影響し、 gunzipCPU に影響し、ファイルコピーは file IO に影響します。

これを簡単にするためにキャッシュしたり、展開済みのファイルをハードリンクさせたりとチューニングをしています。 これ自身は必要な処理なのですが、実体のファイルとして作る関係上、どうしても node_modules は巨大になります。

https://cdn-ak.f.st-hatena.com/images/fotolife/y/yosuke_furukawa/20180604/20180604215229.png

tink sh

tinknode 本体の代替として起動します。

$ node foo.js

で起動するのではなく、

$ tink sh foo.js

で起動します。これで何がやりたいかというと、 node_modules を物理的なフォルダにするのではなく、仮想上のフォルダにすることを目指してます。

仮想上のフォルダになることのメリット

いくつか利点がありますが、まず実際にファイルをコピーする必要がない分、 File IO への影響は緩和されます。

また、 tink 自身はローカル内にハッシュ値を基にしたキャッシュを作るので、ハッシュ値が一致したパッケージに関してはキャッシュが使われます。  Network IO への影響も緩和されます。

また、最大のメリットとして、 tink sh で実行した際にランタイムで依存モジュールを解決するため、 npm install のコマンド実行が不要になります

つまり、 git clonegit pull してから依存ファイルがなかったとしても tink sh <cmd> で起動すれば実行時に依存モジュールを解決し、起動することができます。

virtual node_modules
virtual node_modules

この試みのことを zero install と呼びます。

prepare && unwind

本番環境で Docker 等を使って毎回ゼロからイメージを作ってる場合はイメージ作成後のキャッシュがないため、毎回起動時にパッケージのダウンロードが開始されます。

これを解決するために事前にFetchしてくるコマンド(prepare)と事前に node_modules を作るコマンド(unwind)の2つが提供されています。

$ tink prepare # 事前にfetchしてくる
$ tink unwind # node_modulesの実体を作る

load map

tinknpm v8npm コマンドに統合される予定とのことでした。

f:id:yosuke_furukawa:20190610102508p:plain

yarn v2: berry

presentation:

www.youtube.com

yarn v2tink と同様の戦略です。zero install を実現しています。 .pnp.js というファイルを内部に作成し、そこに依存モジュールを解決できるようにしています。

開発ツールとしては tinkyarn v2 も同じ戦略を取っていました。細かな機能の違いはあるのでいくつか紹介します。

yarn contraints

package.json と実行時の依存関係に矛盾があった場合に、警告した上でpackage.jsonを修正してくれるサブコマンドです。

一番多いユースケースは、実行時に依存してる package が package.json に書かれてなかったとか、 workspace と一緒に使った際にmonorepoのサブパッケージ間で異なるバージョンのライブラリに依存してた等ですね。

いわば、 package.json の linter みたいなものですね。

どうやって実現しているのか

tinkyarn v2 も実態は node のプロセスである以上、 node 側の標準モジュールでは node_modules 以下にあるファイルをロードしに行く必要があります。 これを解決するために、 tinkyarn v2 では node の標準APImodule にパッチを当てています(!)

module のファイルロードを行う箇所のメソッドを拡張し、 node_modules がなくてもファイルをロードできるようにしています。

標準のモジュールロードからは逸脱しているため、今のところ使うのは危険ではあります。将来的に読み込み方が変わる可能性もありますし、標準の node の読み込み方を変更する可能性もあるので、まだ experimental と言ったところでしょうか。

ただし、 electron も同様の手法でモジュールを読み込めるように拡張しているので、そこまで変更がドラスティックに加えにくい箇所でもありますね。

実際に、 tink の解説では、 electron も同じことやってる(ので大丈夫)というニュアンスで発表していました。

f:id:yosuke_furukawa:20190610101630p:plain

まとめ

モジュール管理は zero install 時代になっていくと思います。事前の処理を不要にすることで開発効率を上げて、 git clonegit pull から何もしなくても起動できるようになっていくと思われます。ただ一方で実際に本番で zero install にしてしまうと、起動してから実際に動作するまでのパフォーマンスは落ちる可能性もあるため、起動方法は変更になるかと思われます。

これらを解決するための本番環境用のコマンドとして、 tink preparetink unwind も公開されているので、それらを使って行くのではないかと思っています。

また一方で、 tinkyarn v2 もほとんど同じことをしているので、どちらにも有意差があるようには見えず、状況は変わらないまま今後に突入していくのではないかと思われます。

これらを踏まえて、 Registry についての話を書きます。また次回!

JavaScript が読み込まれる前でもWeb Applicationを動かす

今回は最近取り組んでいる、 JavaScript が読み込まれる前であっても「ちゃんと」 Web Application が動作するように作る話をします。

Server Side Rendering における注意点と対策

BFFを使ってServer Side Rendering をすることに数年前から取り組んでいます。

まずはSSRをやる上での注意点と対策について紹介します。

SSRをすることはSEOのためだと思われがちですが、個人的にはSEOのためにしているわけではなく、 First View を向上するため(特に First Meaningful Paint を向上するため)にやっています。

f:id:yosuke_furukawa:20190210220602p:plain
First View

SEOSSRに関しては Google が最近出したこの記事SEO Considerations 節が詳しいです。ここでは説明しません。

SSRをしない、Client Side Renderingのみの場合、この First Meaningful PaintJavaScript がダウンロードされてからになるので、遅れてしまいます。

ユーザーの環境は様々で、潤沢なwifi環境が揃っていて、最新のマシンが使えて高速という環境ばかりではありません。古いマシンを使って、インターネット環境が整備されてない状況ではJavaScriptをダウンロードする時間もJavaScriptをダウンロードしてから実行する時間も遅くなります。

色々なケースも想定し、SSR を使って First Meaningful Paint を向上することで、表示されるまでの時間の短縮を行っています。

ただし、SSRFirst Meaningful Paint を高速化する一方で、表示が速すぎると、操作するまでの時間、 Time To Interact までに乖離が発生します。

f:id:yosuke_furukawa:20190210221642p:plain
Gap between FMP and TTI

乖離が長ければ長いほど「見えてるのに操作できない時間」が長くなり、ユーザーのストレスになります

これを改善するためにはページあたりに読み込まれるJavaScriptの量を減らすことで、読み込まれる時間を改善する、 Code Splitting と呼ばれる前処理をする必要があります。また、Time To Interact の時間までインジケーターを出してユーザーに処理中であることを表示するのも有効です。

ただ、Code Splitting をしたとしても分割しすぎるとページ遷移のたびに差分のJavaScriptが必要になったり、そもそも React DOM などの巨大なライブラリに依存していると全体で読み込まれるJavaScriptgzip後で数100kbを超えることも珍しくなく、限界があります。

逆にSSRをやめて、Client Side Rendering のみにしてしまうと、「見えるまでの時間」と「操作するまでの時間」のギャップはなくなります。しかしこの場合、人間としては「見えて(認知して)から操作する」ので、ユーザーにとって最適な時間にはなりません。

JavaScript が読み込まれる前でも操作できるようにする

そこで、今取り組んでるのが、いくつかのページではJavaScriptが読み込まれる前でも普通にウェブアプリケーションとして操作できるようにしています。

HTML と Server だけでもちゃんと動くように作る

こうなると、 HTML と Server だけでもちゃんと動くように作らなければいけません。JavaScript を disabled にした状態でどこまでちゃんと動作するかを確認しながら作る必要があります。

リンクの場合

JavaScript のみで動作させる場合、リンクには click イベントをフックするハンドラを用意して、そこで pushState などのURL変更 API を使って遷移させることが多いです。

SSRレンダリングした上で、リンクなどの処理は a タグで書きつつ、 遷移先のURLを定義します。 click ハンドラはそのままにしておけば、JavaScriptが読み込まれる前に実行してもただの a タグでの遷移として動作します。

<a href="/foo" id="js-link" />

// JavaScript
document.getElementById("js-link").addEventListener("click", (e) => {
  e.preventDefault();
  history.pushState({}, "", e.target.href);
})

この辺りはSSRを作る上ではライブラリに頼ることも多いと思うので、ライブラリが提供してくれる機能でも動作します。 react-router などのライブラリも同様の機能を提供します。

form の場合

form の場合は複雑です。formの場合はSSRとは違って、 method が POST のケースも多いので、 POST を受け付けられるエンドポイントを用意する必要があります。

また、 methodaction などの form の属性もきちんと指定する必要があります。 form の method を指定しないために、全部 GET リクエストになってしまったり、ボタンをsubmitにしてなかったために、きちんと送信されないケースも散見されます。

また、 POST などの更新系の操作をする場合、厄介なのは CSRF 対策もしてあげる必要があることです。 hidden の input に対して csrf token と呼ばれるセッションに紐づくランダムな値を設定しないといけません。XHRとは違ってカスタムヘッダを渡すことも、Cross Origin のときにpreflightチェックのリクエストが飛ぶこともないので、準備が必要です。

// form に対してmethodを指定する。
<form onSubmit={handleSubmit} method="POST">
      <div>
        <input type="email" name="username" component={RenderInput} />
        <input type="password" name="password" component={RenderInput} pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"/>
      </div>
      {/* csrf 対策を入れる */}
      <input type="hidden" name="_csrf" value={csrf} />
      <div>
        <button type="submit" disabled={submitting}>
          Login
        </button>
        <button type="button" disabled={submitting} onClick={reset}>
          Clear
        </button>
      </div>
</form>

ログインのような典型的なフォームの場合はユーザーが何をするべきかが表示された段階ではわかっている事が多いため、操作するまでの時間を短縮することで、効果も大きくなります。

また、検索画面のようなフォームも入力項目が少ないため、ユーザーは表示された瞬間に迷わずにクエリーを打ち込みに行きます。このときにクエリーパラメータでURLが変わったとしても動くように作ってあげる必要があります。

このアプローチのメリットとデメリット

アプローチの内容はわかったところで、メリットとデメリットについて紹介します。

メリット

まずは性能的な面でメリットがあります。先程、操作できるようになるまでの時間と表示するまでの時間に乖離が大きいとユーザーはストレスを感じる、という説明をしましたが、JavaScriptをダウンロードするまで待つ必要はなく、「操作できるようになる時間が表示された時間とほとんど同じ」 になります。

ちょうど数ヶ月前に Netflix React の CSR をやめて、SSRでのみReactを採用した、という記事がありましたが、そこでもパフォーマンスの改善事例として紹介されていました。

アプローチとしてはほぼ一緒です。Time to Interact にフォーカスするのであれば、 JavaScript をダウンロードされてなくても動作させる方が効果的です。

次に accessiblity としても効果があります。JavaScriptに頼らずに普通に作ると verified な HTMLを書く必要に迫られます。form の method や action もそうですが、input の name や type といった属性もきちんと書かないといけません。こうすることで、矯正ギブスのような役割を果たしてもらえます。

デメリット

一言で言うと、「実装するのが大変」というところです。一度すべてのページを JavaScript をオンにして動かせるようにしたあとで JavaScript がオフでも動くようなアプリケーションにすることは実装の観点から見るとやってやれなくはないものの、大変です。

また、完璧に JavaScript が動作するアプリと同じUXを提供することは不可能です。先程のformの例でいうと、 validation などは input タグの pattern 属性にマッチしてるかどうかしか出すことができません。 JavaScript を使った validation では、もう少し細かく入力値をチェックできます。例えば「パスワードは英字、数字、記号の3種類が必ず入ってて、8文字以上」などの条件の validationpattern 属性で正規表現で書いたとしても、「パターンにマッチしたかどうか」だけしかチェックされません。 JavaScript では、「記号が抜けてる」、「8文字以下」という細かくメッセージで何が満たせてないかを表示させることで入力を補助させることができます。

リンクならともかく、ボタンの場合や、モーダルウィンドウで確認ダイアログを出したい場合など、大体においてJavaScriptが必要なケースは多く、すべてを JS が disabled にした状態で動作させるようにするのはやはり難しいと言わざるを得ません。

個人的には、ログインやトップページの検索画面など、ユーザーがある程度最初の方に触る(JavaScriptがダウンロードされる前に触りそうな)ページを JS disabled でも動作するように作り、残りは noscript タグで JavaScript がオンじゃないと動かない旨を出してあげるくらいでしょうか。

また、最後にどうしようもないところですが、解析系のタグが動作する前に動いてしまうので、ユーザーのトラッキングはできない可能性があります。この手の解析系がちゃんと動かないとNGのところも多いので、注意してください。

まとめ

JavaScript が読み込まれる前に SSR と HTML だけで動作するアプリを作ることに関しての紹介をしました。 最近の開発では、この方法を基本としており、SSRの弱点の一つである、 First Meaningful PaintTime to Interact までの差を JavaScript が読み込まれる前でも動作させることで解消しています。

ただし、すべてのページでできているわけではなく、トップページに近いような場所でのみ、部分的に動作させています。こうすることで以下のような効果を狙っています。

  1. JavaScript がダウンロードされてなくてもある程度は動作することで、パフォーマンス上のメリットを狙う
  2. HTMLでも verified な状態にすることで、 accessibility の観点や JS がオフのユーザーであってもある程度は利用できるようにする
  3. すべてのUXをJSオフの状態で提供することは不可能なので、必要なページではJSがダウンロードされるまで動作しないように作る

こうすることで、SPAのUXも提供しつつ、潤沢なインターネット環境を持っていないユーザーであってもある程度高速に表示され、動作するように作っています。

再入可能なロックの話

突然のロックの話

いきなりロックの話をしましたが、10月に(なぜか)一緒に働いてるメンバーとの中で大盛り上がりした話題です。もともとはリクルートテクノロジーズで行われている、柴田芳樹さんのプログラミングGo勉強会で話題になった話です。

yshibata.blog.so-net.ne.jp

ここにも書いてあるのですが、 Golang では sync.Mutex を使ったロックでは再入可能ではありません。 一方 Java のロックは再入可能です。

で、この設計に関しては合理的な解説が Russ Cox さんからされています。

groups.google.com

意訳すると以下のような感じですね。

再入可能なロックはbad ideaだ。

mutex を利用する主な理由は mutex が不変式を保護するためだ。
不変式というのは、 例えば 円環(linkedlistのようなもの) の 全要素 p に対して p.Prev.Next == p が成立するといった内部の不変式であったり、
自分のローカル変数 x は p.Prev と等しい、といった外部の不変式を指している。

mutexのロックを取るというのは、「私は不変式を維持する必要がある」というのと、「これらの不変式を一時的に壊す」という二点の表明である。
また、 mutexのロックを開放するというのは、「不変式にはもう依存していない」というのと、「一時的に壊した不変式は元に戻っている」という表明である。

再入可能なロックを取るというのは、いったん mutex のロックを確保した状態で再び mutex のロックを取るが、この状態では不変式を一時的に壊している可能性がある。再入可能なロックは不変式を保護しない。

再入可能なロックというのは単なる間違いであり、バグの温床になる可能性がある。

この話には納得できます。ロックの再入可能可否についてはできないようにする方が良いというのは納得できます。余談ですが、プログラミング言語Go以外の本にもEffective Javaにも同様の話がありますし、詳解Unixプログラミングでもこの手の話はあります。

じゃあなぜJavaは再入可能なのか

Javaは既存のAPI資産がスレッドセーフになっているものがあり、それらの中にはメソッドの中でロックを取っているものもあります。この状況では再入可能なロックを認めざるを得なかったため、今ではバッドプラクティスとして残っています。例を挙げると、HashTableやVectorといった既存のコレクションクラスがスレッドセーフですね。

ちなみに 詳解UNIXプログラミングの中に出てくる pthread も同じく再入可能にするオプションがあります。これも既存のAPIでスレッドセーフなものが多いから渋々追加している機能です。

というわけで、そもそも再入可能なロックを提供すること自体はGoでもJavaでもUnixプログラミングでも望まれていない訳ですね。

社内で盛り上がった内容

さて、再入可能なロックを提供しないという方針については基本的に全員同意しており、これまでの話に対しては反対意見は無いですが、よくよく考えると少し腑に落ちない点があります。それは、「不変式を守るのは、ロックの有無に限らず守らないといけないのではないか?」という点です。

この不変式を守るという話でmutexの再入可能なロックを取らなくしただけではなく、本来的には壊さないように全員が気をつけるべきであり、この問題について取り組んだのが、有名な「契約による設計 (Design By Contract)」の話です。

契約プログラミング - Wikipedia

EiffelやD言語ではこのDesign By Contract を言語仕様に取り入れているというのは有名な話ですね。

Golangでは、不変式を守るという話についてここまで説明があるにもかかわらず、Design By Contractを言語仕様には取り入れていませんし、assertすらありません。

assertを提供していない件についてはちゃんとFAQがありますが、契約による設計を取り入れてない理由も含めてGo言語がそういう取捨選択をしている理由はなんなのか、というので、話が盛り上がり、何度か柴田さんやkoichikさん、和田さんを含めて議論しました。

議論ポイントを整理すると、「ロックを再入可能にしない」という設計については納得するものの、「そこまで不変式を守ると言うなら契約による設計やassertについては入れないという選択をしたのはどうしてか」といった部分ですね。

ただどちらの主張も実は衝突するような話ではなく、「ロックを再入可能にしないのは不変式を壊したくないから、ただし、不変式を壊したくないからと行ってDesign By Contractまでのゴツい仕様は入れたくなかった」という話だろうと、古川は推測していますし、この理由である程度納得しています。

並列並行処理

色んなプログラミング言語を知っていると正解は一つではないというか多様な正解があるという事がわかります。Goの考え方はUnix哲学的なものであり、シンプルな解答を用意しつつも、バグの温床になるような言語仕様は避けようとする考え方が見られます。

一方で、この手のmutexの問題は基本的に「並列プログラミングが難しい」という問題に根ざしたものであり、これに対して何度も挑戦していないと議論ができるようなポイントに到達できないな、と改めて感じ、年末年始はこの本でも読もうかなと思いました。

www.oreilly.co.jp

Yearly Node.js 2018

Node.js 2018 まとめ

この記事は HTML5j カンファレンスで発表した、 Node.js 2018 のまとめの話をブログに起こしたものです。

speakerdeck.com

ちょっとずるいですが、この記事一つで Node.js アドベントカレンダーJavaScript アドベントカレンダーの25日目の記事です。

10月にNode.js v11 がリリース

Node.js v11 は変更点はいくつかありますが、v11.0.0ではそんなに大きな機能はありません。代わりに性能向上と安定性向上を行っています。

これにはNode.jsのコア変更ポリシーが関わっています。

Node.js Core Policyである 「Less is More」

Less is More という言葉をNode.js の文脈で最初に使ったのはこの jsconf での発表が初めてですね。

www.youtube.com

要は「豊富な機能を追加するのではなく、最小限の機能でコアは小さくシンプルにする」という話です。 もともとは建築家の言葉で、「これ以上ないことは豊かなことである」とも訳されます。

さて、この発表の中でも大きな機能が少ない代わりに、フォーカスすることとして、安定性・性能・セキュリティを向上させることについて触れています。

今回はNode.js が2018年の中で、どういう形でこれらの非機能要件とも言える情報について改善を重ねてきたかを解説します。

安定性

安定性と一口に言ってもいろいろあるのでここでは、Node.jsが安定性を得るためにやってることを紹介します。

LTS

Node.js は長期間サポート(LTS)があります。

https://github.com/nodejs/Release/raw/master/schedule.png

このサポートはLTS対象のバージョンであれば2年間のパッチリリースが確約され、セキュリティのアップデートは3年間受けられるというものです。

今だとv6.xが4月までセキュリティアップデート期間、v8.xが4月までバグ修正のアップデート期間です。v10.xは予定では2020年の10月まで受けられます。

V8 の ABI 互換性サポート

Node.js の内部のJavaScriptエンジンであるV8はNode.jsに対しての非互換の修正があるときには事前の通知がされるようになっています。 また、V8自身はアップデートがある度に、Node.jsに対して最新のmasterを追加し、テストが落ちないかを定期的にモニタリングしています。

github.com

Jenkins によるCI実行

Node.jsでは、PR毎に各種CPU, OSのビルドをJenkins上でCIを回すことで壊れるかどうかを確認しています。

jenkins-node-ci
jenkins-ci

ただ、Node.jsのテストも膨大な数があるので、testが実行されると中には PASS したり、 FAIL したりする flaky なテストがあります。これらについてはレポートされる仕組みがあり、その中で詳細な調査を行いながら修正されていきます

flaky test
flaky-test

つい最近 flaky なテストが全部PASSして、グリーンになった!ということでコアメンバーが喜んでました。

(ただこのツイートにもあったとおり、明日にはすぐにイエローになってしまいましたが。)

アプリケーションを安定化させる試み

大きな機能追加はないですが、アプリケーション内でCPU負荷が高いときのinspectorや非同期処理実行時にtraceする async_hook といった機能が追加、改善されています。

Inspector | Node.js v11.5.0 Documentation

Async Hooks | Node.js v11.5.0 Documentation

これらの機能はnode.jsの内部状態をもとに解析するツールです。CPUのプロファイラはV8の内部プロファイラの機能を利用して状況を把握するためのツールです。こういった機能が増えることで、安定性を改善しています。

const inspector = require('inspector');
const fs = require('fs');
const session = new inspector.Session();
session.connect();

session.post('Profiler.enable', () => {
  session.post('Profiler.start', () => {
    // invoke business logic under measurement here...

    // some time later...
    session.post('Profiler.stop', (err, { profile }) => {
      // write profile to disk, upload, etc.
      if (!err) {
        fs.writeFileSync('./profile.cpuprofile', JSON.stringify(profile));
      }
    });
  });
});

性能

Node.js においては性能も重要な指標の一つです。これも維持するために色々やっています。

ベンチマークを常に測る

benchmarking グループというワーキンググループがNode.jsのパフォーマンスを常に計測しています。

benchmark
benchmark

これを見ながら大きなregressionが起きていないかとか、バージョン間で差を見ることもできます。基本的にV8がパフォーマンスを向上させているので、省メモリになっていたり、高速になっています。

また、マイクロベンチマークだけではなく、現実のアプリケーションでもどれくらい下がっているかを計測するためにExpressを使った航空機予約システムである、acmeair という模擬システムでも評価しています。

GitHub - acmeair/acmeair-nodejs: A Node.js implementation of the Acme Air Sample Application. With datastore support of MongoDB, Cloudant, Cassandra. With runtime support of Bluemix/CloudFoundry, Docker... With Micro-Services.

Worker

Node.js の昨今の利用例として、ネットワークサーバだけではなく、babel, webpackといったフロントエンドのツールとして使われることが多いです。この様な時には大量のファイルを変換したり、文字列連結をしたりするので、IOの時間よりもCPUの時間が支配的になります。結果としてマルチスレッド・マルチプロセスでの処理の方が効率的にCPUが利用できます。

Node.js: The Road to Workers

Turbo Boost Next Node.js - Speaker Deck

実際に筆者もbabelを使ってmulti-threadとmulti-process、シンプルに一つのプロセスを使ったもので比較してみました。筆者の計測結果を以下に載せます。

worker result
worker result

これを見ると、ファイル数が100以上であればマルチプロセスよりもマルチスレッドのほうが高速になるという結果が出ました。プロセスを起動するよりもスレッドを起動するほうがコスト的に若干安いので、こういう結果になりますが、まだSharedArrayBufferは利用していないので、メモリ共有をしだすとどうなるかはまだ考察していません。

ちなみに最近入った llhttp というパーサがやばい

最近入った Fedor Indutny 製の HTTP Parser ですね。

github.com

これ、えげつないっす。

HTTP Parser はこれまで C で書かれた http_parser が使われてました。 しかしながら、 Cのhttp_parserは中身を見るとメンテナンスしやすいとは言えず、またアクティブなメンテナもいなかったので徐々にブラックボックス化していました。

Fedor の作った llhttp は「JavaScriptで書いた処理をLLVMバイトコードC言語に変換することでHTTPのパーサを作ってしまう」というものです。正確にはTypeScriptで書かれており、TypeScriptで書いた処理をC言語LLVMバイトコードに変換しています。

これ、普通だと逆で、C言語 / LLVM で書かれたものを JavaScript でも呼べるように asm.js や wasm に変換する」というアプローチを取りそうですが、 Fedor は「 JavaScript で書いた処理を C言語 / LLVM に変換」しています。

中身を読むと分かりますが、実際にはCやLLVMのジェネレータがあります。Node.jsで試すなら、build optionで --experimental-http-parser を付けてビルドするか、 実行時に --http-parser=llhttp とやると最新の Node.js では実行できます。

llhttp
llhttp

セキュリティ

Node.js でも昨今問題になっているセキュリティについてもコアでの取り組みを紹介します。

セキュリティワーキンググループ

Node.js 内部では TSC と呼ばれるコアの内部で話し合いが行われています。毎回セキュリティのトピックは話されており、特に OpenSSLや V8 といった内部依存ライブラリの脆弱性があると事前に関係者だけに告知され、パッチの適用後、全体に通知されます。

nodejs.org

あんまり知られていませんが、 Bug Bounty プログラムも行われています。これにより、セキュリティの脆弱性をついたバグには報奨金が支払われるようになっています。

hackerone.com

セキュリティリリースがあると以下のように告知されます。

nodejs.org

セキュリティの取組み(npm, yarn)

コアのセキュリティではありませんが、3rd party製のライブラリでもセキュリティ障害が見られることがあります。 記憶にあたらしい所で行くと、 event-stream が別メンテナーによってセキュリティの問題を仕込まれた事がありました。

github.com

このような問題は急成長している npm のモジュールだと発生しがちです。対策としては今の所事後策で自分のリポジトリ内に問題があるかを調査することしかできません。そのようなコマンドを npm も yarn も用意しているので、積極的に使っていきましょう。

https://docs.npmjs.com/cli/audit

https://yarnpkg.com/lang/en/docs/cli/audit/

この手の npm|yarn audit コマンドを実行すると、自分の package-lock.json や yarn.lock 内にあるリポジトリ脆弱性の報告がないかを検証してくれます。

Web Standards

「Less is More」といっても例外があります。 Web 標準のAPI に関しては機能追加しようとする動きがあります。

コアコミッターの一人である James Snell さんの話にあった言葉を紹介します。

why node.js needs web standards
why node.js needs web standards

「Node.js は主にウェブアプリケーション開発者プラットフォームとしても今までも、今も存在している。一方で Node.js のコアは small core という哲学を表明している。この small core の中には Web Standards によるものも含まれている。」

これらの流れから、HTTP2 や ES Modules 、 Promise の改善といった機能追加は Web 標準の API と合わせるために行われています。

Promisify や fs.promises は Promise 改善の流れです。

util.promisify が追加された - from scratch

File System | Node.js v11.5.0 Documentation

また、 HTTP/2 から HTTP/3 までの流れも検討はされています。

ngtcp2をベースに HTTP/3 の JS 実装をしようという検討は書かれています。

今後の流れ: Unified JavaScript Platform

今後は JavaScript の共通プラットフォームとして統合していこうとする流れがあります。

Unified JavaScript Platform
Unified JavaScript Platform

現在は、 Web Standard API に関しては W3CWHATWG といったグループが作っています。Node.js の Standard API は我々 Node.js core memberが作っています。また、それらの中間にある JavaScript そのものの API や文法は ECMA/TC39 といったグループが作っています。

これらのグループには特にコンセンサスが取られているわけではなく、それぞれがそれぞれで緩く繋がっていましたが、今後はこの繋がりを強化して、もう少しお互いのコンセンサスを取りながら統合していきたいという話が NodeFest 2018 の Node Discussion でされていました。

W3C / WHATWG で作られたAPI と Node.js の API は歩み寄りをしていき、なるべく寄せていきます。また、その中央で ECMA/TC39 が仕様を固めるという風に三者がまとまりながら話を進めていくようにしていきたいという話がされていました。

Web API も Node.js APIECMAScript も求めているのは "ユースケース" です。さらにWeb API も Node APIECMAScriptも全部丸っと知っているのは仕様策定者よりも開発者になります。開発者、つまり僕らがライブラリやアプリケーションを作ってユースケースを作っていき、仕様策定者側にフィードバックしていく必要があります

つまり、リードしていくのは、仕様作成者だけではなく、我々です。

2019年は Node 学園祭は jsconf.jp として生まれ変わる予定ですが、そこでも仕様フィードバックの場を設けて今後の未来を一緒に作れるようにしていきたいとおもいます。

蛇足

この手のNode.js と JavaScriptアドベントカレンダーの活動も今後は JavaScript アドベントカレンダー一つにして、記事数が足りなくなったら「その2, その3」と増やせるようにしていきたいですね (というわけで Unified Advent Calendar Entry にしてみました)。

Chrome Dev Summitに参加しました!

Chrome Dev Summit に初参加しました!色々トピックとして気になったものを紹介してます。後直接 Addy Osmani とか Paul Irish とかに聞く機会があったので、色々ついでに聞いてきました。

Chrome も 10 周年なんですよねー。感慨深い。

1日目は「現在のChromeでできること、やってること」という感じで、ケーススタディやツールチェインの話が多めでした。 2日目は「未来のChromeでできること、今後やるべきこと」という感じでした。

1日目の熱かったもの

ProjectVisBug

github.com

特定のサイトに対して画像を変更したり、一部のコンテンツの内容を改変したりすることがGUIを通してできるツールですね。

f:id:yosuke_furukawa:20181116195400g:plain

意外と簡単にインストールして、ドラッグアンドドロップやフォントサイズの変更がGUIで変えられるので、オーサリングツールみたいな感じですね。普通にインストールしておくといいと思います。見た目をさっと変えてイメージ伝えるのに良いですね。

Squoosh

squoosh.app

画像のエンコード形式を変更したときの見た目をbefore after形式で見ながら自分の画像の最適なものに変更してくれるツールですね。ツールとしても有用ですが、ツールとしてというよりも中身がすごいですね。 WASMでwebpやmozjpegなどの各種エンコード形式をブラウザで変換してますし、それだけじゃなく、web workerを使っていたり、service workerを使っていたりとモダンな機能をふんだんに使ってますね。

f:id:yosuke_furukawa:20181116200037g:plain

ツールとしてはもちろん、今のOff the main thread や PWA や WebAssembly の全部入りのプロジェクトとして興味深かったです。

Performance Budget Case Studies

昨今のトピックであるPerformanceの話ですね。今回はPinterest だったり、Spotify だったりとパフォーマンスのケーススタディが多く、最近の仕事に近いので参考になりました。

特に Performance Budget という考え方が最近は主流になりつつあるので、各社の対応がどうなってるかが知ることができたのは非常に有用でした。

f:id:yosuke_furukawa:20181115225922p:plain

日経電子版以降、こういう事例が増えましたね。

ただ一方で、ちゃんと気をつけないといけないのは、「パフォーマンスを上げることが即ビジネスのKPIに繋がる」という話はビジネスのKPI次第なので危険ですね。いろんなファクターがビジネスKPIに関連する中でパフォーマンスを上げることはベースラインの品質を上げることはできてもビジネスKPIとは直接起因するファクターになるかは微妙です。

Chrome Dev Summitの話の中で面白かったのは、「Long Term のビジョンを持ちつつも、 Short Term での計画を作っていく」という点です。いきなりビジネスKPIを求めるのではなく、長期的なKPIを上げるというビジョンと短期的な成果を上げていくのが重要というのは水を浴びせられるような気持ちになりました。

f:id:yosuke_furukawa:20181115230703p:plain

この話が無茶苦茶刺さった。。。やっぱ一度パフォーマンス改善をやってみると分かりますが、そんな簡単にビジネスKPIに繋がらないんですよね。

『速くなったことでユーザ体験はよくなったとしてもユーザ体験を上げることが即売上につながるわけではない』、というか。ただし、じゃあやらなくていいかというと違っていて、それは目に見える成果につなげていくための階段の一歩目でしかなく、もっと着実にステップを踏んでいくことで最終的によくなるという話にしないといけないわけです。

2日目の熱かったもの

2日目からは Addy Osmani と直接話したり、色んな人と話に行っていた関係で、途中で退出したものもあったのですが、それにしても面白い発表ばかりでした。

Off the main thread

main threadを使わずにworker threadを如何にうまく使うか、というところに焦点を当てた話ですね。ここのトピックでもいくつか話はありましたが、まずはweb workerのpain pointの話からスタートします。

f:id:yosuke_furukawa:20181116180429p:plain

web worker はメッセージパッシングモデルで実施されていますが、メッセージのやり取りの際にserialize と deserialize が交互に発生します。このやり取りを thread hop と呼んでいて、thread hopがたくさん発生するとNGという話が書いてありました。

f:id:yosuke_furukawa:20181116180347p:plain

これに対して、 Tasklet と呼ばれるライブラリが提案されていました。これは Task 間での協調を簡単にするためのライブラリですね。まだ experimental とのことです。

f:id:yosuke_furukawa:20181116180317p:plain

更に言うと、 Worker にした所で手放しに良くなるわけじゃありません。

f:id:yosuke_furukawa:20181116180743p:plain

Worker にすると rendering はスムースになりますが、入力のレイテンシは遅れます。メインスレッドを阻害しないというだけで直接高速になるとかそういうものではない、ということですね。

worker dom や amp script と呼ばれる amp の仕組みでは、メインスレッドを阻害しないようにしており、このトレードオフをうまく使って実現されているとのことでした。

f:id:yosuke_furukawa:20181116181019p:plain

この他にも Actor Model などの考え方が紹介されており、UIをどう作るかが変わってきそうだなと感じました。

WebPackaging

f:id:yosuke_furukawa:20181116200329p:plain

WebPackaging の Signed Exchange というコンテンツに対して署名して、コンテンツオーナーであることが確認できればURLバーをコンテンツホルダーのURLに変更できるという仕組みが紹介されていました。

f:id:yosuke_furukawa:20181116173440p:plain

特にAMPで有用な技術ですね。AMPでは、Googleの保持するAMPのキャッシュサーバからコンテンツを配信することができますが、現状ではAMPのキャッシュサーバのURLは配信サーバのURLになってしまうため、これが問題視されています。

Signed Exchange はこのURLバーをコンテンツホルダーのURLに変更することが可能な技術です。コンテンツホルダーが署名し、その署名がコンテンツホルダーのものかどうかを検証することで実現されます。まだ仕様策定中の技術です。

Portals

次のページの navigation を seamless にするという話で Portals が紹介されていました。

f:id:yosuke_furukawa:20181116174216p:plain

SPA が提供するものの一つとして、部分レンダリング(header, footer等は変えず、main contents 部分のみをレンダリングする事)による、 seamless なページ遷移がありますが、これを SPA じゃなくても可能にしてしまう技術ですね。ページを先読みし、先読みしたことをイベントとして受け取ることができるのと、それを iframe のような形で表示することができます。別ページであっても部分レンダリングしてるかのように見せることができるのがすごいですね。

実際の活用例として、集英社の漫画を閲覧する機能を Portals で使った例が示されてました。

f:id:yosuke_furukawa:20181116173850p:plain

この他にも タスクの優先順序をスケジューリングすることができる、 Schedule API や Picture In Picture といった機能が紹介されており、 SPAじゃないとできなかったことが徐々にブラウザでやってくれるようになってきているなぁ と思いました。

WebPackaging と Portals を組み合わせることで「これまでサイト間やページ間で感じていたギャップを縮め、low friction から zero friction へ」という話がされていました。

f:id:yosuke_furukawa:20181116200516p:plain

インタビュー

折角の機会なので、色々な人に話を聞いてきました。Google の Paul Irish, Addy Osmani, Alex Russelと少しだけ話してきました。

Interview with Paul Irish

lighthouse などのパフォーマンスツールの開発者である Paul Irish と話してきました。

Q1. Performance Budget という話は多いが、既に React, React DOM, React Router, axios などを使っていると 60KB くらいは有り、さらにその上で moment.js などのライブラリや Polyfills が乗ってくると 300KB とかを超えてしまうが、 Paul Irish はどうしているか?

A1. 基本的にあまりライブラリは使わず、使うとしても重たくないのを選んで使うか、ブラウザの素の機能を使う。DateTime系の機能もdate-fnsにするか、もしくは intl の DateTime APIを使ってしまう。また、最近だとPolyfillsも限定的な環境 (IEとか)でしか使わないので、普段はbabelでtranspileもしない。

Q2. babelを使わないといけないのはいくつかあって、一つは JSX 、 もう一つは ES Modules なんだけど、どうしているか?

A2. 作ってるのがツール系だからあんまり使わないけど、しょうがないときは使う。

Q3. 社内で性能測定ハッカソン(ISUCONみたいなの) をやっていて、その時に headless chrome を high load performance tool として負荷かけつつ、チェックするのにも使おうと思ってるんだけど、プロセスが毎回起動するので負荷をかけるツールとしては使いにくい、もっと軽量なものを予定していないのか?

A3. あったほうが良いかも。ただやるなら Web SpeedTest みたいな感じでちゃんとしたクライアントから実行する仕組みでそれを複数台から実施する方が実際の環境には近いはず、作るのは大変かもしれないけど、作ってくれたら事例になる。

f:id:yosuke_furukawa:20181116174413p:plain

Interview with Addy Osmani

Q1. 会社の中でlighthouse をCIに使っているが、 lighthouse の点数を参考にしているだけで、他にメトリクスとして取るべき指標はあるか?

A1. JS Size, CSS size, image みたいなリソースのコストは取っておいた事例があるかも。

Q2. 事例で言うとJSはどれくらいのサイズにしている or するべきなのか?

A2. JS で言うと、 Pinterest は 200KB 以下という指標を持っている。昔は170KB以下が望ましいとされてたが、今は250KB程度までは問題ないと言われてる。 web.dev を有効活用して欲しい。

Q3. Guess.js みたいな考え方のものを使って先読みをしようと思ってるけどどう思うか?

A3. Guess.js は alpha 版だけど、あれは考え方みたいなものだし、そのまま使って欲しいと思っているわけじゃない。何か統計的な情報に基づいて先読みする仕組みは重要なのでやってみて事例にすると良さそう。

Q4. WebのフロントでPerfomanceを改善してみているが、最終的にビジネスKPIに繋がるような話にまでならないことが多い、この辺をどう考えているか。

A4. まさにそれはGoogle全体で課題だと思ってる。一方で「パフォーマンスを良くしたらビジネスKPIが上がる」というふうに短絡的に捉えるのは危険。パフォーマンスが悪ければ品質の問題になるが、良ければ必ずしも売上やユーザ数が上がるといったKPIに繋がるわけではない。いくつかのサブとなる指標を置いてやってみるのが良いと思う。

Q5. Pinterest がセッション時間が伸びて回遊時間が伸びたのを取ってたみたいな形?

A5. そのとおり。セッション時間が伸びたというのでユーザ 1人あたりが滞在する時間が増える、というのを指標にしている。

f:id:yosuke_furukawa:20181116174625p:plain

interview with Alex Russel

(帰りかけてる時にちょろっと話しただけで、全然ちゃんとは話せず・・・、また写真も取れず。)

Q1. ブログのエントリで「JS は CO2 」とか「DXはおとり商法」みたいな記事を読んだよ。あの話の中で理想とするJSのフレームワークはあるのか、または何も使わず plain なJSでやるのがいいのかはどう思ってる?

A1. JSのフレームワークは必要だと思ってる。ただブログに書いたとおりすごくtiny なもののが良いと思ってる。 preactとか svelte は理想の一つ。

まとめ

1日目は今のWebでできることを紹介しつつ、ケーススタディで非常に面白かったです。2日目は未来のWebでできることを紹介していました。どちらもワクワクする内容で、久しぶりにすごく刺激になるカンファレンスでした。

また、2日目の最後の方に Google の中で Web Performanceをやっている人たちと刺激的な話ができたのも面白かったです。来年もやるとのことですし、Google IO もあるのでまた行きたいですね!