はじめに
はじめまして、長谷川と申します。
2021/10/4 から 2021/10/29 の4週間、株式会社アカツキゲームスの『八月のシンデレラナイン』(以後ハチナイ)の開発を行うチームにサーバーサイドエンジニアとして参加させていただきました。
普段は趣味やアルバイトでWebとモバイルのアプリ開発をしたり、大学院で交通流や人流の解析の研究をしています。
インターン参加まで
アカツキゲームスのことはサポーターズの逆求人イベントで知ったのですが、アカツキゲームスのエンジニアはとにかく楽しそうにものづくりしてるよ〜と人事の方が話されており、興味を持ちました。
選考では主に今までの経験について聞かれ、特に友人と作ったプロダクトの開発をする時に考えていたことについて話したのがウケが良かった気がします。Railsを触るのはかなり久しぶり(&そもそも経験不足)だったので、参加が決定してから他の企業でRailsを使う短期インターンやハッカソンに参加しながら、事前準備をしてインターンに臨みました。
取り組んだこと
今回のインターンには(授業や研究で途中抜けしながら)4週間参加させていただき、主に以下の4つのタスクに取り組みました。
上の3つまでは軽く触れる程度にして、今回のインターン期間の約半分をかけて取り組んだ「チャプター情報一覧取得APIの高速化」について詳しく書いていこうと思います。
管理者画面の機能追加
この管理者ツールでアイテムの付与をできるようにする、というのが一つ目のタスクでした。管理者ツールは主に非エンジニアの職能の方が使うのですが、通常ユーザーに対してアイテムを付与するというのは強力な機能なので、手違いが起きないように運用フローを整えてもらう必要がありました。この部分でエンジニア以外の方とコミュニケーションを取ったのですが、こういう体験は技術とはあまり関係がないながら業務以外では体験しづらいのでいい経験になったなと思います。
マスターデータのバリデーション
(ハチナイにおける)マスターデータとは、選手の能力やショップの交換レートなどのユーザーの操作によって変化しないデータのことです。これと対になる概念として、獲得した経験値や所持しているアイテムなどのユーザーデータがあります。
ハチナイでは、このマスターデータに対して不正な値をもった選手や、イベントが発生しないようにバリデーションをかけています。不具合を未然に防ぐだけでなく発生した不具合が再度発生しないようにするのもマスターデータのバリデーションの役割です。今回のタスクでは過去に起こった不具合の原因を調査し、その不具合が起きないようにするためにバリデーションを追加しました。不具合の原因の調査は、1つ目のタスクと同じようにエンジニア以外の方とコミュニケーションをとりながら進めていったのですが、コードだけからは読み取れない運用ルールなどを知ることができて、コミュニケーションの大切さを学ぶことができました。
新規機能開発
2つ目のタスクが終わった時に「新規機能開発に興味ありますか?」とメンターの方に聞かれ「楽しそう!やりたいです!」と答えると、メンターの方が実際に業務で進めている新規機能の開発の一部分を任せてもらえることになりました。(新規機能については、公開されていない情報をかなり含むので詳細に触れることはできませんが、)テーブル定義、実装方針検討、エンドポイントの決定、API作成、テストを書く、など新規機能開発の一連のフローを経験できました。4つのタスクの中では最もユーザーにとってわかりやすいタスクだったので、自分が開発に参加した機能が実際にリリースされるのが楽しみです。
チャプター情報一覧取得APIのレスポンスを高速化
これが一番時間をかけて頑張った、かつ成果を出せたと思っているタスクです。このAPIはメイン画面から、試合ボタンを押した時などに叩かれるチャプター情報の一覧を返却します。実際のゲーム画面で言うと、例えば
から試合ボタンを押して
へ遷移するときに叩かれているAPIです。確かに言われてみれば、プレイしていても結構遅い。と言うわけで、まずは速度計測から始めました。僕の環境でのレスポンスタイムの計測結果が以下でした。
Completed 200 OK in 3957ms (Views: 2452.5ms | ActiveRecord: 251.4ms)
約4000ms。。。!早くしなくちゃ!と思い早速改善に取り組みました。
ViewsとActiveRecord以外の部分で1300msくらいかかってるのは流石に遅すぎない。。?Controller層の処理が怪しそうと思いそのあたりの処理の速度を測定するとビンゴ!チャプターに関連するアソシエーションを取得するpreloadが大量に連なっている所がとても重くなっていました。(僕はpreloadはN+1を解決するためにするんだから早くするためのモンだと思ってましたが、ハチナイくらいのサービスになるとレコードの量がすごいので、気軽にpreloadすると重くなってしまうんだな。。)その中でも特に遅い部分を調査していると、クリアスターの有無を計算する所が重くなっているようでした。ここはマスターデータだけで計算できる部分だったのでキャッシュに持たせるのが有効そうだと考え、早速実装してみると
Completed 200 OK in 2659ms (Views: 1866.2ms | ActiveRecord: 229.5ms)
といきなり30%ほど改善できました!
この時点まだインターンの残り期間が1週間あったので、さらに高速化したい!とさらに調査を進めました。
というわけで、遅い処理を特定するためにログを見ていると怪しい箇所をいくつか発見。bulletでは検知できない明示的でないN+1が発生しています。
ここのN+1を解消すると
Completed 200 OK in 2330ms (Views: 1739.6ms | ActiveRecord: 73.0ms)
と少し早くなりました。
また、遅い処理で改善できそうな部分を見ていくと、キャッシュをwriteした後は使われないアソシエーションがpreloadされているのを発見したのでそこのpreloadを削除。ここでインターンの残り期間がほとんどなくなっていたので、PRを短時間できちんと出せるような細々した改善点を探すためにログが汚くなっているところを見ていくと、同じようなN+1や無駄なキャッシュのreadを発見しました。これらもなんとか期間内に解消して少しだけ速度改善。これらは速度改善という点で見ればあまり結果は出なかったですが、ログは綺麗な方が気持ちが良いので達成感はありました。
最終的には
Completed 200 OK in 1871ms (Views: 1554.7ms | ActiveRecord: 28.8ms)
というレスポンスタイムになり、最初の4000msと比べると50パーセント以上の改善になりました!
業務を終えて&感想
成果発表
これにてインターンとしての業務は終わり、最後に成果発表会を行いました。
成果発表会では今までお世話になった方々からFBをいただけるのですが、直接は話していなくてもslackで僕のtimesチャンネルを見て、気にかけてくださっていた社員さんたちからも温かいコメントをいただいて、思っていたよりたくさんの方に見守られてこのインターンを走り切れたのだなと温かい気持ちになりました。また、「速度改善というタスクは新規機能開発などと違い、ユーザーに分かりやすいFBをもらえるようなものではないけど、サービスにとってすごく価値があることだからチームの私たちからたくさん感謝を伝えたい」というようなことを言っていただき、嬉しかったし、仕事の価値を認め合える空気があるというのがすごくいい環境だなと思いました。
感想
このインターンでは、人生で初めて大規模な開発に関われたり、色んな職能の方とランチしたりミーティングしたりなど、すごく良い経験をすることができたなと思います。またコードを書くばかりがエンジニアの仕事ではなく、エンジニア以外の職能の方とのコミュニケーション、仕様検討、原因調査などもエンジニアの大切な仕事であることを学べたのはすごく良かったなと思います。
また、メンターの方は自走を促すけど、困ったことがあればすぐに相談に乗ってくださり、僕にとって安心して挑戦できる&成長できる環境を整えてくださいました。この場を借りて改めて感謝を伝えたいです。本当にありがとうございました!