見出し画像

Netflixはリアクトを削除したの?

10,679 文字

Netflixがリアクトを削除して、その結果ウェブサイトが50%速くなったって知ってました?信じられないでしょう?でも、Twitterで見たから間違いないはずです。ほら、これを見てください。実際のプレゼンテーションと思われるものからの本物の画像です。
明らかにこれは大きな話題ですよね?これは誤情報ではありません。コミュニティノートも提案されていません。これは、7年後になって理解もしていないリアクトの問題を利用して、自社のダメなAIスタートアップを売り込もうとする人の投稿でもありません。
ここには多くの話題があります。実際、リアクトを正しく使用することは、とてもシンプルでありながら、ある程度複雑です。Netflixチームがリアクトをデベロッパーにとって良い経験にし、ユーザーにとってウェブサイトを良い経験にするためにしてきたことは、本当に興味深く、微妙な部分があります。
くだらない投稿ではなく、会話に値する内容です。その会話をぜひしたいと思います。HTMLの生成方法から、JavaScriptのバンドル方法、なぜランディングページや利用規約にリアクトを使用するのかまで、興味深い詳細がたくさんあります。
でも、まず今日のスポンサーからの簡単なメッセージをお届けします。ソフトウェア開発には3つの難しい問題があります。命名、オフバイワンエラー、そしてライブ同期です。複数のユーザー間で同時に同期を取ろうとした経験がある人なら、その難しさを知っているでしょう。特にデータ管理、クエリ、レンダリングなどのカオスが加わると更に困難です。
ここに認証機能も備えたライブ同期チャットがあります。やあ、オタクたち。両方に即座に表示されるのが分かりますよね。ここにトリックはありません。マルチウィンドウを使用していないクライアントサイドの同期でもありません。コードを見てみましょう。これが全てのフロントエンドコードです。
これがどうして可能なのでしょうか?本当なのでしょうか?はい、本当です。これがコンベックスなのです。彼らはリアクトアプリケーションやその他のフレームワークのバックエンド全体を扱うことを非常に簡単にしています。私はリアクトオタクです。あなたもそうでしょう。それはそれで良いことです。
バックエンドのコードも同様にシンプルです。バックエンドの開発者である必要すらありません。フロントエンドでuseQueryやミューテーションを使用している部分をコマンドクリックするだけで、その定義を見ることができます。リストクエリには引数がなく、データベースを使用して最新の100件のメッセージを取得してユーザーに送信するシンプルなハンドラがあります。sendは本文と作成者を検証し、その新しいメッセージスキーマを処理します。とても使いやすいのです。
本当にこれだけです。本当にシンプルなのです。まだ試していない人は、今日soy dev.l/c convexでチェックしてみてください。
ここでコミュニティノートを見ると、文脈として非常に有用なリンクが投稿されています。2017年のHacker Newsボードでのなぜコンビネーター会話です。ここから掘り下げていきましょう。出発点として良い場所だと思います。
ツイートに出てきたNetflixのサインアップフローのリアクトについての講演を行ったチームで働いています。完全な講演はここで見ることができます。講演へのリンクも、人々がよく尋ねる質問についてのより多くの文脈を提供しています。
それを聞いてみましょう。なぜランディングページのレンダリングにリアクトを使用するのでしょうか?Netflixのランディングページは、多くの人が考えているよりもずっとダイナミックです。まず少し追加の文脈を説明させてください。
彼らはコードベースからリアクトを削除したわけではありません。アプリからリアクトを削除したわけでもありません。彼らが行ったのは、ランディングページをリアクトでサーバーサイドレンダリングすることだけで、クライアントサイドでJavaScriptを必要としないようにしただけです。つまり、リアクトが削除されたのは、ホームページでクライアントにロードされるJavaScriptのバンドルからだけです。
ここで言うように、最初に尋ねる質問は「リアクトを削除したのなら、なぜレンダリングにそれを使用するのか?他のもので書けばいいじゃないか。HTMLだけで書けばいいじゃないか。怠け者だ、バカだ、JSのソイデブだ」というものでしょう。
このエンジニアが指摘するように、良い理由があります。Netflixのランディングページは、ほとんどの人が考えているよりもはるかにダイナミックです。サインアップフローで最も多くABテストが行われているページで、場所、以前にNetflixのメンバーだったかどうか、デバイスタイプなどに応じて、メッセージングや画像をカスタマイズするための機械学習モデルも使用されています。
これは今のAIの売り込みではありません。これは7年以上前のものだということを覚えておいてください。それ以上に、Netflixは現在200近い国をサポートしており、それぞれの国で異なるローカライゼーション、法的課題、価値提案の組み合わせがあります。
私たちは、これらのABテストとローカライゼーションの課題に関するUIロジックの多くを、主にリアクトコンポーネントを通じてサインアップフロー全体で共有しています。クレイジーですよね。HTMLがより動的になり、結果として生じる可能性のあるものが増えると、リアクトはその問題に対する良い解決策になることが分かります。
HTMLをテンプレート化する他の方法もありますが、もし会社が既に全てをリアクトで構築しており、このページも既にリアクトで書かれていて、単に高速化したいだけなら、これらのツールを使用して適切なHTMLをリアクトでレンダリングし、ユーザーにHTMLだけを送信することができます。
最近の人なら、これはリアクトチームが導入した何かに似ているように聞こえるかもしれません。でも、まだネタバレしないでください。そこにたどり着きますから。
私がいつも挙げる例は、利用規約コンポーネントです。Netflixの顧客にとっては、UIでは文字通り1つか2つのチェックボックスですが、サポートしている国とユーザーの状態の膨大な数により、コードベースで最も複雑なロジックの1つを持っています。
このため、これらのカスタムリアクトコンポーネントをランディングページとシングルページリアクト&Reduxアプリケーションである残りのフロー全体で共有することが、私たちにとってより価値があります。
彼らは全てを共有できます。ただし、ユーザーのために結果を事前にサーバー上で生成しているだけです。サーバーコンポーネントのように聞こえますよね?そこに到達します。
利用規約の例が好きなのは、誰もがこのような非常にダイナミックなフローを持っているわけではないからではなく、データの取得と二重取得が最も必要とされる一貫したものの1つだからです。
古い方法でNextjs、TypeScript、リアクトなどを使用して構築したpingというアプリに行き、利用規約ページに移動すると、興味深いことが分かります。ネットワークタブに移動して、T3ツールが提供するようなものを取得し、これを検索すると、2つの場所で表示されることが分かります。
1つのファイルの2つの場所ではなく、2つの異なるファイルです。ここにping.ginfoなどがありますが、これは実際のHTMLレスポンスで、エディタで開くと、これはURLにアクセスしたときにコンピュータが取得したHTMLページであり、この利用規約の全ての情報が含まれています。
利用規約のH2タグとPタグが全てHTMLに含まれています。クール、それはウェブの仕組みですよね?特別なことは何もありません。でも、もう1つあります。
私たちは同じデータをJavaScriptで再度読み込みます。なぜなら、古いリアクトモデルでサーバーレンダリングする場合、デフォルトのHTML状態を作成しますが、サーバーとクライアントで全く同じJSコードを実行する必要があるからです。
そのため、適切に実行され、利用規約に正しいものが含まれるようにするためのコード、利用規約の全ての単語を含むコードは、ページがロードされるとすぐに全てを再実行、再レンダリング、再アタッチするJSバンドルに含まれる必要があります。
これはとても面倒です。全てのデータを二重に取得しなければならないこと、既にHTMLにあるのに全てのコピーをここにも含める必要があることは、本当に面倒です。
サーバーコンポーネントはこれを大幅に解決します。サーバーコンポーネントを使用する場合、同じものをJSとして送信する必要はなく、HTMLの表現だけで済むからです。もうすぐそこに到達します。また先走ってしまいました。
ランディングページのパフォーマンスを改善することで、特に接続が遅い国々で多くのコンバージョン価値を見てきましたが、共有しているUIロジックの多くを再複製したくはありません。
言っておきますが、Netflixのサインアップができないほど接続が遅い場合、Netflixで映画をストリーミングするのはどうなるのでしょうか?他の会社、例えばAmazonやWalmart、銀行の場合はこれは理にかなっていますが、Netflixにサインアップできないほどインターネットが遅い場合、視聴体験はどうなるのでしょうか?
私たちが決めたトレードオフは、ランディングページをリアクトを使用してサーバーレンダリングすることですが、その間に残りのサインアップフロー用のリアクトとReduxのコードもプリフェッチします。
これは最初のロードのパフォーマンスを最適化するだけでなく、シングルページアプリケーションとしてより大きなJSバンドルサイズをダウンロードする必要がある残りのサインアップフローのロード時間も最適化します。
これは全て理にかなっています。サーバーコンポーネントのように聞こえ始めていますね。ここから面白くなります。
ここにSophieがいます。当時はリアクトチームの従業員でしたが、現在は外部から貢献しています。私はリアクトで働いています。あなたのチームの話をぜひ聞きたいと思います。また、このような問題について協力したいと思います。
私たちは多くの同じ問題を解決していますが、Netflixのエンジニアから話を聞くのは、リアクトを避けている、または私たちが知らなかった理由でフォークしたことを発表する講演以外ではほとんどありません。
はい、当時はこういうことが多くありました。リアクトの一部を再発明したり、フォークしたり、改造したりして、リアクトチームに連絡を取ることもなく、派手な講演をするというようなことが。
状況は良くなっています。これは双方の問題でした。リアクトチームがこのような事柄にどれほどオープンだったかを明確にしていなかったからです。彼らはそれについてはるかに良くなりました。
本当に望むなら、特に大企業で働いているなら、十分な理由があれば彼らに連絡を取るのは簡単です。これが書かれた理由は、ほぼ確実に彼らがサーバーコンポーネントがどのように機能するかを探り始めていたからです。
ここで説明された全ての利点について、厳しいけれど少し面白い現実は、新しいサーバーコンポーネントモデルを使用していれば、ほぼ同じことを全て実現できていたということです。
コンポーネントをランディングページと他の場所で再利用でき、サーバーでレンダリングする場合はサーバーコンポーネントとして、クライアントでレンダリングする場合はクライアントコンポーネントとして機能します。素晴らしいですね。
利用規約をユーザーのクッキーなどに基づいてダイナミックにすることができ、異なる可能な状態を全てJSとしてロードする必要がなく、ユーザーが必要とするものだけをロードすれば良いのです。
これの変わった例を持っています。ここにupload thingがあります。まだ知らない人のために説明すると、これは私が構築したアプリで、アプリにファイルアップロードを簡単に追加できるようにするために作った3Dプリントのものです。
ファイルアップロードと言っても、ウェブUIでどこかにダンプしてユーザーにファイルを見せるだけではありません。ユーザーがファイルをアップロードできるということです。ユーザー生成コンテンツは、適切に処理するのが本当に難しいものです。特にフルスタック開発者やNext開発者の場合、私たちはそれを行う優れた方法を構築しました。
でも、今回はupload thingを宣伝するためではありません。それは既に前にしました。サーバーコンポーネントがこれを構築して作業するのをどれだけ簡単にしたかを皆さんにお見せするためです。
ここに私のアプリがあります。これらすべてに、それぞれが異なることを分かりやすくするための素敵な背景があることに気づいたかもしれません。私はこれにhero patternsを使用しています。hero patternsは、SVGとして取得して使用できるオープンソースのパターンのソースです。とても良いものです。
私はこれらを全て巨大なファイルに入れています。巨大というのは本当です。finderでutils generate patternを表示すると、このファイルだけで205キロバイトのJavaScriptがあり、それは全てレンダリングしたいSVGパターンだけです。
歴史的に、JavaScriptコードでこれを行うことは絶対に避けるべきでした。なぜなら、JavaScriptコードでこれを行うと、この巨大なファイルがユーザーにロードされるからです。このファイル1つだけでリアクト全体よりも大きく、それは少し馬鹿げています。これは本当に悪いことです。
これを行う従来の方法、伝統的な方法は、SVGを全てここに置く代わりに、コンテンツがロードされた後にリモートからロードすることです。しかし、そうすると、ページがロードされた時点でパターンが表示される良い埋め込み動作がなくなり、サーバーから別のラウンドトリップで取得するのを待たなければなりません。理想的ではありません。
では、これらの異なる条件を全て私たちのコードに存在させ、ユーザーにJSを送信することなく、正しいSVGを使用してHTMLを生成することをどうやって確実にするのでしょうか?実は非常にシンプルです。
このファイルはそのように機能します。別の動作をさせたい場合は、これが存在する場所に行きます。page.TSXでこれを呼び出していることが分かります。これをクライアントサイドにしたい場合は簡単です。ここに上がって「use client」とします。
これで、このファイルはJavaScriptをユーザーにロードします。これがなければ、get random pattern Stylesとその関数からの要素、そのコードからの要素はユーザーに送られません。UIが取り得る信じられないほど多くの順列を指定でき、それをコードに表現できますが、それらの潜在的な状態を全てユーザーに送信する必要はありません。
これについて考える方法は、このようなUIを見たとき、コードは全ての異なる状態を処理する必要があるということです。空の状態、ロード中の状態、15個のアプリがある状態、1つのアプリがある状態、それらの異なるアプリの異なる背景を持つ異なる状態を処理する必要があります。
つまり、UIが取り得る全ての順列に対してコードが存在する必要があります。これを考える方法を説明するパターンがあり、それはサーバー駆動UIと呼ばれています。
サーバーがクライアントにデータを提供し、クライアントがそれを使用してUIのどのバージョンを表示するかを判断する代わりに、サーバーがUIを駆動するとどうなるでしょうか?サーバーがクライアントに「あなたのUIはこのように見えるべきです」と伝えるのです。
これが、ウェブが以前機能していた方法です。アプリ、そして私も認めますが、リアクトやコアのようなものを使用して構築されたシングルページアプリやウェブサイトは、異なる考え方を促します。
HTMLには何も含まれず、少しのJSをロードし、それがJSONを取得して、ユーザーのデバイス上でHTMLを生成するというものです。これは、HTMLがレンダリングできる全ての方法が最初にJSに存在する必要があることを意味します。
サーバーコンポーネントは、もはやクライアントのデバイス上にそれらの順列を表現するコードを全て持つ必要がないことを意味します。サーバー上で実行して、その順列だけをユーザーに送信できます。
私はそのファイルに少なくとも400のパターンを持っています。おそらくここにはそれだけあります。これらの全てのパターンと全てのものを持っていますが、ロードされるのは実際にレンダリングされているものの実際のHTMLだけです。
これがサーバーコンポーネントの魔法です。では、これらが異なるパターンではなく、異なる国であり、15個ではなく1つをレンダリングするものの、それぞれに異なるニーズがあり、その理論上のJavaScriptファイルが、全ての異なる言語、全ての異なる期待が存在する可能性のある全ての異なるコピーで巨大であると想像してください。
そして今、それらの異なる順列を全てレンダリングする必要があり、それはJavaScriptが全ての言語のための全てのものを含む必要があることを意味します。アメリカ版をロードする時、インド版のコードもロードし、ドイツ版のコードもロードし、そのURLが潜在的に取り得る全ての異なる状態のための全ての異なるJavaScriptをロードします。
サーバーコンポーネントの魔法は、実際にレンダリングしているものに対してのみフェッチを行うということです。そのため、米国でこのページをロードしている場合、インドやドイツ版のJavaScriptはロードせず、レンダリングしたものだけをロードします。
これは、ここで説明されている問題を解決します。彼らは事実上、ここで説明していることでサーバーコンポーネントを再実装しましたが、面白いことに、正しい方法でサーバーコンポーネントを実装すると、節約は50%よりもさらに大きくなる可能性があります。
これらのことを活用する多くのアプリケーションで、私たちは既にこれを見てきました。サーバーコンポーネントを使用すると、ユーザーに追加のJavaScriptを送信することなくHTMLを生成するサーバーコードを持つことができます。
これは単なるPHPの再発明ではありません。なぜなら、PHPではクライアントコードを書くことができないからです。クライアント上で私が説明している方法で動作し、サーバー上ではユーザーにJavaScriptを送信しないコンポーネントを持つことができ、両方の場所で再利用できます。
これは、他のものが持っていなかった概念です。確かに、サーバーがHTMLを送信するのはPHPのように感じるかもしれませんが、これを単なるPHPだと思うなら、あなたはPHPもブラウザも理解していません。
ランダムなチャッターを批判して申し訳ありませんが、これは今日誰かが言った中で最も馬鹿げたことで、もしあなたがこれが実際にそうだと思うなら、私の内容を見ていることが信じられません。
とにかく、これの証拠が欲しい場合、とても良い例があります。私には「Next faster」という動画があり、おそらく既に公開されているはずです。McMasterというウェブサイトがあり、人々はそれがバニラHTMLだからそんなに速いと考えているようですが、実際には大量のJS、つまり複数メガバイトのJSを使用して、それほど速く感じるようにしています。
EthanとNcerとそのチームは、Next fasterというサービスでそれを再構築しました。これは学校教材用のもので、さらに速いです。クリックすると、今、今、今、今、今と即座にロードされます。なぜなら、nextjsとサーバーレンダリングを使用すると、これを行うのがとても簡単だからです。
新しいモデルの最も素晴らしい部分は、単なるHTMLであることをやめてクライアントのJSになるタイミングを選択でき、HTMLとしてサーバーからクライアントに物事を渡すことができることです。
サーバーコンポーネントが以前のモデルとどれほど異なるかを示すために、シンプルな例を作りました。ドキュメントで、typescriptやJavaScript、python、HTMLなどのような小さなタブがあることを想像してください。そのようなタブバーの1つです。
これらの小さなタブがあります。タブA、タブB、タブC。クリックすると、異なるコンテンツが表示されます。これら全てをプロパティとして渡します。タブコンテンツ、タブ=a、タブ=b、タブ=cです。
この小さなヘルパー関数tabContentsがあり、タブのコンポーネントをレンダリングすることをコンソールログに記録します。これを皆さんが慣れている方法で行うと、無視してここに行き、更新してタブCをクリックすると、ログが記録されます。タブBをクリックすると、ログが記録されます。
理由は、この全てのJavaScriptがクライアント上で実行されているからです。その通りです。しかし、これを削除するとどうなるでしょうか?
これらのサーバーログが表示されていますが、これらはnextによって挿入されています。彼らが行う素晴らしいことですが、これらはクライアントサイドでは発生していません。単に私のためにそれらを転送しているだけです。
そして、タブ間をクリックしても新しいログはありません。どうしてでしょうか?何が起きているのでしょうか?
サーバーコンポーネントで現在できる本当に素晴らしいことの1つで、他のフレームワークにはないものは、tabContentsのようなサーバーレンダリングされたコンポーネントを、useStateの呼び出しがあるのでクライアントコンポーネントであることが明らかなtabWrapperのようなクライアントコンポーネントにプロパティとして渡すと、これら全ての状態がサーバー上でレンダリングされるということです。
なぜなら、それらは全てプロパティとして渡されているからです。そのため、A、B、Cは全てサーバー上でレンダリングされ、事実上HTMLとしてクライアントに渡されます。つまり、それらは全てサーバー上で事前レンダリングされ、今では待つ必要はありません。
それらは全てそこにあり、HTML内にあり、ブラウザ内にあります。そして、これらの異なる状態が全て存在し得て、全てこのコードで生成され、実行されているにもかかわらず、それはエンドユーザーには影響しません。
これらの何もユーザーには送られません。ユーザーはそれについて知る必要はありませんし、知るべきではありません。今では、これらの異なる条件を無限に持つことができ、そのどれもユーザーが取得するJSとしてロードされません。
そして、通常リアクトから得られるダイナミックな動作とコントロールを諦める必要はありません。JSをユーザーに送信しないこれらのものと、送信するものを組み合わせるオプションがあるだけです。
これは新しいパラダイムです。本当に素晴らしく、7年前のコメントで説明されている全ての問題を解決します。そのコメントは、無料で注目を集めようとするAIの売り込み屋によって誤用されている7年以上前の講演からのものです。
このことについてさらに注目を集めていることを信じられませんが、長い間見た中で最も馬鹿げたことだったので、少し怒りを爆発させなければなりませんでした。
なぜなら、この問題が深く誤解されているだけでなく、新しい解決策によって解決されており、これを皮肉なく大きな問題として共有している人々は、新しい解決策について文句を言い、「ああ、私たちはただPHPを再発明しただけだ」と言っている同じ人たちです。いいえ、そうではありません。これは新しいものです。これが新しいものであることを理解できないなら、それはもはや私たちの責任ではありません。
私たちの多くが、このパターンがなぜ素晴らしく、next fasterのような本当に良い公開例を使って、どのようにして物事をとても動的に、マークアップとデータモデルの両方で多くのことが起こっているにもかかわらず、使用するのが面倒なものにならないように構築できるかを説明する十分な仕事をしています。next fasterはオープンソースで、どのように作られているかを見ることができます。
しかし、シングルページアプリの全盛期にNetflixにいた場合は、少し同情を示しましょう。これらの解決策は存在せず、HTMLのレンダリング方法を再発明してリアクトの部分を取り除くような劇的なことをする理由が理解できます。
サーバーコンポーネントがまだなかったからです。しかし、今はあります。そして、これらのツールが改善されていないかのように、10年近く前の例を引き続き参照するのは恥ずかしいことです。
これらのことを、リアクトが本番環境でどのように機能するかについての本物や誠実で意味のある解説であるかのように共有し続けることを本当にやめてほしいと思います。
Netflixの誰も今日これが正しいことだとは言わないでしょう。それを構築した人も言わないでしょう。そして、私は代わりに正しい方法を説明しています。
嫌いなものを批判しているからといって、理解していないことを共有するのをやめてください。そして、AIの売り込みをやめてください。もうたくさんです。
ああ、この件についてはもう何も言うことはありません。以上です。

いいなと思ったら応援しよう!