🧑‍💻

KLab Server Side Camp 第 3 回 に参加してきました

2022/09/13に公開

KLab Server Side Camp 第 3 回 に参加してきました

9/1 ~ 9/7 の 5 日間、KLab Server Side Camp 第 3 回に参加してきました。

KLab Server Side Camp(クラブサーバサイドキャンプ)は、サーバサイド特化型の技術系インターンです。
本イベントの為にオリジナルで自社開発したスマホ向けゲーム(音ゲー)を題材に、そのゲームアプリの中でサーバサイドの技術がどのように使われているかを、講義形式で進めつつ実際に課題にも取り組み手を動かしてもらいながら経験を積むことができるサーバサイド特化型のインターンです。

http://dsas.blog.klab.org/archives/2022-01/52381462.html

応募

インターンの存在は、LabBase 経由でインターンの紹介メッセージを受け取りったことで知り、第 2 次の募集ではあったのですが応募してみることにしました。
参加しようと思った理由としては、このような感じで、ちょうどやってみたいと思っていたことと一致していたことが大きいです。

  • ゲームに関する開発の経験をしてみたかった
  • サーバーサイドエンジニアとしてのキャリアも考えてみたい
  • Python は書けるけど、サーバーサイドの開発経験は少ない

応募した時期が、第 2 次の締め切りに近い時期だった & 応募が多かった、ということから「選考に落ちても、気にしないで」と面談時に言われていました。
結果的には、選考通過していて、参加出来ることになりました。ありがとうございます。

選考は、書類とオンライン面談です。面接ではなく、面談なので、自分のことをアピールするのは書類がメインになると思います。やってきたこと、インターンにかける思いを詰めて提出すると良いと思います。後は、インターンのために早く動き出せると良さそうなことと、期間が近くても提出してみることをアドバイスしておきます。

5日間で学べた技術スタック

5 日間で学べた技術スタックは、こういった感じです。

  • GitHub Codespaces
  • Python
    • IPython
    • FastAPI
    • SQLAlchemy Core
    • Pydantic
  • MySQL

詳しくは、こちらにも記載されていますが、インターン期間中に触って感じたことをまとめてみます。

http://dsas.blog.klab.org/archives/2022-01/52381462.html

GitHub Codespaces

開発環境として、GitHub Codespaces を使っていました。初日は環境構築で終わることはよくある話ですが、GitHub Codespaces を使ったことで、詰まることがなくてとても快適でした。
期間中に GitHub が不安定だった[1]らしいのですが、作業時間には復旧していたために問題無く利用できていました。こういったハンズオンイベントなどを開催する時には、ローカルに VSCode さえあれば出来るので、上手く活用出来そうです。

GitHub Codespaces はブラウザから使うだけでなく、VSCode から Codespaces に接続して利用が可能です。このとき、VSCode から利用した場合のポートフォワーディングもいい感じにしてくれるし、一時的に特定のポートを public にすることも出来るのは知らなかったです。今回だと、他のインターン生のサーバーサイドの実装に接続してマルチプレイをテストする時は、この機能を活用していました。

https://docs.github.com/ja/codespaces/developing-in-codespaces/forwarding-ports-in-your-codespace#sharing-a-port

IPython

IPython は、python コマンドで利用できるインタプリタよりも圧倒的に扱いやすかったです。自分で調べていた時に知ったのですが、IPython.embed() でソースコード内に埋め込む事ができる機能は面白いなと思いました。

print デバッグの代わりに、IPython のインタプリタを埋め込んでおいて、インタプリタ上で見たい値を表示したり、値を変更したりといった使い方が出来ます。

例えば、この main.py は、1+2 の加算結果を変数 res に格納して、その値が 3 と一致しているかどうかをテストしています。この挙動を IPython.embed() して埋め込んだ IPython から res の値を 4 に変更しています。
この結果、assert でエラーを発生させる、といった事が可能です。

値の表示だけでなく、動的に処理を変更出来るのは Python ならではだな、と思いました。デバッグで上手く活用していきたいです。

FastAPI + Pydantic + SQLAlchemy

データ型を意識した開発がすごくやりやすいな、と感じました。Python は型の制約が緩いので、辞書型など扱っているデータが少し違っても動いてしまうことがあるのですが、その部分を Pydantic でカバー出来る感じでした。
FastAPI と Pydantic で、リクエストとレスポンスの型のバリデーション、SQLAlchemy と Pydantic でクエリの結果のバリデーションを実現出来ています。

やったこと

題材として与えられた音ゲーを 4 人でプレイ出来るところまで、サーバーサイドの実装を完成させることができました。インターン中の講義で取り上げられた MySQL の排他ロックを使って、ルームに参加出来る最大人数の 4 人を超えて参加できてしまわないよう考慮することにも挑戦しました。



しかし、ゲームのサーバーサイドとして提供するべき機能としては不十分で、

  • マルチプレイ中に途中退出したユーザの扱い
  • 不正なスコアになっていないか検証する

などを実装する必要があります。これらは、インターン期間中の課題としては早く出来た人のための追加課題といった扱いで、実際に取り組んで成果発表をしていたインターン生もいました。

僕は、今回のインターンを通して、Python で綺麗なサーバーサイドのコードを書く方法を知る、ということも目標にしていました。そこで、余った時間を使って実際に取り組んでみたので、学んだことをまとめてみることにします。

課題として与えられた音ゲーの機能の実装に関しては、他のインターン生の参加ブログを覗いてみたり、ぜひインターンに参加して挑戦してみてください。

作成したコードは、このリポジトリから見ることが出来ます。

https://github.com/Hiroya-W/gameserver

poetry を導入する

初期の状態では、利用しているライブラリのリストが requirements.txt に書かれている状態でした。これを、poetry を使ってライブラリのバージョン管理、仮想環境の作成を出来るようにします。

そのために、Dockerfile で poetry をインストールします。
poetry のインストーラは、デフォルトでバイナリを $HOME/.poetry/bin に配置します。devcontainer で利用する vscode ユーザを対象にインストールし、/home/vscode/.poetry/bin にパスを通しました。

https://github.com/Hiroya-W/gameserver/blob/04b9f4bc7868803a22d5355f5c572c69c89800d8/.devcontainer/Dockerfile#L18-L19

後は、必要なパッケージを poetry を使ってインストールしていきます。この時生成する pyproject.toml に、フォーマッタの blackisort、静的型チェッカの mypy の設定をまとめる事もできます。リンターの flake8 はまだ pyproject.toml に対応していなかったので、setup.cfg に書きました。

Swagger UIへ説明が表示されるように

FastAPI を使うことで、OpenAPI を自動生成し、Swagger UI 上で API ドキュメントとして表示することが出来ます。その中で表示される Schema 情報として、各パラメータの説明を表示することが出来るようになっています。

これは、Pydantic の Field を使って、description を設定しておくことで反映されるようになります。

https://github.com/Hiroya-W/gameserver/blob/04b9f4bc7868803a22d5355f5c572c69c89800d8/app/schemas/user.py#L15-L23

docstring とは違う書き方であるため、Field を使った場合は VSCode などのエディタ上でホバーした時に表示されるドキュメントには表示されないようです。docstring と Field の 2 箇所で管理するのは面倒そうですが、どちらでも見えるようにするには、2 箇所とも書くしか無さそうな印象でした。

複数行にわたるクエリ

Python では " を 3 つ繋げることで、複数行の文字列を定義することが出来ます。これを使えば、インデントをつけて整形したクエリをそのまま Python スクリプト内に記述できます。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/model.py#L234-L251

ファイル分割

用意された初期実装では、API の実装を ./app/api.py、MySQL へクエリを投げて処理する実装を ./app/model.py に書いていました。今回のサーバーサイドの実装では、大きく分けて userroom への API として分ける事ができ、結果としてこのように分割しました。

.
├── app
│   ├── __init__.py
│   ├── api.py
│   ├── config.py
│   ├── db.py
│   ├── dependencies.py
│   ├── exceptions.py
│   ├── model.py
│   ├── routers
│   │   ├── __init__.py
│   │   ├── room.py
│   │   └── user.py
│   └── schemas
│       ├── __init__.py
│       ├── room.py
│       └── user.py
└── tests
    ├── __init__.py
    ├── test_room.py
    └── test_user.py

プロジェクトの構造は、ドキュメントやテンプレートのリポジトリを参考にしました。

https://fastapi.tiangolo.com/tutorial/bigger-applications/

https://github.com/tiangolo/full-stack-fastapi-postgresql

api.py

router の追加、例外ハンドラの登録をしています。router は routers モジュール、例外ハンドラは exceptions.py に分離しています。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/api.py#L1-L25

dependencies.py

FastAPI で提供されている Dependency Injection の機能で依存性として追加する関数などを定義します。各 API を実装する関数で Depends(depends_func_name) のように利用される関数ですね。

今回は、簡易的に用意された認証用の関数 get_auth_token() をここに書いています。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/dependencies.py#L1-L11

exceptions.py

例外と例外ハンドラを定義し、ここで定義したものを api.py で登録をしています。これで、Python プログラムから InvalidToken を raise すると、HTTP ステータスとして 401 のレスポンスを返しています。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/exceptions.py#L5-L6
https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/exceptions.py#L17-L18

routersモジュール

FastAPI の APIRouter を使って、user API として routers/user.py、room API として routers/room.py のファイルを分割しています。このように prefix として /room を指定しておくと、デコレータでパスを省略でき、tag をつけておくと、Swagger UI でも tag ごとに分けて表示されるようになります。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/routers/room.py#L1-L24

schemasモジュール

API へのリクエストとして受け取る型、レスポンスとして返す型を定義しています。

https://github.com/Hiroya-W/gameserver/blob/3ccd890e20677137ff86a5472c2c7c646f0e67d4/app/schemas/room.py#L44-L54

model.py

インターン期間中に model.py の分割まで手を回すことが出来ず、そのままになってしまっています。これは、インターン後の課題として取り組んでみようと思います。

参加していただいたもの

たくさん頂きました!ありがとうございます!



感想

周りのインターン生は、サーバーサイドの開発経験がほとんど無い方ばかりだったので、同じ目標を持って課題に取り組む事ができてよかったです。

Server Side Camp というだけあって、サーバーサイドに専念できた 5 日間になりました。参加前は、サーバーサイド書けるようになりたい、と思っていたのが、インターン最終日にはサーバーサイド書けそう!と思えるくらいには自信がつきました。後は、たくさん書いて、経験を積んでいこうと思っています。

成果発表時は、1 人 1 人のコードの良かったところ、もっと工夫できるところを見ていって頂けたのはとても良かったです。同じことを実現するコードを書いていたので、こんな実装方法もあるんだと勉強になりましたし、良いところは真似していきたいと感じました。

また、成果発表で「良いコードを書こうという熱情が伝わってきました」ってコメントを頂けて嬉しかったです。これからも良いコードを模索していきたいと思います!

音ゲー、ネームカード、修了証書、どれを取ってもこのインターン用に書き下ろしているらしく、良いインターンにしてほしいという思いも強く伝わりました。
メンターさん、運営さん、今回のインターン生のみんなと参加出来て良かったです。ありがとうございました。

https://twitter.com/Hyuyu_kun/status/1567446740663676929

第4回もあるよ

KLab Server Side Camp 第 4 回が 2022/12/26(月)~2023/1/6(金)で開催されるようで、既に応募は始まっています!
気になった方はぜひ応募して、経験してみてほしいです。

<ウィンターインターン、エントリー受付中>
■「KLab Server Side Camp」(第 4 回)
https://klab-hr.snar.jp/jobboard/detail.aspx?id=MxhYoTHEWuM
日程:12/26(月)・27(火)・28(水)・1/5(木)・6(金)※平日 5 日間
第 1 次応募締切:10/3(月)23:59 まで

  • オリジナルの音ゲーを題材とした「サーバサイド」開発体験インターン
  • メンターは自社エンジニアの Python コアコミッターが務めます

#KLabServerSideCamp
#サーバサイドキャンプ

脚注
  1. https://www.githubstatus.com/incidents/wl09fvhb20x8 ↩︎

GitHubで編集を提案

Discussion