縮めてPOKEMON!!

https://github.com/hackz-megalo-cup/microservices-app

Go

TypeScript

Kubernetes

AWS

PostgreSQL

リアルなプログラミング言語POKEMONとレイドバトル!

さどるふ

warisuno

zatu

kfff

推しアイデア

プログラミング言語が3DでリアルなPOKEMONに変身! レイドバトルで協力してPOKEMONを倒し、個性豊かなアイテムを駆使して捕獲しよう!

作った背景

プログラミング言語をPOKEMONにしたらおもしろいとおもった。

推し技術

①マイクロサービスでドメイン領域ごとに独立実装 ②HTTP3に対応したWebTransportで高速リアルタイム通信 ③Kubernetes

プロジェクト詳細

POlymorpwhism KEnel MOdule Network (ポリモーフィズム・カーネル・モジュール・ネットワーク)

縮めてPOKEMON!!

推し技術!

Event Storming!

Event Stormingとは

複雑なビジネスプロセスやドメインの知識を共有、可視化、そして理解するための協同作業ベースのモデリング手法

なぜEvent Stormingを行ったか

今回のプロダクトを作るにあたり、プロセスが複雑であることが予想していた。 なので、誰がどのような行動を行い、どんなイベントが起こり、どんな流れで進行していくのかを把握する必要があると思い行なった。 始点はログインするところから始まり、終点はポケモンを捕まえるところ

初めてEvent Stormingを行ったが、考えないといけないことが多く大変ではあったが、チームメンバー間での認識のすり合わせや、考慮もれが潰れていったのでとても効果を感じた。 image image

Microservices!

こだわりポイント

Event Stormingで洗い出したドメイン領域ごとに、サービスを切っているため独立して作業を進めることが可能。 また、Apache Kafka互換のメッセージングブローカーであるRedPandaを使っており、Pub/Subのようになっているため、呼び出し元を知らなくて済む疎結合な構成になってい流。 他には、Argocdを使いGitHubを監視して自動でデプロイ(GitOps)したり、分散トレーシングのための監視基盤、 ゲームサーバー用にAgonesを使っていたり、k8sのCNIはカーネル空間で動くeBPFのCiliumを使用している。

基本的に、通信はgRPCを使っているが、ゲーム部分においてはHTTP/3 上で動くWebTransportを使用 (なお、iPhoneでは使えない; w ;)。 一部、WebTransportが使えない層のために、fallbackでWebSocketに繋いでいる。

image

k8s(Amazon EKS)

auth / gateway / capture / item / lobby / masterdata / raid-lobby / projector / game-server / frontend の全サービスをAmazon EKS上にデプロイ。ArgoCDがGitHubのmainブランチを監視し、マージと同時に自動でクラスタへ反映するGitOps構成を採用。k8sのCNIにはeBPFベースのCiliumを使用しており、カーネル空間でのパケット処理により低レイテンシなサービス間通信を実現している。ゲームサーバーはAgonesで管理し、バトルセッションごとにPodを動的にアロケーション・ライフサイクル管理している。

時間が厳しかったのでgemini産 image

開発がいど

image

CI基盤

commit前、PR、mainマージ後にCIが動く これで本番環境でのエラーを未然に防げた

  • commit前: pre-commitフックでlint / format(Go: golangci-lint・gofmt、Frontend: Biome)を自動実行
  • PR時: contract(buf lint + breaking change検出)/ go-check(ビルド+テスト+race検出)/ frontend-check(tsc + Vite build)/ node-check の4ジョブが並列で走る
  • mainマージ後: 上記に加えて nix-build(各サービスのDockerイメージをghcr.ioにpush)と render-manifests(K8s YAMLをNixidyで自動生成)が動き、ArgoCDが差分を検知して本番クラスタへ自動デプロイ
  • 差分に応じて実行するJobと実行しないJobを設定した image

がんばった。

Github Actions

ジョブ回数: 1,401回 実行時間: 2,281分38時間 image

UI

UIをpencilを使って作成した。 imageimage

Issues

実施したイシュー数: 228件 送信したPR: 161件 image

image

Discord

チーム開発をするにあたって、Discordの鯖を整備した

openclaw

gpt 5.3 codexで動かしていたので、コーディングだったり、日常会話をした image

Webhook

PRをたくさん作る開発フローにしたので、PRが作られたことがわかるようにdiscordで通知飛ばすようにした image

頑張ったこと

  • イベントソーシング + Sagaパターンの共通基盤化: 全Goサービスに event_store / outbox_events / idempotency_keys / snapshots の4テーブルを統一仕様で実装。Transactional Outboxパターンにより「DBへの書き込みとKafkaへの発行が不可分」な設計を実現し、at-least-once配信保証を達成した
  • 耐障害設計の3層積層: サービス間呼び出しにCircuit Breaker(gobreaker)→ Bulkhead → Retry(指数バックオフ)を積層し、部分障害がカスケードしない構成をplatformパッケージとして共通化した
  • Proto-firstな開発フロー: buf v2でProtoを唯一の真とし、Go(connect-go)とTypeScript(connect-query)の両クライアントを自動生成。型安全性をフロントエンドからバックエンドまで貫通させた
  • 経験のなさすぎる開発手段: gRPCを使ってprotoを決めて自動生成してもらうプロセスのすべてが初めてで理解が追い付かず、非常に難しかった

開発体験を向上させるための工夫

  • devenv.nixとnix-direnvを使って開発ツールを統一
  • Tiltfileを使って、ローカルでk8sの開発をサポート
  • ci/cd
  • gitops
  • precommit
  • Devin review

難しかったこと

  • WebTransportのブラウザ対応: HTTP/3 + QUICが前提のWebTransportはiOS Safariで動作せず、最終的にWebSocketへのfallbackを実装したが、双方の接続状態管理・メッセージスキーマの共通化が設計上難しかった
  • 分散トレーシングのコンテキスト伝播: OpenTelemetryのトレースコンテキストをgRPC(connect-rpc)・Kafka(Watermill)・HTTPの3経路すべてで正しく伝播させる設定が難航した

苦労したこと

  • Goの開発とマイクロサービスが始めてで開発に入るまでのキャッチアップに時間がかかった
  • Devinのレビューが優秀過ぎて毎回指摘される
  • Godotにコメントにピリオドが無いことを指摘される
  • WSL特有のパス系のエラーに苦しんだ
  • armでは動くのにx86だとうごかねぇ。。
  • WSLエラー: Windowsのファイルパス(C:\...)とLinuxパス(/mnt/c/...)の混在でDockerのvolumemountが壊れ、原因特定に時間を溶かした
  • Godot: コメントアウト末尾のピリオド欠如を毎回指摘された

いろいろ

Devinに勝った

image

疲れた

チームメンバー4人中3人が東京周辺から来ている。 非常に困憊している。 しかしながら、うちのリーダーの福岡出身のthirdlfさんは2徹して開発しているため、東京勢の疲労とは比べ物にならないのである・

さどるふ

@thirdlf03