ICFPC2021 感想

Special Weekend ってチームでダッシュボードっぽいやつを書いてました。バックエンドは Go、フロントエンドは React で書いてました。今回は本当に問題にノータッチだった……

仕事では HTML や JS 関係を全く触らないし、もっと言えば Docker も RDB も触らないという環境なので、ICFPC が唯一の触る環境だった感じもあります(社内に Docker じゃないコンテナフォーマットとか、Kubernetes の前身のコンテナオーケストレーションシステムとか、RDB の皮を被っているようでで被っていない DBMS などがある)。チーム変わってから Kubernetes とか AWS とか Azure を使い始めたので、そこらへんはわかってきた。

コンテスト前におさけーさんが React とか Material UI とか使うと適当に UI が作れて便利〜って言っていたので、当日ぶっつけ本番で Create React App ってやつをベースに適当に作りました。また、当日にぶっつけ本番で GKE を初めて使い、ほぼ初めて SQLite と MySQL を使ってバックエンドを作ってました。使った Tech stack の中で、Go と Kubernetes のジェネリックな部分だけがちゃんと知っているところだった気がする。

以下、記憶があるうちに箇条書きでどんなことをやったか:

  • とりあえず問題を解く班と解かない班(解かない班とは)に別れて、解かない班は手動 UI とダッシュボードを作る感じに。自分はダッシュボードをやる感じに。
  • 最近は Kubernetes を触っているし、GKE でいいやろって思って適当に GCP Project を作って GKE Autopilot でクラスタ作成。
  • ご自宅に立ててる Go のサーバー向けに使ってた Dockerfile をコピペして、Go が動くイメージを作ってデプロイ。マネージド Kubernetes 使ってると Service とか Ingress あたりがうまく統合されていて、ロードバランサーとかも適当に作られて便利。
    • あと GKE は Cloud Console から適当に Kubenetes オブジェクト見れることができて便利ですね。
    • でも Network Endpoint Group あたりのアタッチが遅い気がする……
    • ここらへんは Prober を適切に設定することで、改善した雰囲気もある。
  • 作らない班でデータどうしようか話す。みんなして「データベースは持ちたくない……」って話をする。これが仇になってあとで MySQL へのマイグレーションをすることになる。
    • 話の中では Git をデータベースとして使えばいいんでは、ってなって最初はそういうコードを書こうと思ったけど、途中でやっぱそれも面倒くさくなって Persistent Volume + SQLite という構成にした。
    • Git サーバーをやっていた身としては Git をデータベースとして使うのは万死に値する行為だけど、使う側からすれば便利っぽく見えるよね……
      • Git サーバー側からすれば、たかだか一秒に N 回(しかしフルで clone される場合もある)みたいな要件と、一秒に 1000×N 回(ただし 1 ファイルしか読まない)みたいなのが混在したトラフィックは超厳しいです……まぁ現実には 1000×N 回フル clone が一秒間に同時に来て死ぬんですが。
  • 雑に SQLite でデータを保存するやつを、マニュアル見ながらせこせこ書く。DB ファイルと問題と回答のファイルは適当に PV へ。
  • git push したあとに git fetch したら Go のコードはきれいになっていて、React のコードは TypeScript になっていた。すごい。
  • git push したあとに git fetch したらビジュアライザが勝手についていた。すごい。
  • Kubernetes は Secret あたりの管理が楽でいいなぁと思う
  • JavaScript よくわからないなぁって話をした気がする。Java とか Go はなんだかんだ言って仕様を読むと良いんだけど、JavaScript は ES の仕様を読むといいんだろうか、みたいな話をした。
  • 回答のバリデーションとか Dislike の計算をサーバーサイドでしたいけど、そのコードは Rust で書かれている…… 妥当なのは Dockerfile で Rust のバイナリをビルドするんだけど、どうせそんなに更新されないしな、と思ってバイナリをレポジトリに突っ込む。ギルティ。
  • 公式サイトから Minimal dislike をとってくるコードとかすでに submit された回答を scrape するコードをサーバーサイドに移植して定期的に走らせる。
    • ここらへんが API としてアクセス可能ではなくて厳しい。去年は一応すべてが API でアクセス可能だったので非常に良かった気がする。
  • ダッシュボードから公式に submit できるようにする
  • なんかデプロイするとダッシュボード(API)サーバーが一時的に落ちたりとかするのが厳しいという思いが出てくる。しかしデータベースが SQLite だったり、PV が ReadWriteOnce だったりしてレプリカ作るのは厳しい。そこにちょうどタスクキューシステムを Cloud SQL で動かすということになったので、データをすべて Cloud SQL の MySQL にマイグレーションするってことをやる。
    • 泣きながら MySQL のドキュメントを読んで SQL を書く。
    • 特に問題なくマイグレーション完了。ダウンタイム 20 分ぐらい。
  • ついでにフロントエンドのデプロイとバックエンドのデプロイを分けたい、という思いから分ける。バックエンドはフロントエンドの asset サーバーのプロキシとして動作するようにして、フロントエンドの asset サーバー単体で更新できるようにする。
    • まぁこれは API サーバーを最初から別ドメインで運用しておけばよかった気がする。
  • ダッシュボードからタスクキューに投げるボタンをつける
  • ダッシュボードが重すぎる
    • なんか Chrome のプロファイラすら動かない……と思ったら useEffect の部分があれで無限ループになってる部分があった。
    • それでも重いと思ったけど、ちゃんと Warning みて key をつけたら軽くなった。なんか想像するに React の仮想 DOM 計算時に key をベースにして計算を省いている部分がある?
    • あと、ダッシュボードが実質全回答をサーバーから取得するようになっていて厳しい。が、これは最後まで手をつけられず。まぁ数人しか使っていないサーバーだし……

以下、事後の感想:

  • なんか今年は FP な雰囲気が弱かった……気もする。まぁ毎年問題は FP と関係ないようになってる気がするけど、どこかしらに FP っぽいなにかが散らばってたような気もする。
  • JSON とかテキストで表現された問題郡に対して、色々JSON とかテキストで回答を提示し、それに対するメタデータ(点数とか)をつけてランキングをつくったりタグ付けしたり、というダッシュボード要件は変わらないんだから、パッとできるようになっておきたい。なっていたい……
    • まぁそれはタスクキューもそうだね……
    • もしかしたら雑に Mongo とか使うとこういうときは楽なのかもしれない
  • GKE と Cloud SQL はよかった
  • React 便利だったけど、当日ぶっつけでコピペしながら使ったので、微妙にこれ使い方違ったなってところがあったりする。あと Redux とかでグローバルな状態をそっちに押し込んでおけば良かったみたいな気持ちもある。
    • まぁでも 1 分ぐらいしか触ってない人でも、とりあえず見れるダッシュボードが作れる仕組みは良いですね。
  • RDB を脳死で使えるようになったほうがいいなぁ、と思いつつ、仕事で使わないと微妙にモチベーションがわかんのだよな…… Spanner で Query 書くのそこまで推奨されてないし、Query 書くのは Dremel 向けだし……
    • あと Spanner はスキーマ定義だけすれば、あとは差分が自動で適用されていいなぁと思いました。まぁ Spanner は Spanner で(というか地域分散する都合で)主キーの設計あたりで微妙に別プラクティスがある気がする(e.g. 番号が連続したキーを作らないとか)。
    • まぁ ICFPC で普段使わないツールを使ったり、チーム変わって違うツール使ったりするけど、なんだかんだ言ってすぐ使えるようになれてるので、必要になったら学ぶでも普段は問題ない気がする。こういうコンテストみたいに「今すぐ必要」みたいなときに、やっときゃよかったって思う。

こうやって見返してみると、本当に問題にノータッチだったな。まぁ問題ノータッチでも参加して楽しめるってことで。