世の中のHTML5アプリケーションが糞だから、俺が「初期化」の作り方を教えてやんよ
2chまとめみたいなタイトルにしてみた。(してみたかった)
HTML5のアーキテクチャと初期化とキャッシュの考え方が、「ウェブエンジニア」は本当に出来てない。
とくにソシャゲをウェブビューに貼ってスマホ対応しました系。本当にダメ。
じゃあどうするか?基本的に「初期化」の考え方を直せばどうにかなる。
(この記事はBackboneを使うときに考えてることだけど、他でも一緒だと思う)
前提
- シングルページアプリケーション
- セマンティクスやSEOは考慮しない
基本哲学
- 共通モデルの初期化を徹底的に行う
- サーバーにリクエストを投げるのは最小限
- クライアントでサーバーモデルのキャッシュを作り、更新が期待されるまで再取得しない
理由
いくらDOMの最適化したところでUXに影響が大きいのはサーバーリクエスト(200~2000ms)で、プログラミング段階で辛さがあつまるのは非同期処理の部分。 プログラマとしては、非同期処理はクライアントMVCのコントローラ的な部分に集約し、それ以外(描画)は同期的に行う。 基本部分を何度も使いまわすことで、モデルの同期(非同期処理)を最小限にする
サーバーとクライアントの役割
まずリッチアプリケーションのための、サーバーの役割を確認する。
これだけ。ビューは一切触れない。必要なのは静的データの配信と、REST API/RPCだけ。(もちろん他にも認証とかあるけど省略) 利点は、モデルのビジネスロジックに専念できること。ビューのテスト不要。
クライアントの初期化処理
適切にやると次のような手順になる。
- 共通モデルの初期化
- 現在のステート特有のモデルのリクエスト
- ビュー構築用のオブジェクト生成
- ビューの描画
- DOMにイベントハンドラ付与
- ビューイベント or ポーリングイベントの待機
アプリケーションの共通モデルと、状態特有のモデルは、徹底機に分離しよう。 ここで、ダメなアプリはページ遷移時に共通モデルの初期化まで戻ってしまう。ちょっとしか触ってないけどガールフレンドかっこなんとかそうだった。 何度も使うモデルを取得してしまうと、UXを著しく落とす。そのモデルは既にもってないか?という発想を常に持っておく。
イベント待機状態でイベントが来たときの段階を確認する。
- コントローラがモデルのメソッドを叩く or モデルに対してイベントを発火
- モデルの変更に応じてオブジェクトを再生成
- 関連ビューの再描画
- イベント待機
ここでいうイベントとは、クリックやルーティングを指す。オールドスタイルなWebならルーティングのみがイベントだったが、今では「多くあるイベントのうちの一つ」である。ここの発想がない人が多い。
ビューが属するドメインを意識して、必要なビューだけ再更新する。必要とあらばDOM操作で直接書き換えてもいいが、経験上、テキスト以上HTML未満にしておいた方が良い。
まとめ
一連の流れをまとめる
- サーバー: index.htmlを返却
- クライアント: DOMのロード(bodyのload)
- クライアント: 静的データのロード
- クライアント: 共通オブジェクトの初期化
- クライアント: ステートに応じてAPIを叩く
- サーバー: REST APIからJSON生成して返却
- クライアント: モデルから描画に必要なオブジェクトを生成
- クライアント: HTMLに描画してイベントハンドラ付与
- クライアント: ビューイベント待機
- サーバー: リクエスト待機
イベント発生
- クライアント: リクエストが必要な場合、APIを叩く
- サーバー: なんかする
- クライアント: 「モデルから描画に必要なオブジェクトを生成」に戻る
サンプルコード書こうとしたけど飽きた。 たぶん、最初にビューごともらってない分、最初の一回のロードは長くなる。だけど、それ以降はだいぶ早くなるはず。
リッチアプリケーションなんだから初回ロードぐらい長めに取らせろ。ローディングバー出すから。以上。
おまけ:モデルの副作用と成功を前提にした非同期
モデルに副作用を起こすAPIを叩く場合、「成功を前提に」リクエスト結果を待たずモデルを書き換えてしまうという方法もある。非同期に処理結果が返却された時は初期化したりなんなりでリカバリーする。
だいたいリクエストに失敗したときは整合性崩れるからリロードしても良い場合が多い。
が、エンバグしたときが辛いので、次のRESTで取得すべきモデル状態が予測可能で、その処理をまたぐ場合に素早い状態遷移が必要なときだけでよい。