isyumi_netブログ

isyumi_netがプログラミングのこととかを書くブログ

『あのアーティストの代表曲は』の技術詳解

 

こういうWebアプリを作った。
https://famous-song.app/

本人は企画として面白いと思っている。
せっかくなので、どういう技術で作られているかについて解説する。

概要

まず、認証とRPCは全てFirebaseを使っている。
サーバーサイドはFirebase HostingとCloud Functions。
フロントエンドはTypeScript/React/Redux/typescript-fsaあたりを使った。
投票ページはSPAで、それ以外の結果表示ページはSSRしている。

意図

SSR

最近はSSR不要論も多い気がする。
ただ、フロントエンドでSPAと合流するようなSSRならともかく、ペライチのHTMLを生成するだけならSSRしたほうがロードが速いし実装も楽だと思う(そこに反対する人はいないと思う)。
SSRにはReactのtsxを使った。
tsxを使うと、引数にTypeScriptの型をそのまま使えるので簡単である。

SSRのCache-Controlにはこれを指定した。
public, max-age=10, stale-while-revalidate=1000
キャッシュが古くてもとりあえずCDNのキャッシュを返し、その間にCDNからCloud Functionsにアクセスしてキャッシュを入れ替える。
こうした理由はコレだ

  • Cloud Functionsはそこそこ重い
  • リアルタイム性が超重要というわけではない
  • ユーザーも、おかしいなと思えばリロードするくらいのリテラシはあると思う

コマンド化

フロントエンドからRealtime Databaseの公開データを直接書き換えるのではなく、
フロントエンドからサーバーサイドにコマンドを送って、サーバーがそのコマンドを元に公開データを書き換える仕組みにした。
こうした理由は、この方がバリデーションやアクセス制御の点で楽だからだ。

この方式には1個欠点がある。
フロントエンドでサーバーの処理待ちがしづらいことだ。
RESTであれば、POSTを投げてからサーバーで処理が終るまでグルグルを出しておくということが簡単にできる。
しかし、Firebaseでコレをやってしまうとグルグルを消すタイミングがわからないという問題だ。
そこで、サーバーで処理が終わったこともRealtime Database経由でフロントエンドに通知することに指定ある。
その部分を抽象化してあるので、フロントエンドはasync/awaitで簡単に処理の待ち合わせができるようになっている。

フロントエンドでの正規化

それなりに大きいフロントエンドであれば、フロントエンドでも状態を正規化して持つべきだ。
正規化というのはRDB用語かもしれないが、要するに

  • 値段は三桁ごとのコンマを入れずに数値で持つ
  • Dateはタイムゾーンを統一しておく
  • 省略可能なものに関しては必ず省略する
  • RDBと同じように関係で表せるものは関係で表す

というよううなことだ。
タイムゾーンに関しては、YYYY-MM-DDの文字列で持つというのも結構優秀だ。
省略可能なものというのは、例えば誕生日・現在時刻・年齢や直角三角形の3辺など、二つが確定すれば残り一個も確定するようなものに関してはその1個を省略して持つほうが扱いやすい。
関係で表すとは、例えば、商品一覧とユーザー一覧と購買一覧があるなら、無理にオブジェクトで親子関係を作らずに配列を三つ持つということだ。

重要な点は、そのデータがどのように使われるかをあえて意識せず、データとしての完全性を最優先した型で持つことだ。
一見、そのデータがどのように使われるかに応じて型を決めたほうが後の処理を楽に作れる気がする。小さなアリケーションならこういう考え方もあると思う。
しかし、そういう考え方だと早晩コードが散らかってカオスになる。データの使い回しがしづらくなる。
やはり、データは極力完全な形で持つべきだ。

タブレイアウト

僕は、タブレイアウトって素晴らしいと思っている。
昔rebuild.fmでもそういうことを言っている人がいた。
2ch専ブラのJaneStyleやTabtterなど、人気のツールはだいたいタブレイアウトだ。
だから僕もタブレイアウトにした。
Webというものはクモの巣状にリンクが広がっていくモデルなので、ネイティブアプリと違って階層構造で画面遷移を表現しづらい。
それならば全てはタブであるという一般化をしたほうが認知しやすい。

アイキャッチの自動生成

Twitterなどにリンクを投稿する時のOGPのことだ。
実装の詳細はここに書いた。
https://qiita.com/isyumi_net/items/ee94a5e2d963958eb515
頑張ってレイアウトを計算すれば画像処理の延長で生成自動化は可能だが、
今使っている技術の延長で画像を生成できるということで、puppeteerを使った画像生成をした。特にBootstrapを使えるのでデザインが統一できて良い。