こんにちは。アカツキゲームス新卒採用担当の藤元です。
先月7/7(木)、七夕の日にアカツキゲームスではエンジニアを志す学生さま向けにLT会を実施しました!
※ LTとは:Lightning Talkの略で短いプレゼンテーションのこと
▼イベント概要はこちらから
https://aktsk.connpass.com/event/239674/
続きを読むこんにちは。アカツキゲームス新卒採用担当の藤元です。
先月7/7(木)、七夕の日にアカツキゲームスではエンジニアを志す学生さま向けにLT会を実施しました!
※ LTとは:Lightning Talkの略で短いプレゼンテーションのこと
▼イベント概要はこちらから
https://aktsk.connpass.com/event/239674/
続きを読むどうもnamekosiruです。今回は7月11日~7月29日(3週間)の期間にアカツキのクライアントエンジニアのインターンに参加してきたのでそれについてのブログを書いていこうと思います!!
私は現在奈良先端科学技術大学院大学に所属する修士1年の学生です。開発経験としてはインターンやアルバイトでデータ分析、ML*1開発を中心に行っていました。その裏で細々とサーバーサイドの開発もやっていたような経歴になります。 今年の4月ごろから就活を考え始め、幼い頃から今までずっとやっていたゲームの開発に携わりたいと思いゲーム業界を中心に就活をしています。
アカツキさんのインターンに参加しようと思った経緯について話します。
夏のインターンではゲーム業界の開発を学べるようなインターンを探していました。
また、私はインターンを探す上で以下の2つの軸を中心に探していきました。
探しているうちに逆求人などでお会いしたアカツキさんの社風やインターン内容に惹かれました。アカツキさんではコアバリューとしていくつか掲げている原則がありますがその中に
という原則があります。この部分が自分の軸と非常にマッチしていると感じインターンシップに応募する形になりました。面接を通じてチーム開発に対する考えやゲームに対する思いを話したところ採用という形になりました。
インターン中に何に取り組んだかを話します。
インターンではあるタイトルのクライアントチームにクライアントエンジニアとしてジョインさせていただくことになりました。インターンでは「開発者が喜ぶデバッグ機能の開発」に取り組みました。具体的な内容は以下の通りです。
上記の内容を以下の4つの流れで取り組みました
始めに工数見積では改善要望シート*3から自分の取り組むべき課題を選定しました。ここでは以下の3つの観点で選定を行いました。
開発日数では実際のその機能を開発するのにどのくらいの日数がかかるかを考慮します。ゲーム開発は機能やタイトルのリリースに締め切りが設けられていることが多々あります。そのため「どの機能をいつまでに」開発するかを見積もることは非常に重要になります。そのため機能開発を始める際に無計画に開発するのではなく、マイルストーンを要所ごとに設けて開発を進めていく必要があります。
技術力では今回のインターンに限った話ではありますが3週間という短い期間で最大限のアウトプットを出さなければなりません。そのため「自身の技術力で本当に実装ができるのか」、「実装が期間内で終わるのか」などの要素を考慮しなければなりません。
改善要望の優先度では「その機能がどの程度必要とされているのか」を考慮します。優先度が低いものよりも優先度が高いものの方が重要度が高いの至極当然です。そのため優先度を考慮して本当に必要とされている機能を選定する必要があります。
上記のような観点で工数の見積を行いました。技術力の観点では正しく見積をできなかったので後々にモブワークという方法で機能の開発をしました。
さて実際に取り組む課題を選定した後は要望者に実際にヒアリングします。
始めにヒアリングをする際に必ずすることは要望の背景・目的を聞くことです。これを行うことで前提をお互いの認識の誤差を減らすことができます。また、自らアイデアを提案する場合でも背景や目的を知っていることでより良いアイデアを提案しやすくなります。加えて、画面共有や動画などを用意して相手にわかりやすく伝えることも非常に重要です。
そしてお待ちかねの実装です。さあ書くぞという意気込みでコーディングに取り組みました。しかし、私の場合機能の実装が難しく一人ではできなかったです。そこで他のクライアントメンバーに協力を要請してモブワーク*4を行いました。モブワークでは自分がドライバーを務め、他のメンバーからの指示をもとに機能の開発を行いました。モブワークでは普段知ることがない 暗黙知*5を知ることができたのが非常に新鮮でした。エンジニアの視点や考え方、細かいTipsなどはドキュメント上に中々書き起こすことができません。そのため他のエンジニアの考え方を学ぶ機会としてモブワークは非常に有効です。
最後にコードの品質を保つためにレビューを行います。レビューでは機能の実装方法や変数名などを細かく見られます。印象に残った言葉として「命名をつけにくいのは設計そのものが良くない」が挙げられます。個人開発やチームのハッカソン開発で命名をつけにくいことがしばしばありました。この当時は自分が命名をうまくつけられないだけと考えていました。しかし、本当の原因は設計そのものが良くなかったことにありました。普段から命名を意識することで設計全体の良し悪しも図ることができるのには非常に驚きました。
また、作った機能を要望者の方に画像や動画を用いて確認をしてもらいます。作った機能を再度確認してもらうことで本当にその機能が要望者の要求を満たしているか確認できます。実際に作った機能は作って終わりにするのではなく、作った機能に対して確認&フィードバックもらい更により良いものにしていく必要があります。
実際の運用されているゲームの大量のソースコードの読むことには面くらいました。普段インターンで読むことも多くあるのですがそれと比にならないくらいすごい量のソースコードが管理されていることがわかりました。インターンの課題に取り組む際も取り組むべき場所をその膨大な量のコードから見つけてこなければならず非常に困難でした。しかし、私の参加したプロジェクトでは非常に命名にこだわってコーディングされているので読み込む上でそれらの名前が非常に助けになりました。
そのため複雑なシステムになるほど名前にこだわっていくことは大切だと感じました。また、この話はソースコードに限った話ではありません。プルリクエスト、コミットメッセージ、Slackでの文章あらゆる場面でこの可読性を意識しなければなりません。常に自分のメッセージを読んで「適切な量の情報を適切な相手にわかりやすく伝えることができているか」を意識し続けることが可読性の向上に繋がっていくのだと強く感じました。
膨大な量のソースコードを読んでいるとついつい時間が過ぎてしまうことがありました。そのためインターン始めの方は非常に作業効率が悪かったです。そこで私はタスクごとに時間を見積何をしなければならないのかを週単位と日単位でスケジューリングしました。これらを行うことでついつい眺めているだけになりがちなコードリーディングを効率よく行うことができました。また、その日ごとにTODOを設けて課題に取り組めた点も非常によかったのでこれからも続けていきたいなと思いました。
インターン期間中によく言われたのが「たくさん学ぶ」ことでした。この学び方については二つの学び方があると思います。一つ目は単純に学びの量を増やす。二つ目は学びを抽象化して他のことに応用する。この二つ目を特にインターンで得られました。社会人になると自由に使える時間が減り一つ目の「学びの量を増やす」のは難しくなります。しかし、エンジニアの職業柄たくさん学ばなければなりません。時間が少ない状況で学ぶことを実現するためにこの学びの抽象化は非常に重要です。日常的に経験することからその経験を抽象化して新たな物事に応用することが「たくさん学ぶ」ことに繋がります。この「学びの抽象化」はエンジニアに限らずに行えるのでこれからも積極的に行っていこうと思います。
メンターの伊藤さん、クライアントメンバーのみなさん、プロジェクトの皆さんのおかげで多くのことを学ぶことができました。3週間という短い間でしたが本当にありがとうございました!
初めまして、2022年の7/4~7/29の3週間、アカツキゲームスのサーバーサイドインターンに参加させていただきました、白木といいます。この記事では、私が取りくんだこと、学んだこと、参加してよかったことについて書かせていただきたいと思います。
名古屋工業大学大学院工学専攻情報工学系プログラムの修士1年の白木です。普段はTLSの研究、Go言語を用いた開発を行なっています。自宅でLinuxを搭載したサーバでアプリケーションを動かしたりもしています。
今回のインターンで私が配属させていただいたプロジェクトは、Ruby on Railsによるゲームのサーバチームでした。インターン開始前の事前面談で私の経験してみたいことをふまえ、「大規模システムの負荷改善」のタスクに取り組むことになりました。以下がインターン期間に取り組んだことです。
実際にN+1問題が発生したAPIのログを見ると、下記図のような現象が起こっていることが判明しました。
これは、example_func関数の内部のusers.selectでusersテーブルからuserのデータ取得をを行うクエリを1回発行し、そして、ループでn_func関数を呼び、取得したユーザデータと紐付いたarticlesを得るクエリをN回発行する状態示した図です。
下記図のような、ループ開始前に、userと紐付いたarticlesをincludeメソッドを用いて予め取得しておくコードを書き、冗長なクエリを除去し、問題を解決しました。
RailsのActiveRecordにはEager loadingと呼ばれる機能があります。これは、予め、アソシエーションしているテーブルのデータをメモリ上にキャッシュすることができます。そのため、ループ開始前に、ループ内部で将来的に使われるアソシエーションをEager loadingすることにより、クエリの発行回数を減らすことができます。今回は、このEager loadingを使いました。
この評価結果は、負荷試験環境で計測したものであり、実測値ではありません。クエリの発行回数は、N+1問題解消時にはN+1問題発生時の0.4倍ほどに抑えられていることがわかります。この変更によって、大量の同時リクエスト発生時にも、データベースへの負荷を最小限にとどめることができます。
N+1問題発生時 | N+1問題解消時 | |
---|---|---|
クエリの総呼び出し回数 | 279 | 108 |
ソースコードとログの規模が大きく、処理の中で様々な関数が呼ばれることから、N+1問題の発生している処理が書かれている箇所を探すのに苦労しました。また、メンターのyasuさんとのモブプロを通じたRailsのデバッグ方法・ログの解析方法、N+1問題の対策を講じていたが、コードが複雑になっているが故に一部解決できていなかったのを目の当たりにし、エンジニアが実装時にN+1問題の発生に気付きにくいということも学ぶことができました。
今回、私がN+1問題の解決に取り組んでいたのは新しいバージョンの機能改修の箇所です。実は、この改修はあるAPIの負荷を減らし、パフォーマンスを向上させるものでした。そのため、その機能改修によってAPIが前のバージョンと比べ、適切に直っている、また、新たに負荷懸念となるようなAPIがないか調査をするために、負荷試験を行いました。
Locustというツールで負荷試験シナリオを記述し、実施しました。クライアント側から90分間、負荷を与え、その結果をNew Relic、Cloudwatchのメトリクスを見ることで、調査をしました。機能改修箇所は、意図されたパフォーマンスを示し、新たに負荷懸念となるようなAPIは見つかりませんでした。
私が、負荷試験を実施したことがなく、負荷試験の勉強をするところから始めました。前バージョンの負荷試験の結果、メンターのyasuさんの助力もあり、なんとか苦労しながらも理解することができました。また、私がAWSの使用経験がなく、AWSが提供するサービスの知識不足により、色々とハマったりもしました。しかし、苦労はしましたが、非常に良い経験ができたと感じています。学生のポケットマネーでは、クラウドサービスの学習に対して投資することが困難な場合が多いです。そのため、AWSのサービスを触ることができたこと自体にも大きな価値があると思いました。
APIを処理するアプリケーションサーバでは、ログをとっています。このログは、APIの解析、障害時の原因究明をするために用いられており、重要な役割を担っています。このログをDBで管理しているのですが、以前、このDBに問題が発生しました。int、unsigned int型でauto increment属性を付与しているテーブルで、idがオーバーフローをし、ログをDBに保存することができなくなるという問題が発生しました。そのため、エンジニアがこの問題に事前に気が付けるように「ログのDBのidがオーバーフローする前に検知し、slackに通知を投げるシステム」の開発が必要になりました。
本番環境と接続しているDBで、先述のオーバーフローを検知するrakeタスクは既にあります。そのため、この実装を利用し、ログDBのオーバーフロー検知を実現させます。auto incrementの値を取得して、閾値を超えているかの判定処理を、関数化してログDBにも適用させました。時間が足りず、テストの修正ができませんでした。
ログDBをどのように扱うかについて苦労しました。ログDBはRailsのAPIサーバと接続するものでないため、どのように接続させれば良いのかが全くわかりませんでした。しかし、過去にログDBに接続を行う処理が書かれていたため、それを参考にして、解決しました。また、既存の処理を関数化させる際にも、多くの問題を起こしてしまいました。処理を抽象化させる際に、綺麗にさせることを意識していなかったため、非常に汚いソースコードを生成してしました。そのことをレビューで指摘されたため、今後、しっかりと目を向けていきたいと思いました。 また、閾値を決める際に、本番環境のデータの集計するクエリを発行しました。この結果を見た際に、私の想像を遥かに超える数が集計され、インターン期間に携わってきたシステムの規模の大きさに驚きました。
このインターンで当初、取り組みたかった大規模システムに携われることができ、非常に楽しい時間を過ごすことができました。技術的な学びは先述の取り組みの中で多く得られました。手を動かした箇所だけでなく、データベースのシャーディングさせて、アプリケーションを動かしているのを見て、大規模システムを支える技術を見ることもできました。その他の学びとして、アカツキゲームスが採用しているスクラム開発も経験することができました。デイリースクラム、スプリントレビュー、スプリント・レトロスペクティブ、スプリント・プランニングに参加することで、よりスクラム開発への理解が膨らみました。そして、実環境で運用される機能開発をインターンで行うことができ、いい意味で緊張感のある開発を行うことができました。
最後に、メンターのyasuさん、そして、技術的なサポート、ブログ執筆のお手伝いをしてくださったプロジェクト関係の皆様、ありがとうございました!
はじめまして!7 月 4 日から 7 月 22 日にかけて、株式会社アカツキゲームスのインターンシップにバックエンドエンジニアとして参加させて頂きました、菊池と申します。
本記事では、私がインターンシップの期間で取り組んだ課題を紹介すると共に、インターンシップを通じて感じたこと等を書いていきたいと思います。この記事がアカツキのインターンシップへの参加を検討している方の一助となれば幸いです!
こんにちは、若松と申します。
今回は、2022年7月4日から22日までAkatsuki Games Internship 2022のGo/GCP コースに参加させていただきました。
インターン情報 aktsk.jp
目次
Akatsuki Games Internshipの存在を知ったのは、2022年の3月でした。 とある、面談イベントでAkatsuki Gamesの人事の方と一度お話しする機会があり興味を持ちました。
自分が今回配属されたチームは、Akatsuki Gamesの基盤開発を担っている「ATLASチーム」でした。
業務内容としては、ゲーム内通貨管理基盤の開発に携わらせていただきました。
通貨管理基盤は、図1のような構成になっています。
通貨管理基盤は、Goで開発され、App Engine上で動いています。また、管理者がダッシュボード上から各ゲーム内通貨の状況を確認するための管理画面は、Python(Flask)で実装されており、Cloud Run上で動いています。
データの管理などには、Sercret Manager、Datastore、Cloud Storage、Big Queryが使用されており、インフラのリソースはTerraformで管理しています。
参加時期が前期の末だったので、大学の課題や研究と並行しての参加となり、実際に稼働できたのは2週間ちょっとでした。
(大学と並行して無理のない範囲で柔軟に対応して、参加させていただきました。)
その間に自分は、以下の2つのタスクに取り組みました。
支払い情報検証用キーのバリデーション
Load Balancerを設置することによる、システムの拡張性の向上
修正対象となる部分は、Google Play Storeでの後払い購入された際の購入情報(後払いレシート)の検証フローでした。
Google Play Storeで後払い購入を有効にしたサービスには、後払いレシートを検証するためのキーが発行されます。
一連の流れとしては、サービス公開前に発行された検証用キーを通貨管理基盤に登録する。サービス公開後、ユーザーがゲーム内通貨を購入した際に、検証用キーを用いて後払いレシートを検証するという流れでした。
自分は、サービス公開前に検証用キーを登録する際の処理に、キーの検証処理を実装しました。
登録をリクエストされたキーを用いて、Play Storeの検証用クライアントを生成できるか検証することでキーの検証処理としました。
2つ目は、システムを変更に強い構成にすることを目的としたタスクに取り組みました。
最終的な構成としては、App Engine(通貨管理基盤)をLoad Balancer経由でアクセスできるようにすることで実現しました。 通貨管理基盤は、複数のプロジェクト(リージョン)で運用されており、それぞれのプロジェクトごとにロードバランサーの設置の有無を選択可能にしたいという要件もありました。
それらの要件を加味した上で、最終的に図2のような構成で実装しました。
従来の構成では、App Engineにデプロイした際に発行されるURLをクライアントに叩いてもらうことでリクエストを送ってもらっていましたが、システムの構成を変える際に、変更の度にリクエスト先を修正する手間をクライアントに要さないために、新しく通貨管理基盤用のドメインを取得しました。
ドメインの取得には、Google DomainsとCloud Domainsの利用が考えられましたが、Cloud Domainsを採用しました。
採用理由は以下のようなことが挙げられます。
ただ、現在TerraformではCloud Domainsはサポートされていないため、新しくドメイン管理用のプロジェクトを作成しました。 ドメイン管理用のプロジェクトを作成した理由としては、以下の理由が挙げられます。
通貨管理基盤をデプロイしているプロジェクト同士の責務は同じにしたい.
Terraformで管理できていないリソースは、それだけでまとめたい
1つめの理由についてもう少し具体的にすると、通貨管理基盤をデプロイしているプロジェクトのどれか1つでドメインを取得した場合、ロードバランサーを設置する際のDNS周りの設定が1つのプロジェクトに依存してしまいます(図3)
現状Terraformで管理できていない部分は、Cloud Domainsでのドメイン管理と、新たにロードバランサーを設置するプロジェクトへサブドメイン追加の権限付与が挙げられます。
(サブドメインの追加自体は、Terraformで管理しています。)
これらの人為的ミスが起こりうる部分でどれだけミスの可能性を落とせるかが課題となりそうな気がしています。
無事に、applyでリソースが生成できることを確認した後は、簡単な負荷計測を行いました。 今回のシステム構成の改善に伴う性能の劣化を懸念していましたが、秒間100リクエストほどの試験では問題ありませんでした。
また、Terraformのモジュール化、新たに追加していた権限の最適化を行いコードとしての完成度も高めることができました。
自分にとっては2つ目のタスクの過程全てが難所でした。
特に悩まされたのは、以下の2つでした。
Stateと実環境のリソースでの差分発生時のエラー
リソース間の依存関係を意識せずに作業を進めていた結果、前の変更でたまたま必要なroleが追加されていたがために、問題なくapplyされてしまい、リソースを削除する際には、権限が先に削除され、権限不足でエラーが発生しました。 そのほかにも、State上だとAPIが有効なはずなのに、実際は無効になっていてエラーになってしまうといった状況もありました。
先にCLI上できちんとリソースが生成可能かどうか検証する、一度の変更差分を小さくする(リソースをまとめて追加・削除しない)ことの必要性を感じました。
各リソースへの適切パラメーターの付与
Terraformは、各ベンダー・各リソースのテンプレートが準備されているため、一見簡単にリソースを定義できそうに最初は感じていましたが、そんなことはありませんでした。 GCPの仕様変更によって、参考にしていた公式ドキュメントのままでは、上手くいかない場面や、文章としての記載はなくExample Codeで示されているパラメーターのルールなどを把握する必要がありました。 いきなりTerraformからリソースを生成する前に、一度CLI上でリソースを生成して確認する必要性を感じました。
しかし今回のインターンでは、あえて自分がこれまでに全く経験したことがない分野のタスクに挑戦させていただきました。
現状のシステム構成、変更する目的・要件を加味し、必要なリソースや変更点を洗い出す → 壁打ちしながら構成を検討する → コードに落とし込む → 検証する
という一連の流れを経験することができました。
システムのインフラをコードで管理することで、属人化を防ぐことができると感じました。 また、インフラをコードで管理することで多少の導入コストはあるものの、長い目で見ると確実に生産性が向上するのではないかと感じました。
今回は、非常に学びになった3週間でした。
メンターのなかひこさん、チームメンバーのみなさん、アカツキゲームスのみなさん、ありがとうございました!