HTMLファーストなサイトを構築して一晩でユーザー数を2倍に増やした方法
(mohkohn.co.uk)- HTMLファースト のアプローチにより、公共サービスの申請フォームをJavaScriptなしでも動作させ、性能の低い端末・ブラウザ・ネットワーク環境でもユーザーが申請を完了できるようにした
- 既存のReactアプリは顧客からの苦情により3日で取り下げられ、ローディングスピナー・グローバルなJavaScript状態・アクセシビリティ問題・
localStorageの5MB制限に引っかかる画像保存方式が問題だった - 新しい実装はAstroベースで、フォームの各ステップを別ページとして構成し、送信データとアップロードを バックエンドセッション に各段階ごとに保存して入力データの消失を防いだ
- フォーム検証はブラウザ内蔵のHTML検証をラップするWebコンポーネントで処理し、失敗時にはブラウザ標準の検証とバックエンドAPI検証へ続く プログレッシブエンハンスメント 構造を採用した
- リリース後、フォーム完了者は2倍に増え、JavaScriptの失敗で離脱したユーザーはJavaScriptベースの分析パッケージでは捉えられないことが明らかになった
問題の背景と失敗した以前の試み
- 顧客はユーティリティ企業で、サービス申請はWebサイト上の古いASPフォームまたは手動手続きで可能だった
- 手動手続きは企業にとってより高コストで、顧客満足度が96%を下回ると数百万ポンドの罰金が発生しうる規制独占の状況だった
- 問題解決のための以前の試みは2回失敗しており、直近の試みでは別の国の請負業者がReactアプリを作成していた
- Reactアプリは一般公開から3日後、顧客からの苦情で取り下げられた
- そのアプリはローディングスピナーとグローバルなJavaScript状態が入り混じっており、アクセシビリティも備えていなかった
- 画像アップロードはフォームの中核機能だったが、画像とすべてのフォームデータを5MB制限のある
localStorageに保存しようとしていた
HTMLファーストとして定めた基準
- 新しいサイトは Astro で構築され、HTMLファーストな構造を採用した
- JavaScriptはWebコンポーネント内でのみ使用され、JavaScriptなしでも正常に動作するWebサイトを段階的に改善する役割を担った
- 公共サービスは可能な限りあらゆる端末で動作しなければならないという基準を適用した
- 接続状態が悪くても動作しなければならないという基準を適用した
- 一度入力されたフォームデータは決して消えてはならないという基準を適用した
- Terence Edenの事例は、GOV.UKのシンプルなHTMLページが、低速でメモリ不足を起こしがちなPlayStation Portableブラウザでも住宅給付情報を読めるようにしていたことを示している
- GOV.UKのページは軽量に設計されたシンプルなHTMLで書かれており、劣悪なブラウザでも動作する必要があった
フォーム構造とデータ保持の方式
- フォームの各セッションは固有IDを持つ必要があった
- フォームウィザードの全ステップで、送信データとアップロードファイルはバックエンドに保存される必要があった
- JavaScriptなしでもフォーム完了が可能である必要があった
- 古くて性能の低いWebブラウザでもフォーム完了が可能である必要があった
- アクセシビリティはWCAG基準を満たす必要があり、チームはAAAではなくAAを目標に定めた
- JavaScriptと最新CSSは体験を向上させるために使うべきだった
- 最終的な構造では、フォームウィザードの各ステップが別ページとなり、ユーザーが次へ進むを押すとフォームが送信された
- APIがデータを有効だと判断すると、ブラウザは次のステップへリダイレクトされた
- フォーム送信とリダイレクトは古いWebアプリケーションのパターンだが、Remix のおかげで小さな現代的復興を迎えている
- このサービスはリアルタイムデータを表示するアプリではなく大きなフォームであり、レンダリング前に20MBのJavaScriptを送る方式は不適切だった
フォーム検証とプログレッシブエンハンスメント
- フォーム検証とフォームエラーのレンダリングは、Reactの検証ライブラリのせいでチームが何か月も費やす領域として扱われがちだった
- ブラウザにはすでに検証システムが含まれており、別途ライブラリ管理が必要な質の低い模倣実装より少ない作業で活用できる
- 実装された HTML Webコンポーネント は、既存のHTMLを包むシンプルなカスタム要素だった
- このWebコンポーネントはShadow DOMを使わず、JavaScript内でHTMLをほとんどレンダリングしなかった
- コンポーネントはHTMLフォームを包み、HTML検証を取り込んで現代的な形で表示した
- HTML検証のポップアップツールチップは抑止し、フィールドと関連付けられた
aria-describedby要素内にエラーを配置した - 現在は
aria-errormessageの使用が推奨されている - 入力中に有効な状態になると検証を消去し、
blurと送信時に再評価した - このユーザー体験は1KB未満で提供され、失敗時にはブラウザ標準の検証へフォールバックした
- ブラウザ標準の検証も失敗した場合は、バックエンドAPIが検証を処理した
- 検証上の問題はユーザーのブラウザが許す最も早い時点で通知され、失敗しても常に受け入れ可能な体験へフォールバックした
- その後、一般利用を目指した新バージョンのWebコンポーネントが最初から書き直され、名前は validation-enhancer となった
- 使用例は、
validation-enhancerがHTMLフォームを包み、input type="email"、required、aria-errormessageをそのまま活用する構造である
Email
Submit
リリース結果と結論
- リリース後、フォームを完了した人数は2倍になった
- 分析担当者たちは、これらのユーザーがどこから来たのか分からなかった
- JavaScriptベースの分析パッケージは、JavaScriptの失敗で離脱したユーザーを見られない
- バックエンドセッションを維持し、ユーザーデータを決して失わないアプローチは効果を上げた
- ある事例では、ユーザーはフォームを開始してから1か月後に完了した
- 契約業務が終わった後、後任者はJavaScriptなしでも常に動作する構造がチームにより多くの仕事を生むと反応した
- 古いブラウザの利用者、悪いネットワーク接続の利用者、支援技術の利用者を排除することは、独占的な公共サービスでは受け入れられない
- ソフトウェア産業の拡大期に現れた粗く未成熟なやり方を押し通し続ける流れは手放すべきだ
- PlayStation Portableと3G接続でも動作するWebアプリケーションを作れば、すべてのユーザーに対して動作し、30年後でも動作しうる
2件のコメント
Hacker Newsの意見
非Web開発者として気になるのですが、なぜこのやり方が作業量の増加になるのか分かりません。
記事で説明されているアプローチはかなり単純に見えます。フォーム用の標準コンポーネントを作って、その下に送信ボタンを置けばいいだけです。昔個人サイトを作ったときもそうしていましたし、それほど難しくはありませんでした。この分野をよく知らないからかもしれませんが、派手なフロントエンドを作るほうがずっと難しく見えます。
馬鹿だからではありません。直接「ReactなしでWebサイトは作れますか?」と聞けば、当然「はい」と答えるでしょう。でも新しいWebサイトを作れと言われると、慣れと仕事を終わらせたい気持ちから、深く考えず新しいReactプロジェクトを始めてしまいます。
中には本当に別の方法を知らない人もいます。素のHTMLを返す普通のHTTPサーバーの立て方も、JavaScriptなしで検証・送信されるフォームを作った経験もありません。こういう人たちはHNに書き込むような人ではなく、新しいツールや技術、あるいは古いツールや技術についてのオンライン議論にも参加しません。ブートキャンプや大学のWebアプリの授業を1つ受けて、就職に必要な分だけ学び、その後は雇用主が求める、あるいはチームの誰かが選んだ特定のツールだけをその都度学んできたタイプです。
年長の立場からすると、これに気づくまで少し時間がかかりましたが、今では理解できます。キャリアの道筋によっては、HTML、CSS、素のJavaScriptの最も基本的な部分に、各技術の複雑なフレームワーク専用の部分より後になって触れる人もいます。だから彼らには、それがより非専門的なのではなく、むしろより難解で高度、あるいは周辺的な知識のように感じられるのです。
「それは私たちの仕事をずっと増やす」という言い方も、必ずしも意図的に間違っている主張ではないのかもしれません。慣れていない道具で作業をすれば、その道具のほうが複雑でなくても、実際に仕事量がずっと多いように感じられる可能性は高いです。
アプリは速くて単純でしたが、その代償もありました。リッチなUI要素をnpmパッケージからそのまま持ってくる能力が制限され、良いユーザー体験を提供するにははるかに多くの作業が必要でした。すべてに時間がかかり、結果としてユーザー体験も悪くなりました。気にはかけていましたが、最後まで面倒を見る時間がないこともあります。
会社は失敗しましたし、Reactがそれを救えたとも思いません。ただ、「単純さ」への道徳的なこだわりも役には立たなかったと自分の経験から言えます。常にトレードオフなのです。
ある人は、大半の人が思いつく解決策よりもっと単純で合理的な解決策を提示したと言い、引き継いだ人は満足していませんでした。
引き継がれたコードの品質が高かったのか分かるのでしょうか。その人は「Reactではない」という事実に反応したのでしょうか。会社にアプリの作り方について強制されるテンプレートがあった可能性はあるのでしょうか。
分かりません。
ここしばらく頻繁には聞きませんが、HTML Triptychの提案は、いつかブラウザに入ってほしいと今でも願っているものの1つです。HTMLフォームがRESTエンドポイントと対話するやり方は良いパターンです。
ユーザー補助の検証は入力属性で処理し、実際の検証はリクエストの向こう側で行い、流れは GET /form => POST /thing => GET /thing/1 という形になります。triptychの機能が実装されれば、素晴らしいパターンになるでしょう。
[0] https://triptychproject.org/
Reactサイトはまったく好きではありませんが、理解できないのは、こういうサイトは遅延読み込みをまったくしないのかという点です。
大きなシングルページアプリでも、必要なときだけコンポーネントを読み込めば非常に高速です。
Angular1 -> Vue2 -> Svelte2 を経て、シャドーDOMなしの素のWeb Componentsに落ち着きましたが、作業していて楽しいし速いです。
最近はほとんどのアプリを単に HTMX + Go + SQLite で作っている
たいていのプロジェクトにはそれで十分だと感じている
私のサイトの1つは画像が多く、月間 10TB のトラフィックを処理している。この場合の構成は次のとおり: 1. 信頼できるデータストアが必要なので S3 を使う 2. 手前に Cloudflare を置いて Tiered Cache を有効にする。こうすると POP はオリジンよりも Cloudflare から取得することを優先する。ブラウザと Cloudflare の両方で全てを1年間キャッシュし、オリジンのキャッシュポリシーとクエリ文字列を無視するルールを設定し、リビジョンが必要な不変オブジェクトだけを使う 3. その前段に BunnyCDN を置く
Cloudflare だけでは画像の多いサイトを運用させてもらえないので、この方法でコストを大きく下げている。ポリシー上、主に画像に使ってはいけず、HTML、CSS、JavaScript とその他のサイトコンテンツに使う必要がある
S3 だけを使うと費用がとても大きくなる
ただ最近はモバイルアプリも作っている。PWA には限界がある。OS が IndexedDB のストレージを回収できてしまうので、会員登録やバックエンドの介入なしに、アプリ内で信頼できるデータストアを提供できない
結局 Android では Flutter に移るしかなかったが、別の苦しさがあった。アプリ更新が「審査中」のまま長くかかることがあり、もどかしい。同じアプリのウェブアプリ版は、それと比べると更新が非常に速い
なぜ JavaScript、HTML、CSS でアプリを作れるようにして、しかも安定したストレージまで大きな努力なしに提供してくれるモバイル OS がないのか不思議だ。PWA アプリを素早く更新できる点は良い
時間旅行は簡単な部分で、その次は Palm の没落と webOS がスマートフォン OS として忘れ去られるのを何とか防がなければならない
2009年が遠すぎるなら、2012年の Firefox OS に賭けてみることもできる
冗談はさておき、人や企業が試したことはある。ただ、悪いタイミングといくつもの出来事が重なって、私たちの時間線ではその現実は実現しなかった
C のような余計な負担がなく、それでいて Java のようにビジネスロジックに集中できるよう道を空けてくれる、まさに最適な地点にある感じだ。Rust とは違う
もちろん全ての作業に向いているわけではない。特に抽象化を作る力が弱いのは惜しい。だがビジネスロジックの多いサーバーアプリには素晴らしい。何でもやろうとする言語ではなく、その分野に特化した感じがある
SQL と HTMX/ウェブ/OAuth の部分を抽象化しようと、ライブラリもいくつか作った。今では自分のアプリ同士がかなり似ていて、機能を移植しやすい
https://github.com/cattlecloud/webtools
https://github.com/cattlecloud/litesql
反論としては In Defence of the Single Page Application がある
https://williamkennedy.ninja/javascript/2022/05/03/in-defenc...
In Defence of the Single Page Application - https://news.ycombinator.com/item?id=31275178 - 2022年5月、コメント32件
この記事は良いし、問題を持ち込み、それを適切な技術と適切な深さで解決した優れた実例だ。顧客のドメイン知識を完全に持っていると本当に助けになる
ただし「シンプルな HTML は React より良い」というようなフレーミングは好きではない。同じ話は React 開発者としてでもまったく同じようにできるからだ
サーバー側セッション保存とブラウザ側保存の複雑さや機微など、この記事でざっくり流されている話はいくらでもできるが、長くなりすぎる
HTML で単純なものは React でも単純だ
文字どおり同じコードだ。React でブラウザベースの HTML 検証を使えないようにしているわけではない。React で複雑になるコード、たとえば過剰に複雑な検証ロジックは Astro でも複雑になる。Astro にもスキーマ検証などに関する独自のやり方があり、Astro サイトに統合するにはクライアントルーターなども統合しなければならないので、そこでも過剰に複雑になりやすい
比較対象も、おそらく不完全な知識しかない海外の外注チームで、プロジェクトの構造上、できるだけ早く、できるだけ少ない時間で、できるだけ大きな複雑性を持つ解決策を作るインセンティブがある
最後の点は巧妙だ。外注先が意図的にそうしているという意味ではないが、インセンティブ構造 の上では過剰に複雑なほうが実際に彼らの利益になるため、シンプルなやり方へ進む直接的な動機がない
とにかく、目の前の問題を直接扱うシンプルな解決策のほうが常に良く、どのスタックを選んでも同じだ
Astro のフォーム検証に反感があるわけではなく、「ネイティブ HTML のブラウザ検証」以上の話があることを強調したかっただけだ
素晴らしい文章だが、こういう刺激を与えてくれる文章を読むたびにいつも葛藤する。言っていることは完全に正しく、うまく動き、素早く読み込まれ、最新ブラウザに依存しないシンプルなサイトという発想が気に入っている
すると今度は、これが自分に React やその時々で流行しているしゃれた技術を理解できるほどの頭の良さがないからではないか、と考えてしまう
越えられない理解の限界線があるように感じる。Sublime のようなシンプルなエディタを渡されて Web ページを作れと言われれば、JavaScript があっても幸せな領域だ。VSCode や Zed、あちこちに付いた Claude/Copilot/ChatGPT プラグイン、React のチュートリアルを渡されると頭がふにゃふにゃになる
シンプルに保つのは悪いことではなく、むしろ過度に複雑にしないだけの賢さが必要な場合が多い
Embrace Extend Extinguish は現実のものであり、それに同調する人たちは、より速く嘘をつき、ゴミコードを吐き出す LLM に置き換えられても当然だ
ほぼ 15 年前を思い出す。Grails でバックエンドのセッション管理を使い、レスポンシブ CSS と「少しの」JS で強化したHTML フォームを使っていた
当時と違うのは、ブラウザ技術が今ほど発達していなかったことだ。複数のブラウザを気にしなければならず、IE7、さらには IE6 まで扱う必要があったので難しく、広範な QA が必要だった。BrowserStack が出てきたのはもっと後だった
JavaScript ライブラリが進化したのには理由がある。npm もなく、bower すらなかった。そこへ Backbone.js が出てきて気に入っていた。AngularJS は驚異的で、その次の Angular バージョンでは大きな互換性破壊があり、その後 React、Polymer などが登場した
今どきのネイティブブラウザは多くのことができ、機能強化も簡単だ。だが、いつもそうだったわけではない。当時 React を使うと決めたのはさまざまな理由で妥当であり、ここでもそうだったのかもしれない
10 年以上前、法務省のために GOV.UK でこうしたアプリを作っていた。長いフォームを段階的に検証し、複数ページに分けられる独自のフォームウィザードライブラリを作った。Ruby on Rails がそれを標準ではサポートしていなかったからだ
当時は、ユーザーがどんな環境からアクセスしようと、誰もがデジタルサービスを利用できるべきだという原則が非常に重要だった
各セッション ID ごとにマルチページアプリケーションのページとそのセッション ID を照合できるので、必要ならユーザー自身が入力することもできる。とはいえ、IP アドレス、アップロード日、ブラウザ、OS といった十分な情報があれば判別できるはずだ。ただし最も正確なセッションはブラウザ内にあるべきで、単一の申請書のクッキーが PlayStation Portable を使っている親戚のような別の申請者と混ざらないようにしなければならない
モバイルアプリにはどんな技術を使っているのか気になる。完全なモバイルアプリではなく、WebView を使っているのではないかと推測している
これは「React アプリを HTML フォームに変えたら性能が良くなった」という話ではない。「悪い Web ページを良い Web ページに変えたら性能が良くなった」という話だ
これをブラウザ体験を駆動する技術のせいにするのは愚かだ。React でも優れたユーザー体験は作れるし、素の HTML でもひどい Web サイトは作れる
改善は技術ではなく、設計変更から来たものだ
だがその通りだ。ユーザー側の変化は使用技術ではなく、設計を直したことから生まれた
これはひどい職務経歴書の bullet point によく似ている。誰かが「Web サイトを HTML 優先に書き直して訪問者数を 100% 増加」と、事業成果がコード変更のおかげであるかのように主張するようなものだ。その項目について尋ねると、結局はデザイン上の問題を修正したり機能を追加したりするためにサイト全体を再設計し、その結果として訪問者増が起きたのだと認めることになる
Douglas Crockford の JavaScript: The Good Parts は笑ってしまうほど短い責務だ。React: The Good Parts はそれよりさらに短いだろう
面白いことに、原文はここ 10 年ほどほとんど見なくなったマルチページのウィザード風フォームを説明している。だが自分がそういうものを見るときは、たいていひどいエンタープライズシステムだった。最後に見たのは経費精算向けの Oracle 製品のようなものだった
そういうものの問題はいつも、作業の途中が遅いことだ。ボタンを押すたびに数秒待たされる。1、2 ステップ戻らなければならないと、いらだたしさは倍になる。出来の悪いシングルページアプリは起動が遅い傾向がある。読み込みには時間がかかるが、いったん読み込まれてしまえば、通常はパフォーマンスは悪くない
Lobste.rsの意見
人のためにきちんと動くものを作るのは、当然ながらより手間がかかる。だが、それこそが結局 仕事全体の核心 でもある
後輩たちが本当に言いたかったのは、Webプラットフォームの基本をよく知らないという意味に近いように見える
それが望ましいという意味ではなく、今の現実がそうだという話だ
「フォーム送信とリダイレクト」を同僚に説明するのに時間がかかった、というくだりは苦い。みんなが クライアント中心のWebアプリ に慣れきってしまったせいだ
今のWeb開発は本当に残念な状態で、教え直さなければならないことが多い
こうしたアプローチを正当化するのに、そこまで高いレベルの互換性は必要ないと思う。記事でも言っているように、しょせん フォーム にすぎない
だから自分なら、どんな場合でもそう作ると思う
記事で説明されているようなサイト作りをしてみたい。ほぼすべてのブラウザで動き、アクセシビリティにも配慮しなければならない 非常に小さなダウンロードサイズ という制約は、かなり面白い挑戦に聞こえる
こういう分野を専門にしている会社があるのか、採用しているのか気になる。単に昔のシンプルだったやり方が恋しい年配者なだけかもしれない
機能が十分にうまく分離されているので、再利用可能なライブラリとして切り出すのはとても簡単なレベルで、まだやることも多い。こういうものを Webフレームワークのデフォルト に入れたくなる。本当に良い記事だ
少し皮肉なことに、Firefoxではあるスタイルのせいで本文がまったく見えず、選択もできなかったので、リーダーモードに切り替えなければならなかった。見えたのはタイトル、ピンク色の引用マーク、コードブロックだけで、残りは見えなかった
修正: 下を見ると、たぶん自分の環境の問題らしい。文脈のために残しておく
記事自体はちゃんと読めた。開発者であれ最終ユーザーであれ、私たちは皆Reactの「俊敏性」のコストを払っている。会社で別のスタックを使えたらいいのにと何度も思った
また、著者の 共感力 と、それを「みんなが勝てる」構造として設計している点が印象的だ。気にかける姿勢は、結局は報われる
とても共感する。以前、JavaScriptが極端に多いブログを作ったのだが、JSベースの機能のせいで、ほとんど反乱が起きるところだった
まだHTML優先方式へ移行する時間は取れていないが、見た目には大体 HTML優先のWebページ のようにしてある
自分の分析データでも似たような結果を見た。直帰率は80%から約50%まで下がり、その後の記事の新規訪問者はほぼ2倍になった
最初にJSで作ったひどい実装のせいで、どれだけ多くの人が自分のドメインを一生避けるようになったのかを考えるとぞっとする。Webページやブログなら、これは最も重要な助言のひとつだ
このやり方は 自動フォーム入力 にも役立つ。以前、フォーム全体が動的で、各部分を識別する属性もなかったため、自動入力を作れなかった
機能性より見た目の良さを優先して過剰に設計されていて残念だったし、だからこそユーザー優先設計についてのこの記事は楽しく読めた
ここに SSEストリーミング と morph ライブラリを加えれば、動的・リアルタイム・マルチプレイヤーの機能もかなりうまく作れそうだ