【翻訳】Date and Times in JavaScript

この記事は littledan から依頼を受けて、翻訳しています。広く Date and Times の JS プロポーザルについて意見がほしいとのことです。 意見は以下の場所にポストできます。

docs.google.com

原文: blogs.igalia.com

tl;dr:

Temporal のプロポーザルについてフィードバックを求めています。 Polyfill を試したら、サーベイの回答を送ってください、ただしまだ本番環境では使わないでもらいたいです。

JavaScript の Date クラスは壊れています、しかし Breaking the Web を起こさずに修正する方法はありません。風のうわさでは、 Date クラスは 10 日で作られた JS Engine のhackに含まれたもので、 java.util.Date に基づいたものと言われています。しかも java.util.Date は摩訶不思議なAPIだったため、 1997 年には deprecated になっていて、今ではより良い API のものが使われています。 Java が歩んできた歴史はそのまま JavaScript も同じ歴史を辿ろうとしています。 built-in のDateクラスはとても使いにくいものとして残り続けることでしょう。

2, 3年前から、とある proposal が開発され始めました。その proposal は新しくグローバルに Temporal という JavaScript のオブジェクトを生やすものでした。 Temporal は robust で modern な API 設計で、日付、時刻、タイムスタンプを扱えるものになっています。さらに Date では不可能だったり困難だったこと下記のことが簡単にできるようになっています。

Date では不可能だったり困難だったこと:

  • Timezonesをまたいだ日付変更
  • 夏時間を考慮した上での時刻の加算、減算処理
  • 日付だけ、時刻だけでの処理
  • non-Gregorian カレンダーの時間を扱うこと

さらに Temporal は "just works (うまく動く) " なデフォルトの動作を持っていますが、コーナーケース(オーバーフロー、曖昧な時刻の解釈、などなど)に対応するために opt-in での制御ができるように設計されています。この proposal の歴史と「なぜ Date そのものを直せないか」をさらに知りたければ Maggie Pintのブログを読むことをオススメします。

maggiepint.com

Temporal の能力についていくつか例を挙げます。cookbookを見てみてください。 これらの例の多くは legacy Date クラスには困難なものが多いです。特に timezone の取り扱いに関しては Date では難しいものが多いです。 (ただし、このポストでは例を上げてますが、コードに関しては変更される可能性が大いにあります。)

この proposal は現時点では TC39 のプロセス内で Stage 2 になります。我々 Temporal Interest Group はすぐに Stage 3 に持っていこうとしてます。これまで Temporal の機能セットやAPIに関して長い間活動してきました。そしてついに、我々は 必要十分な機能が揃っており、 API の妥当性を信じる所まで来ています。もちろんホワイトボード上の議論だけで良いAPIの設計はできません。 JavaScript 開発者コミュニティに試してもらい、実際に要望を満たしているかを確認する必要があります。

まだまだ初期フェーズなので、 drastic な変更も必要になったらする可能性があります。ただしそれはフィードバックに基づいたものです。だから、どうか Temporal を試した上で我々にフィードバックを送ってください。

Temporal の試し方

カジュアルに試すのであれば、インタラクティブなpromptを使えば簡単です!ブラウザを開いて、 API ドキュメントページに行ってください。APIドキュメントもしくは cookbook のページのどこでも、ブラウザコンソールから Temporal をロードされた状態で試すことが可能です。 Example のコードを実際に実行して試すことが可能です。もしくは RunKit 上でも試すことが可能です。

もしくは、あなたは Temporal を使った小さなテストプロジェクトを構築するような踏み込んだ評価に興味があるのかもしれません。あなた方の貴重なプロジェクトの時間を奪うようなことになってしまうかもしれませんが、その方法が最も価値のあるフィードバックになるでしょう。踏み込んだ評価をしてくれることに深く感謝します! npm 上に既に Temporal API の polyfill をリリースしています。 npm install --save proposal-temporal をあなたのプロジェクトの中で実行すれば、 Temporal をあなたのプロジェクトの中に取り入れることができます (const { Temporal } = require('proposal-temporal');) 。

しかし、アプリケーションの本番環境では polyfill は使わないでください! proposal はまだ Stage 2 です。さらに polyfill は 0.x version です。それは API が変更される可能性が高いことを示しています。我々はあなたがたからのフィードバックを受けたらそれに基づいてAPIを変更し続けていこうとしています。

フィードバックの送り方

再三申し上げましたが、Temporal を使った上で、あなたからの意見を聞きたいです!一度でもトライしたら、短いサーベイに記入してください。もしよければ、あなたへのコンタクト情報を教えて下さい。教えていただければ、質問にはフォローアップして回答を差し上げます。

我々の issue tracker も気軽に開いてください! 我々はあなたがサーベイに記入したかどうかに関わらず提案を喜んで受け入れます。 issue 内に書かれたフィードバックは閲覧できます、また賛成意見には thumbs-up を送ったり、反対意見には thumbs-down を送ることもできます。

参加していただけるのであれば、謝辞を述べます。私達が受け取った全てのフィードバックは proposal を Stage 3 に上げるため、またブラウザ内で Temporal を利用できるようにするための正しい決定をするのに役に立てていきます。

番外編 (筆者が試したところ)

というわけで、 Temporal を試してみた。まずすごいと思ったのは公式が用意している cookbook が気合が入ってる。

tc39.es

9種類の大きなユースケースを紹介した上で、それぞれのサンプルコードが書かれている。

const future = Temporal.Date.from("2020-08-28")
const today = Temporal.now.date()
const days = future.difference(today).days; // 31

これだけで、日付からの差分が出せるところは嬉しい。あとは細かく、 Calendar形式で1日追加するとかの細かい操作や timezone の変更などの操作が直感的にできる。 <input type=date> な field にも直接入れることができたりと細かいニーズに対応できている。さすが次世代 Date といったところか。

const datePicker = document.getElementById('calendar-input'); // カレンダーのDate Picker
const today = Temporal.now.date(); 
datePicker.max = today; // 現在日付をmaxにして、過去の日付しか選べないようにする。
datePicker.value = today;

若干使いにくそうだな、と思った所も上げる。

使いにくいと思った所その1, epochtime を取る所

// epochsecond を取る時は Date.now() / 1000 だったが、今回からはこうなる。
const now = Temporal.now.absolute();
now.getEpochSeconds();

まず、長い。長いけどAPIはわかりやすい。一方で手軽さがないので、 Date.now() / 1000 を手癖で覚えてるとそっち使ってしまいそう。ただDate.now()/1000 と比較すると、小数点のケアをしなくていいので、楽。これからは Temporal の方法を覚えていきたい。

一方で absolute instance を一度作ってしまうと次から getEpochSeconds() を呼び出しても同じ値になってしまう。一回はこれ絡みの不具合が起きそうな気がする。

const now = Temporal.now.absolute();
setInterval(() => {
  console.log(now.getEpochSeconds()); // 毎回同じ数
}, 1000);

最新の値を更新したければ毎回 absolute から取るしか無さそう。

setInterval(() => {
  const now = Temporal.now.absolute();
  console.log(now.getEpochSeconds()); // 毎回違う数
}, 1000);

epoch seconds を取るときはロギングする時とかが多い気がするが、それを毎回 Temporal instance を作っては捨てるようなことしてもパフォーマンス的に問題ないのかとかは一瞬気になったが、実装次第だろう。個人的にはinstanceを作らなくても epochtime くらいならサクッと取れるようにしてほしい。 Temporal.getEpochSeconds() のように。

Temporal.xxx.from でパースできない文字列を食わせると例外がthrowされる。

from 関数は本当に便利。日付だけで扱いたければ Temporal.Date.from(2020-01-01) で日付のみの Temporal instance を作ってくれる。また、時刻だけで扱いたければ Temporal.Time.from("12:10") で 12時10分 のTimeにしてくれる。また、 日付のオブジェクトを渡せばそれに合わせて instance を作ってくれる。

ただし、 ISODate 形式(YYYY-MM-DDTHH:mm)に反する文字列だと例外が throw される。また、ありえない日付(13月32日のような)ものを食わせると、object形式とstring形式で動きが異なる。

Temporal.DateTime.from("2019-12-10T12:10") // from 関数は文字列を parse して Temporal instance にしてくれる。便利。
Temporal.DateTime.from({ year: 2019, month: 12, day: 1 }) // こっちもわかりやすい、object としてpropertyつけて渡せば良い。
Temporal.DateTime.from("2019-12-10a12:10") // もしも invalid な文字列だと RangeError: invalid ISO 8601 string: 2019-12-10a12:10
Temporal.DateTime.from("2019-13-32T12:10") // 文字列にありえない月や日が入ってても RangeError がthrowされる。
Temporal.DateTime.from({ year: 2019, month: 13, day: 32 }) // object で渡したときは throw されない、 2019-12-31 などの一番近い日付に補正される。
Temporal.DateTime.from({ year: 2019, month: 13, day: 32 }, {disambiguation: "reject"}) // disambiguation を reject にすれば RangeError が throw される。

ここは、若干動きがわかりにくいかも。。。文字列で渡したときは disambiguation が必ず "reject" のようになるが、object で渡したときは disambiguation が "constrain" になる。 polyfill の問題かな。

ちなみに、これまでの Date だと invalid Date という number で言う NaN のような扱いになっており、例外は throw されなかった。

new Date("2012-12-11T12:20") // 2012-12-11T03:20:00.000Z
new Date("2012-12-11a12:20") // Invalid Date

どっちが良いかは諸説あると思うが、いままで手軽に扱っていた Date のマインドセットのままでは使えない。ちなみに moment とかも同様にパースできなくても例外を投げたりしない、 NaN 扱いになる。パースできない時に NaN 扱いだった Date ときちんと例外を処理しないといけない Temporal のどちらが良いかは筆者には判断付かないが、 JavaScript はこれまでの歴史上、例外の取り扱いが難しいので、この辺の議論は是非参加してみたい。

まだまだありそうだけど、翻訳を先に出したかったので、ここまで。後は読者の方々も試してみてほしいです。試してみたら、サーベイに回答しましょう。

web.dev live 2020 を聴講した

今年はコロナの影響でいろんなイベントがオンラインになったり、中止になったりしてますが、 web.dev live 2020 が7月初頭にやっていたので、聴講してきました。

web.dev

その中でも面白かったものについていくつか紹介します。

Day 1

ほぼ Core Web Vitals についての話でした。

以下のトークが面白かったです。

  • What's new in speed tooling
  • Optimize for Core Web Vitals

Core Web Vitals についてはもう既にたくさん資料があると思いますが、一応解説しておきます。

Core Web Vitals

初期表示の新しい指標です。去年くらいからずっと Chrome Dev Summit とかでは言われていて、既にLighthouse をはじめとして、色々なツールでサポートされています。Largest Contentful Paint(初期表示範囲内で一番面積の大きいコンテンツが描画されるまでの時間), First Input Delay(最初に入力可能になるまでの時間), Cumulative Layout Shift (初期表示された後にレイアウトがずれた時のズレ幅)の3つを指標としています。

web.dev

Core Web Vitals 指標
Core Web Vitals 指標

一日目はこの指標の説明とどうやったら良くなるかが非常にたくさん描かれていました。

What's new in speed tooling

www.youtube.com

じゃあ Core Web Vitals はいいとして、『どうやってツールを使ってそれらを把握していくのが良いのか?』というのが語られてました。

ほとんどのツールでもう既にCWVは取れる

上記画像の通り、基本的にはどんなツールでも Core Web Vitals は取得できます。一方で、それぞれ特徴があるので、使い分け方についても解説します。

  • 本番環境では Search Console で警告が来るのでそれのレポートを見て、
  • Page Speed Insights で問題を深掘って発見し、
  • Lighthouse/DevTools でローカルの高速化をはかり、
  • web.devのガイダンスを読み
  • Lighthouse CI でレグレッションを防ぎ、
  • Chrome User Experience Report でフィールドデータも確認する

という流れを継続してやるのが CWV のやり方と流れです。

どうやって改善するか

便利だな、と思ったのは、 Dev Tools 上で Cumulative Layout Shift 違反が起きている箇所を特定できるところですね。これがあれば、CLS違反になっている箇所をどうやって修正するかを確認できるので、便利そうでした。

DevTools 上でCLS違反が起きてる箇所がわかる。

また、2020年までは上述した threshold にするものの、一年おきに水準や方法は見直していくという事でした。

Core Web Vitals 2021
Core Web Vitals 2021

Optimize for Core Web Vitals

www.youtube.com

具体的にどうやって Core Web Vitals を上げていくかというテクニックめいた話でした。 実際に Chloe というファッションブランドのサイトを Core Web Vitals に基づき改善していった話をしてました。

CLS の改善

先程の説明の通り、 Cumulative Layout Shift (CLS) は初期表示の後にレイアウトが変わってしまう問題です。馴染みやすい問題として、「ガタンッ」問題 とも呼ばれているものです。ロード前のコンテンツがロードされることで高さが変わったり、幅が変わることでレイアウトが変わってしまう現象を指しています。

見た目にも悪いですし、何より押そうとしたらレイアウトがずれてリンクが押せなくなったりと実害が出る問題です。 このガタンッ問題をどうやって防ぐかという話を解説してくれていました。

最初に画像に関しては width, height を img タグに設定しておき、後から高さや幅が変わらないようにしておきます。 もしもできるなら、画像の背景色に合わせた類似色を表示エリアに事前に表示することも推奨されていました。

Chloe の例

背景色を画像に合わせて塗っておくことで、画像が表示される前であっても見た目やレイアウトが損なわれません。

また、後からコンテンツを表示された領域に挿入することは基本NGです。しかし、広告やプロモーション等でどうしても後から入るケースも考えられます。その時も高さに関しては事前に領域を確保しておきましょう。

広告の入る領域を事前に確保しておく

LCP の改善

Largest Contentful Paint は先程の説明の通り、『初期表示領域における、最大面積を持つコンテンツのロードにかかる時間』を指すのですが、対象は所謂ヒーローイメージであることが多いので、画像のチューニングが紹介されてました。

基本的に画像はCDNを利用し、webpをデフォルトで使ってほしい点、また本質的に必要なサイズの画像しか用意しない事で画像のサイズをカリカリに縮小した状態で表示させることで初期表示の改善に取り組んでいきました。

ヒーローイメージのチューニング

また、Server Push を使った改善も取り組んだことを紹介していました。 Naive な Server Push 自体は Cache Aware ではないため、 HTTP/2 の Server Push をそのまま活用したわけではなく、 Akamai の Server Push を使ってインテリジェントな Push を実現したという解説がされていました。

blogs.akamai.com

結果として大幅な LCP の改善ができたことを紹介していました。

Server Push Impact

Day 2

ほぼ PWA の話でしたが、筆者が興味を持ったのは以下の2つでした。

  • What’s new in V8
  • Zoom on Web

What's new in V8

www.youtube.com

ほぼほぼ知ってる話でしたが、一応 recap しておきます。

ES 新機能

  • Nullish Coalescing
  • Optional Chaining
  • WeakRef

が追加されました。

Optional Chaining

Nullish Coalescing

WeakRef

それぞれ説明するまでもないかな、と思ったので解説は割愛します。WeakRefのユースケースをイベントリスナーの廃棄に使うっていうケースが紹介されてて、そこだけ面白かったです。

Memory Improvements

メモリの消費量を抑える新しい仕組みについて 2 点解説されていました。

  • Pointer Compression
  • JIT-less mode (V8 Lite)

Pointer Compression

イデア自体は凄くシンプルで、64bit アドレスでメモリアロケート先のポインターを持つのではなく、base address は64bitのアドレスにしつつ、そこからのoffsetを32bitアドレスで持つことで全体的にアドレスの管理をするメモリの消費量を減らすというものです。

Pointer Compression

内容自体は凄くシンプルですが、結果としては、平均で40%程度削減されている結果が見込めるという事でした。

Pointer Compression memory reduction

JIT less mode

V8 は多くのメモリ確保をしていますが、その内訳を見ると、JITに必要なメモリが含まれていることがわかります。

v8 memory の内訳

JIT の機能をオフにしてしまえば、いくつかのメモリを持たなくて済むため、メモリ消費量を抑えることができます。

JIT less memory

まだこれは試験的な機能ですが、JIT less にすることでメモリ消費量は10-25%程度の削減が見込めるということでした。

jit-less result

Zoom on Web

www.youtube.com

Zoom の動画チャット機能を Web で提供するため、 Chrome と Zoom で組んで色々な機能のリリースやトライアルをやっているという話でした。

WebAssembly on SIMD, WebTransport, WebCodec の3つの技術を紹介し、それぞれを組み合わせていく話が紹介されていました。

WebTransport は UDP レイヤでのデータ通信を実現し、それを使って動画を転送しつつ、WebCodec で動画のデコードとエンコードを行い描画を行い、 WebAssembly SIMD を使って背景の透過などの動画エフェクトを掛けるという紹介がされていました。

wasm simd

Day 3

Privacy Sandbox セキュリティ 周りの話がほとんどでした。

www.chromium.org

そこまで目新しい話はありませんでしたが、 COOP, COEP の話は抑えておいて良いと思います。

また、 Signin Form Best Practice の話は割と面白かったです。

Cross Origin Opener Policy, Cross Origin Embedder Policy

www.youtube.com

Cross Origin 、つまりクロスドメインにおいて、オリジンの情報をいかに守るか、という話です。

Cross Origin Opener Policy

COOP は通常 window.opener から開き元になる origin の DOM が参照変更できることを避け、 window.opener がただの null になります。

COEP は Cross Origin Resource Policy が設定されていないリソースの読み込みをさせないようにリソースの読み込みポリシーを見て表示可否を制御できるポリシーです。

設定すると許可されていないリソースの読み込みをblockさせることができます。

COEP

Signin form best practice

www.youtube.com

おそらく Web エンジニアが幾度となく作ってきた サインインフォームについての話でした。

web.dev

  • 意味のあるHTMLを使って div とかだけで表現するな。
  • button は button として使うこと、 button を "送信" みたいなボタンにせず、 "Sign-in" などの意味のあるラベルを用意すること
  • 登録用パスワードを2個書かせたり、登録用メールアドレスを2つ書かせるような double up form にするな
  • autofocus を使ってどっから書くか明確にせよ
  • password の type は使うが、見たい時にはマスクが外れるようにせよ
  • input type は email や tel など入力フォームに合わせてちゃんと設定せよ
  • inputmode の利用も考慮すること
  • Sign in button が入力キーボードで見えなくなることを避けよ(押せなくなるから)

sign in ボタンがかぶってる例

  • Sign up のときやパスワード再入力時に name を new-password や current-password でわけて表現すること

などなど、ものすごくたくさん紹介されていた。

password のマスクを外すときは typeをtextにしつつ、aria labelもちゃんと変更する例

Recap

「Web Vitals で初期表示の改善の話がされ、 V8 や WASM の話でアプリケーションの能力を広げ、 Privacy をきちんと保護する」というなんとなく全体的に今推してる機能がわかる話だった。

2020年の JSConf.jp は中止にします

表題の通り、 2020年の JSConf.jp は中止にします。2021年の開催を目指します。

TC39とのコラボレーションとかも検討していたのですが、楽しみにしていた方々、大変申し訳ございません。

いろいろな葛藤はありましたが、 JSConf.jp の前身になった Node 学園祭のときから「豪華なスピーカーに会えること」「Node.jsやTC39の中にいる人と直接交流できること」「知見が共有できる場所」というのを大事にしてきたのですが、オンライン開催ではその意味が半分以上失われてしまうと思っており、 JSConf.jp は開催しません。

ただし、少し形を変えて、オンラインで開催する小さなカンファレンスは開催するかもしれません(名前は TBD です、 JSHome とかにするかも?)。

よろしくおねがいいたします。

2019年振り返り

はじめに

なんかよく見たら 2年前の自分がちゃんと書いてるくせに 1年前の自分は書いてなくて、進化してるのか退化してるのかわからなかったので、今年からはちゃんと書こうと思いました。

yosuke-furukawa.hatenablog.com

会社

マネジメント

マネージャーも3年目ですね。なんだかんだ、メンバーにも恵まれてるなと思うことが多いです。 メンバーがアウトプットを率先してやってるので、エンジニアコミュニティとして大きく形成されているなと思います。エキスパート同士が互いを教え合い、また競い合いながら目的を達成していくのは見てて気持ちが良いです。

2019年振り返り.md · GitHub

engineer.recruit-lifestyle.co.jp

qiita.com

recruit-tech.co.jp

qiita.com

recruit-tech.co.jp

背中を黙って預けておけるメンバーなので、特にマネジメントの仕事と言ってもキャリアの相談や仕事の相談に乗って一緒に考えることはしてますが、やってることはその程度といえばその程度で、細かい事は任せてます。「『お前はどうしたいんだ』ってよく言うのか」、と聞かれますが、「メンバーがどうなりたいか」と「メンバーにどうなっててほしいか」というwill と期待の話はよくします。逆に言うと日々のマネジメントはそれくらいしかしてないです。

R-ISUCON で 1 位に

エンジニアコミュニティといえば社内でやってるイベントの R-ISUCON で 1位取ったりしました。

recruit-tech.co.jp

嬉しかったのは R-ISUCON やってたら ISUCON の予選を3位で通過したことです。自分が通過したことももちろん嬉しかったのですが、 R-ISUCON をやっていた他のグループも通過していてレベルが上ってることを感じました。

yosuke-furukawa.hatenablog.com

関連会社の技術顧問になった

ニジボックスという弊社の関連会社の技術顧問も新規でやることにしました。

会社の技術的な質を上げるには、技術部分の底上げをすることとトップレベルを引き上げることの2つが重要だと思っています。

トップレベルを引き上げることは自組織のマネジメントで行っていますが、縁あって底上げをする役目も一緒に行うことになりました。といってもまだ10月からなったばかりなので、 JavaScript の研修を教えたり、そもそもコードを書く時に意識することを教えたりといった基礎的な所と意識的な所を教えています。

qiita.com

Chrome Advisory Board になった

Chrome にアドバイスする諮問委員会、 Chrome Advisory Board のメンバーになりました(正確には2018年から)。現時点では日本に 3 人の諮問委員会メンバーがいて、リクルートの他だと Yahoo!Cyber Agent のメンバーがいます。活動としてはいち早く新しい Chrome の仕様を教えてもらって試して、使った結果をフィードバックするというのが主な仕事です。

AMP をやったり、 Next.js 使ったりしてるのはその辺があります。 Next.js に最近送った PR も AMP 系ですね。

github.com

そんな使い方があるのかーという、仕様の勉強にもなります。 Google のAMPの中の人達にこの手の活動を通じて気軽に質問できるようになったのは大きいですね。

この他にも Paul Irish に気軽に lighthouse の中身を聞いたり、実際にサービスを見てアドバイスもらったりできて良かったです。

Japan Node.js Association の活動

会社でやったこと以外にも自分が持ってる法人の活動も書いておきます。

JSConf.JP 開催

今年はなんといっても JSConf.JP 開催できたのが大きいです。

yosuke-furukawa.hatenablog.com

今年の前半からずっと JSConf をやってたし、日本で JSConf が開催できたのは日本の JavaScript コミュニティ全体にとって良かったと思います。トークの内容もJSコミュニティを代表するにふさわしい内容だったと自負しています。

ただこれまで JSConf EU とかで登壇依頼してたのですが、来年はやらないので新しい場所に行く必要があるかも。。

あと、来年はなんと言ってもオリンピックがあるので、前回みたいな外部の会場を抑えるのは難しいかもしれませんね。。。 今7, 8, 9月にやる予定だったイベントが軒並み9月後半、10月、11月にずれてきてるという話なので、会場の検索中です。

ただ間違いなく2020年も JSConf はやります。

個人活動

会社、自分の法人以外の活動も書いておきます。

登壇系

技術的な登壇はもとより、マネージャーや組織づくり系の登壇、エンジニアキャリア的な登壇に呼ばれましたね。

この辺に呼ばれた(自分が話した)感じですね。自分の中で新しいなと思ったのは Global CFP Day と EOF 2019 ですね。

Global CFP Day は「海外登壇にチャレンジするにはどうしたらいいか」、というテーマでめっちゃ面白いカンファレンスでした。

f:id:yosuke_furukawa:20191231193941p:plain
Global CFP Day

このカンファレンスで紹介された「Present! A Techie's Guide to Public Speaking」という本は 海外カンファレンスのテックトークとはどういうものなのかを紹介した本です。かなり面白いのでマジでおすすめです。

www.amazon.com

EOF 2019 は自分がマネジメントでやってたことをちゃんと言語化した形になりました。

あまりちゃんとした形で表明してなったけど、自分は勉強会と同じ考え方でマネジメントしてるんだなという発見になりました。

執筆系

以下の場所に記事を寄稿しました。

gihyo.jp

マイクロサービスのつなげ方の章で BFF の話を解説させていただきました。 また、 CodeGrid は Node.js v12 - v13 で変わることの話をさせていただきました。

www.codegrid.net

www.codegrid.net

後半のマジで忙しい時に2連続で執筆依頼が来たのですが、これを断っていたら今回執筆ゼロだったので受けてよかったです。

OSS

最近ちゃんとコードも書いていこうという精神で、 Write Code Everyday に挑戦しています。まだ4ヶ月が終わろうとしてるところですね。マネージャーになったけど、コード書いていないっていうのは嫌だったので、コードも書くし、マネジメントもやるし、っていう精神でやっています。

f:id:yosuke_furukawa:20191231195047p:plain
Write Code Everyday 挑戦中

OSS で言うとリクルートのライブラリで、 Specter を作ったりしていました。

github.com

yosuke-furukawa.hatenablog.com

結構中身がわかってきたし、不具合も見えてきたので、 Next.js へのコントリビューションをもう少し本格的にやろうと思います。

github.com

Node.js core contributor としては活動が少し落ち着いてしまったので、もう少し復活させようと思います。

Podcast

fukabori.fm に出させていただきました。結構この活動がきっかけで周辺会社とも絡む機会を増やせると良いなと思っています。内容は社内ISUCONですが、かなりエンジニアコミュニティづくりに寄った話が多かった気がします。

fukabori.fm

Blog

この辺が盛り上がった気がしますね。もっと書きます。。。

yosuke-furukawa.hatenablog.com

yosuke-furukawa.hatenablog.com

来年に向けて

明らかにブログが減ってしまっているのでまずはペースを2017年に戻したいのと、2017年は海外登壇も多くやっていたので、それも復活したいです。 Node.js は QUIC や ES Modules を起点にまたコントリビューションできる所見つけてやっていきます。

そろそろ新しい言語をまた覚え直すとかやりたいし、その一方で他の人達が新しいチャレンジしてるのも見てて面白そうだなと思うので、好奇心を原動力に2020年もまたがんばります。

実践 Off the main thread

実践 Off the main thread

実際に Off the main thread をやりつつ、パフォーマンスチューニングをする際にどこに気をつけるべきかを今やっているので、それについて話します。

Off the main thread とは

JavaScript の処理は基本的にメインスレッドで実施します。JavaScriptの実行処理以外にも記述された内容を解釈するためのパース処理やGC処理もメインスレッドをブロックします。メインスレッドの処理が多いとUI jankと呼ばれるガタツキ、チラツキ、画面の固まりの原因になります。

UI jankが発生していると、ユーザーがクリックしたり、text入力をしようとしてから反応するまでの時間(Input Latency)が即時ではなくなります

このUI jankを無くすために、なるべくメインスレッドを阻害する要因を減らすことが Off the main thread と呼ばれるトピックです。

Input Latency

ユーザが入力してから反応するまでの時間を指しています。 Off the main thread は前述の通り、このInput Latencyを少なくするための試みです。 メインスレッドでLong Taskを実行している間、特にレンダリングなどの重たい処理を実行している間は入力があっても即座に反応しません。

f:id:yosuke_furukawa:20190319025141p:plain
Long Task実行中に入力処理があった場合

この場合、inputの処理はキューイングされ、後回しになります。

f:id:yosuke_furukawa:20190319025356p:plain
入力されてから実際に発火して反応があるまでの時間

このレイテンシを最小限にしつつ、スムーズに動作しているように見せないと、固まっているかのように見えます。

「どれくらいで固まっているように見えるか」ですが、Google が出している、RAIL と呼ばれる原則では、100ms 以内に反応がないと、ユーザーは遅れているように見えるという指標があり、少なくともそれを満たす必要があります。 ただし、 lighthouse では 50ms 以内にしないと警告が出ます(アプリが表示し切るまでにさらに 50ms かかると推定されており、トータルで 100ms が Input に対しての Response になるため)。つまり、 Input Latency は表示し始めてから 50ms 、 入力が始まってから 100ms 以内に反応する必要があります。

developers.google.com

developers.google.com

何が Input Latency の遅延原因になっているか

Input Latency の遅延原因となっているのは主に JavaScript の実行だというレポート結果があります。

tdresser.github.io

f:id:yosuke_furukawa:20190319030621p:plain
input latencyの中で処理の内訳

2300以上のサイトを調査し、最初の30秒間に入力処理をした際の処理の内訳を精査したところ、V8.Execute という JavaScript 実行中の処理で25% ~ 70%の時間が発生しています。

これを Web Worker など、 Worker Thread で行えるようにし、 Input Latency を改善するというのが Chrome での topic の1つです。ただし、実際にやってみると、それ以前の問題が多く、実際にやればやるほど「Worker 以前に処理するべき問題」のが多く見つかります。

Worker 以前に処理するべき問題を放置して Worker Thread にしても Input Latency は改善できても処理そのものが重たいので、結局もっさりした動きになります。

実践 Off the main thread

今回の話はこの input latency を改善するため、 UI Jank をどうやって見つけるかとそれを改善するときのやり方、また実際にReact などの SPA を改善する時に見つけたありがちな問題について解説します。

UI Jank の見つけ方

Chrome だと DevTools の Performance タブから比較的簡単に見つけられます。 Performance タブで赤くなっている箇所では、 Jank が起きています。

UI Jank
UI Jank

この Jank を見つけたら、そこから中で何をやっているか見つけに行きます。この JSConf.JP のサイトでは hydration 処理と呼ばれる SSRCSR の状態を同期する処理で Jank が起きています。

Hydration処理
Hydration処理

このケースで言うと、 Hydration と呼ばれる SSRCSR の同期処理が走った後、React の props が変わり、 React の render 処理が中で走っています。結果として hydration 後に render が走ることで React の state が SSR 時のものと同期されることになります。一方で、 Input Latency は落ちる事になります。

ただし、『 UI Jank がある == 不具合』ではないので、これを必ずしも直さないといけないわけではありません。現時点ではどうしようもない処理もあります。 Hydration はその典型です。

よくある Jank のパターン

この hydration 以外にも発生するケーススタディがありますので紹介しておきます。

スクロールごとに重たい計算をしてしまうパターン

スクロールするたびにガタつくケースはだいたいコレですね。よくあるのは、スクロールしたタイミングで要素を変更する lazyload や 無限スクロールのような処理があるケースで、実装がまずいパターンです。

実装がまずい、と一口に書きましたが、「重たいオブジェクトを毎回生成する」、「scrollのたびに現在のviewportに要素が入っているかを毎回計算する」といった処理を指しています。

前者はオブジェクトのキャッシュかインスタンス生成を減らす事を検討し、後者は Intersection Observer などの API で再実装が求められます。 また、 scroll イベントを毎回発生させる必要がないなら、 throttle, debounce といったイベントを間引くことで処理そのものが発生する回数を減らすことができます。

ちなみにスクロールに限らず、『頻度高く発生するイベントをトリガーに重たい処理をしている』事がそもそも問題になります。

他のケースとしては、 moment のような時刻計算をするためのオブジェクトを表示されるたびに計算し、その計算のたびにインスタンスを作ってから時間の差分を計算しているケースもありました。

不要な props を渡してしまうパターン

ここからは主に React の話ですが、React に限らず、 SPA の view libraryではよく発生すると思います。

<Foo {...props} />

のように prop を全て展開して渡しているパターンや、 実際には使わないけど渡しているパターンですね。Reactの SPA の場合、UI Jank の8割方はこれです。この不要な props を渡しているところのバリエーションが多いです。

不要に Reconciliation といった差分検出処理が走ったり、 render が走ってしまい、 Jank が発生しやすくなります。

shouldComponentUpdate を書いて除外するか、きちんと渡す時に精査してから渡してあげれば発生しません。また、型を真面目に書いていればある程度防げたりもするでしょう。

関数をそのまま handler に渡してしまうパターン

こちらもよく見ます。以下のような状況ですね。

<Foo onClick={(e) => { ... }} />

これも、ある種の不要な props なのですが、趣が若干異なります。アロー関数に限らず、関数をその場で定義した場合、propsを渡す際に毎回 function オブジェクトが生成されて React に渡されます。こうなると関数オブジェクトそのものが毎回変わっているため、差分検出処理時に必ず差分がある事になります。

useCallback 等で callback をmemo化した状態で渡すか、 class componentにするなら、関数定義を constructor で定義するか static 関数にするかして、関数を再定義しない方法で handler に渡す必要があります。

どうにもならないときの処理として Worker を使う

処理をダイエットしたけど、どうしても減らない、とにかく重い計算処理を走らせる必要がある、という時に Worker を使いましょう。 Worker は Comlink 経由で使うと利用しやすいです。

実際に利用したときのシーンは AirSHIFT のブログに掲載されています。

web.dev

// Cost計算する処理、 worker を comlink で promisified している。
import React from 'react';
import { proxy } from 'comlink';
 
// import the workerlized calc function with comlink
const WorkerlizedCostCalc = proxy(new Worker('./WorkerlizedCostCalc.js'));
export default function Cost({ userInfo }) {
  // execute the calculation in the worker
  const instance = await new WorkerlizedCostCalc();
  const cost = await instance.calc(userInfo);
  return <p>{cost}</p>;
}

ただ Worker にしただけで速くなるわけではありません。 Worker にすることで Main Thread を逼迫することは減りますが、そもそも無駄な処理がないかを地道に特定し、逼迫する時間を減らすことが一番重要です。

まとめ

Off the main thread だからといって、なんでも worker でやれば OK という話ではありません。自分のアプリ、サイトが遅い要因を特定し、ある程度性能を改善してからどうしようもない時に Worker を使いましょう。そうすると Input Latency だけではなく、処理全体が軽くなります。

Worker は速くなると言っても、 Main Thread の逼迫を軽減するためのものであり、使ったからといって手放しで高速になるわけではありません。一方で、使いこなせれば非常に強力な武器になります。 Comlink などのツールは使いこなせると良いでしょう。

また、仕様側でもよりよい API 設計を考えている話が去年から出ています。この辺も追っておくと良いでしょう。

nhiroki.jp

また、 『UI Jank』の原因は JavaScript のメインスレッド逼迫だけではありません。 CSS や Layout 計算などの要因でも数多く発生します。

Jank の原因をまとめたサイトやチェックリスト等もあるので参考にしてください。

calendar.perfplanet.com

docs.google.com

jankfree.org

2020年の Node.js, 2025年の Node.js (Web Standard編)

この記事は Node.js Advent Calendar の 25 日目の記事です。

qiita.com

Node.js の 2020 年はどうなるのか 2025 年にはどうなっているのかを予想していこうと思います。 ちなみに、あくまで筆者の予想にすぎないです。こうなるという与太話みたいなものだと思っていてください。

Node.js のこれまでと今後

Node.js は進化を続けていますが、 2018 年に語った通り、その進化の方向は以下のような方向に流れています。

  • Web Standard
  • Performance
  • Security
  • Stability

speakerdeck.com

今回は主に Web Standard の部分に限定して、これまでとこれからと更にその先を予測してみようと思います。

Web Standard 2020 / 2025

Node.jsは Web Standard に追従するという旨の発信はずっとしています。全ての Web Standard を follow するといっても実際サーバサイドには不要なものもあります。取捨選択をしながらなるべく追従をしていくという形になるでしょう。

ES Modules

ES Modules が Node.js v13.2.0 より、 ES Modules が experimental フラグが取れ experimental オプション無しで動きます(ただし、API status は experimental のまま)。相互運用性の方法もほぼ確定になりました。 Node の ES Modules 対応は 2020 年から徐々にその割合を伸ばし、 2025 年には利用されているモジュールが ES Modules : CommonJS が 3 : 7位の比率になる と予想します。 徐々に .mjsesm に対応してほしいみたいな issue 増えてきましたね。

github.com

github.com

github.com

100% のモジュールが ES Modules になることは考えにくいですが、新しいモジュールや使われてるモジュールを始めとして、徐々に対応するような段階的にアップデートが行われるのではないかと思っています。詳しくは以下のエントリに書いたので詳細をご確認ください。

yosuke-furukawa.hatenablog.com

QUIC

QUIC の initial implementation の PR が作られました。

github.com

まだ ngtcp2 を持ってきて binding を作った段階で、 http3 の実装などは現時点ではまだです。 Node.js の QUIC 及び、 HTTP3 の対応は 2020 年で初期実装が完遂し、experimental 付きでリリース、 2025 年には quic, http3 ともに experimental flag が取れる と予測します。

一方で http2 はどうなるんでしょうね。クライアントとしては生き残る気がしつつも、毎回クライアント側で http1.1, http2, http3 を呼びわけたくないので、統一的なAPIからコールされるようにならないと厳しいですね。

fetch

http1.1, http2, http3 のクライアント側の話で言うと、それらを統一的に呼び分けるために fetch を入れようという話もあります。今だと require('http')require('http2') のようにロードするモジュールから分ける必要があります。

github.com

このPRはただの既存の npm にある node-fetch を core に入れてみようとしただけの議論用のPRですが、 ES Modules のような大物が終わった後は fetch の実装を進めるのかなと予測しています。

2020年には、、、議論は進んで fetch working group ができる、 2025年には http3 とともに fetch も入る と予測します。

Streams

fetch とくると、気になるのは Stream ですよね。 WHATWG Stream と既存 Stream は違うものなので別物として実装はされると思いますが、今の所進捗が見えません。リポジトリはあります。ただ議論が止まってますね。

github.com

新しくモチベーションがある人が引き継ぐ必要がありそうな気もします。 fetch の議論を進めていく上で一緒に進んでほしいと思います。やる気があったら実装してみます。

ただこうなると、Joyee が書いたこのスライドにもありますが、 fetch の完璧に compatible な実装を用意は難しいですね。また、 Browser API と完璧に同じにする必要も無いので、 Node.js なりに互換はあるが微妙に別物な fetch になりそうですね。

2020年はわかりません、おそらく今の感じだと進捗はないでしょう fetch working group ができたらそこで議論再開ではないでしょうか。2025年には一旦 WHATWG Stream 無しで実装が進んでリリースされてそうだと予測します。

ちなみに Stream ですが、 新しく BoB Stream という提案がされています。これは今までの Push と Pull 型の混在した Stream ではなく、完全に新しい API で再検討された Pull 型の Stream です。

github.com

WHATWG Stream のものとはAPIも概念も異なります。こっちのが議論は進んでいるので入るのは WHATWG Stream よりは早そうですね。 2025 年には決着付いてるでしょう。

Web Assembly

Web Assembly 対応は v8 中心に進んでいる上に、 WASI 対応も v13.3.0 で experimental flag 付きでリリースされました。

github.com

つまり、 Web Assembly 対応したモジュールを読み込むことができるのはもちろん、 WASI に対応した形でFile, Network IOを行うモジュールも使えるようになります。

ただまだまだ大本の WASM, WASI の仕様が unstable なのでどう転ぶかはわかりません。筆者がそこまで追いきれてない領域です。 2020年には徐々に今の native module が wasm/wasi を使って書かれるようになってくると予測します。ただ、大本の団体がまだ安定版を作れていないので、2025年でもまだ experimental なままな気がしてます。

先日公開された TensorFlow.js が wasm を backend にするというニュースが流れてきて、徐々にモジュールのレイヤでは使われ始めてるという実感を感じます。

github.com

その他 Web Platform API はどうなるのか

crypto は Web Crypto を Node.js API に採用する議論は進められています。

github.com

cryptoWeb Crypto も別物です。 Promise をベースとした Web Crypto でこちらはユーザーの API の利便性を考えられているものの、既存の crypto は性能をベースに考えられているので趣きが若干異なりますね。今の tls モジュールが Web Crypto をベースに変わるとかはちょっと想像ができません。こちらももう少し議論が進めば入る可能性はあります。 2020 年には決着がつきそうですね。入るかどうかは判断が難しいですが、2020年に experimental リリースされそうな気はします。

一方で、 WebTransport, Web Codec等の対応はまだ議論すらされていません。ちなみにWebSocketsも core に入れるかどうかは忘れられてる気もします。。。

Web Platform の API を入れるかどうかは、「ユースケースが Node.js にとって妥当かどうか」、「ユーザーランドで実装が困難かどうか」、「既存の API との整合性」で決まるので、それぞれの判断をする議論が無い限り話は進みません。

まとめ

  • ES Modules は 2020 年には増え続けて、 2025年には ESM : CJS で 3 : 7 程度の比率になる
  • QUIC は来年 experimental でリリース (v14) HTTP3 はそこから議論が始まって RFC がでたら2025年にはリリースされてる
  • fetch は来年一旦 working group ができる、2025年にはリリースされてる
  • stream は多分来年も何も進まないが、 fetch working group で一緒に議論はされる、 2025 年には一旦 whatwg stream 無しでリリースされる
  • WASM は既に初期リリースはされているので後は仕様側が安定したら徐々に進むはず、ただまだ仕様が unstable なままだと experimental flag は取れない。2025年にもまだ experimental な気がする。
  • その他: Web Crypto が入りそう、ほかはまだまだ、ユースケースから募集中。

書いてて思いましたが、 2025 年って v24 とかですね。。。こう書くと全然予測ができない気もしてきました。やっぱり予測するものではなく、自分たちで予測を超えていく動きをしたいですね。

来年も Node.js に JSConf にがんばります。

Universal Data Fetch ライブラリ、 Specter の紹介

この記事は Recruit Engineers Advent Calendar 2019 の 16日目の記事です。

adventar.org

最近僕が作っている OSS である Specter の話をします。

github.com

Specter とは

Client から Backend と BFF から Backend への Universal なデータフェッチを提供してくれるためのツールです。以下の特徴を持ちます。

  • 軽量
  • TypeScript Freindly な型付け機能
  • 投機的先読み

2年ほど前に報告されたCPUの投機的実行に基づく脆弱性である、 Spectre から来ています。と言っても、脆弱性の名前ではありません。投機的先読みを機能として持っているため、この名前をつけています(不吉な名前ではありますが・・・)。

まずは、 GraphQL でも grpc-web でもなく、なぜこいつが産まれたのか、その背景から説明します。

背景

リクルートでも GraphQL を使うケースは徐々に見え始めていますが、まだまだ少数派です。よくあるケースは REST-ish な API サーバがすでに Backend に存在し、それを基に BFF レイヤから API Aggregation をするようなケースです。

f:id:yosuke_furukawa:20191216002138p:plain
BFF が Backend API を Aggregation するケース

Specter 以前はこの部分に Fetchr と呼ばれる OSS を使っていました。しかしながら、 Fetchr は TypeScript などの昨今のフロントエンドのトレンドにマッチしておらず、 非同期呼び出しも callback API を中心として Promise 化されたラッパーが存在する程度でした(そこに以前は 不具合があり、一撃 DoS を直したり してました)。

次の候補として、 Client と BFF 間の通信で、 GraphQL を使うという話もありましたが、最近は AMP で amp-list を使うなど、 Response の戻り値の型が決まっているようなケースも有り、諸々のユースケースに対応するため、独自で開発するに至ったという経緯です。今回は特徴を解説しつつ、なぜこのような設計なのかの Why について解説します。 最後に How についても少しだけ解説します。

軽量

Specter 自身のファイルサイズは BundlePhobia によると、 minify, gzip 付きで 2.2kB 程度です。

bundlephobia.com

ちなみに他のよくある data fetch ライブラリと比較すると以下のとおりです。他のライブラリとは機能が違うので単純比較は難しいですが、同等の機能を提供している Fetchr よりも10kB以上削減されています

f:id:yosuke_furukawa:20191216010313p:plain
各種 bundle size まとめ lower is better

Specter は内部的に fetch を使っています。これまでの data fetch ライブラリは基本的に XHR をラップする形で Promise を提供しています。IE11等、 fetch をサポートしていないブラウザ用にはこのアプローチが必要なものの、最近では fetch をサポートしていないブラウザのが珍しいので、こうしています。

一方で、 IE11 用に unfetch と呼ばれる軽量な polyfill を用意しています。これにより、 IE11 のような fetch 未サポートの環境でも Specter は動作します。

TypeScript friendly

Specter は TypeScript で型をつけられるようになっています。一方で、 TypeScript じゃなくても普通の JavaScript でも呼べるようにAPIは作られています。 TypeScript にどっぷり浸かるような TypeScript specific なライブラリではなく、あくまで TypeScript friendly としているのは、そのためです。

// TypeScript で使えば普通に型をはめて使える(ただし、TypeScript specific ではないので、あくまで型を自称しているのみ。GraphQLなどのアプローチとは異なる)
const request = new Request<RequestHeader, RequestQuery, RequestBody>("counter", {
    headers: {},
    query: {},
    body: {
      count: (count + 1),
    }
  });
const data = await client.update<CounterResponse>(request);
// Generics をやめてしまえば、 JS から普通に使える
const request = new Request("counter", {
    headers: {},
    query: {},
    body: {
      count: (count + 1),
    }
  });
const data = await client.update(request);

既存のシステムがまだまだ JavaScript で動いているものも多い状況で派手に migration をするのではなく、段階的に移行できるようにするためにこうしています。特に Fetchr で動いているものを徐々に TypeScript にしているような状況では、 Specter のように段階的な移行ができると移行の計画が立てやすいという考えでこうしています。

投機的先読み (Prefetching)

Prefetch の方法はいくつかあります。Prefetch もパフォーマンスチューニング分野ではよく研究されているものの1つです。いくつか Prefetch の方法を紹介します。

Prefetch で、一般的なのは dev.to でも実装されている、マウスオーバーしたら prefetch するという方法でしょうか。この方法では ユーザーが押そうとしたリンク を先読みするという効果があります。ただし、この方法はマウスを使わない端末、つまりスマートフォンタブレットでは使えません。

また、 Next.js や Nuxt.js には Link 先を 投機的に prefetch してくれる機能が存在します。この機能は Prefetching Pages と呼ばれており、静的なリンクでは viewport 内に Link が入ったら先読みします。 ただし、この方法は若干富豪的です。 さらにあまりにもリンクが多い場合は通信容量も増えてしまいます(所謂ギガが減る

https://nextjs.org/docs#prefetching-pages

最近はもう少しスマートな方法として、 Predictive Prefetching と呼ばれる方法が登場しています。これは Google Analytics などで計測している統計データに基づいて Prefetch する方法です。 GA の情報から次に行く可能性の高いリンクを予め Prefetch する方法です。

web.dev

Specter はまだ GA と組み込んで実装する機能は未実装ですが、ヒューリスティックに先読みする機能 (経験則に基づいて先読みする機能) 自体は存在します。例えば、検索実行時に、経験則に基づいて、検索結果の上位5件を予め Prefetch するなどのアプローチをすることが可能です。

// HackerNews の top story 一覧を取得する
const res = await fetch("https://hacker-news.firebaseio.com/v0/topstories.json", {
  method: "GET",
  headers: {
    "Content-Type": "application/json; charset=utf-8"
  }
});
const data: Array<number> = await res.json();

// 上位10件に関しては先読みするためのヒントとなる "次のリクエスト候補" に入れることができる
// もしもギガが気になるなら取らなくても可能
const nextReqs = data.slice(0, 10).map((id) => new ClientRequest<{},{ id: number },null>("hnitem", { 
  headers: {}, 
  query: { id: id }, 
  body: null,
}));
const resp = new Response(
  {},
  data,
);
resp.setNextReqs(...nextReqs);
return resp;

先読みする時は下記の要領で実行します。

const data = await client.read<HackerNewsListResponse>(request);
setTimeout(() => {
  // ここで先読みする、先読みしたデータは cache として残るため、次に取りに行く時には cache から fetch できる
  const reqs = data.getNextReqs();
  reqs?.forEach((req) => client.read(req));
}, 100);

実際HackerNews APIを基に先読みするケースと、先読みしないケースの両方を検証した所、先読みを行わないときに比べて時間が500msec以上減っています(先読み結果をcacheしているため)。

先読みしないとき: avg. 566ms
先読みしたとき: avg. 15ms

また、 Universal なライブラリとして作っているため、 Prefetch のタイミングが柔軟に変更できることが強みの1つです。SPAなどのリッチなアプリケーション の場合は Service Worker で行えば main thread を阻害しないで 先読みが可能です。また、そこまでしなくても requestIdleCallback などのブラウザが busy じゃないタイミングで Prefetch させることも可能です。逆に AMP 等、 クライアントで柔軟に Prefetch できない場合はサーバサイド (Node.js) で Prefetch した結果を Cache に入れておく事も可能です。

詳しくは HackersNews の example を確認してください。

github.com

使い方など

Next.js や React, Redux で利用する時の方法については詳しくは GitHub の examples を参考にしてください。

Next.js で使うとき: specter/examples/nextjs at master · recruit-tech/specter · GitHub React, Redux で使うとき: specter/examples/counter at master · recruit-tech/specter · GitHub

その他、何かあれば GitHub で気軽に issue 報告をお願いします。日本語でも問題ありません。

github.com

展望

まずはリクルート社内で実践をしながら、より細かなニーズに対応していこうと思っています。 @agreed からクライアントを自動生成する、などのニーズはたくさんあります。さらに、弊社では Google Analytics だけではなく、 Adobe Analytics や独自分析基盤などがあるため、それらともインテグレートしていく必要があります。

まだまだ実験的なデータフェッチライブラリなので、事業ニーズと一緒に考える必要は数多くありますが、ある程度まで動くものができた段階で徐々に広げていく予定です。

まとめ

Specter について解説しました。 Specter 自身は軽量で、 TypeScript friendly で、 投機的先読みが可能なデータフェッチライブラリです。それぞれの機能についての背景と利用した際にどれだけの利点があるかについても加えて解説しました。

実験的なアプローチですが、リクルート社内にはアプリケーションが多数あるので、それぞれのユースケースに対応していこうと思っています。今後は以下のようなロードマップを描いています。

  • example や 事例を増やす
  • ドキュメント拡充
  • Predictive Prefetch 実装
  • Analytics 基盤との連携

よかったら使ってみてください :) Feedback をお待ちしています。