プログラミング

株式会社アカツキでインターンをして多様な経験を積めました

どうも、ましです(Youtuberみたい)

この度タイトル通りではありますが株式会社アカツキさんのインターンに3週間参加させていただきました。本当に楽しかったので様子・学びを忘れないうちに書き留めたいと思います。

概要

今回僕はサーバーサイドエンジニア(Rails)として八月のシンデレラナイン(通称:ハチナイ )というゲームを作っているチームに参加させていただきました。丁度アニメが再放送されていたり渋谷駅に広告が貼られたりでご存知の方も多いかもしれません。また、待遇もすごく良くて特に業務用mac book proが高スペックでめっちゃテンション上がりました!!Unity起動しながらDockerでRailsサーバー建ててChromeでタブ20個くらい開いてRubyMineもVscodeもひらきながらZoomで通話しても余裕です。

参加の経緯

サポーターズさんの1on1逆求人でアカツキさんとお話しをしました。元々昨年参加された方のブログなどを見て良い会社・サーバーサイドについて力を付けられそうというイメージを抱いていました。今回はインターンで使う言語はRailと決まっており、元々僕はRailsでの開発経験がなかったのですが「(それでマッチしないとしちゃうのは)もったいないな〜」と言っていただき面談・面接を組んでいただきました。(特例のような書き方ですがアカツキでは未経験の言語を扱うことになっても開発経験があれば受け入れてもらえるケースは多いようです)

その後面談・面接を終え無事合格をいただきました。面接では技術的なことも聞かれましたが終始楽しく考え・答えることができました。

インターンでは

  • パフォーマンスを気にする必要があるような大規模なプロジェクトで開発がしたい
  • サーバーサイドを書きたい!
  • チーム開発の流れやマナーを学びたい
  • ゲームがどう作られているのか知りたい

というのを目的・目標にしていました。

取り組んだこと

タイトルで多方面学んだと書いている通り「運用改善・新規機能追加・パフォーマンスチューニング・CI・脆弱性検知設定・(ちょっとAWS)」など幅広く扱わせていただきました。

運用改善

管理画面で複数件削除できるように

まず最初は運用改善のタスクとして積まれていた「管理画面で複数件削除できるようにして欲しい」という物に取り組みました。管理画面はActive Adminというgemで作られていたのでかなり簡単に実装できました。

index do
 selectable_column
 id_column
 ...
end

def batch_action
 ...
 Hoge.destroy_all
 ...
end

という形で書くだけでした。最初の慣れるための課題としては良かったと思います。

検証用ユーザーの追加を管理画面でできるように

時系列的には最後から2つ目にしたことです。検証などの際にテスト用ユーザーを追加したい機会があるのですが今まではRakeタスクとして定義されており、実行するにはわざわざコマンドを打つ必要がありました。それはめんどくさいので管理画面からGUIで行えるようにしました。

Rails.application.load_tasks
Rake::Task['タスク名'].execute
#clearしとかないと次2回実行される
Rake::Taks['タスク名'].clear

という形で書けます。もちろん実際にはクラスなどに分離して書き直した方が良いのですが工数などを考えてこの実装にしました。

新キャラクターの実装

クリスタルベアマックスといういわゆる限界突破用のキャラクターの追加をチームの方から依頼していただきました。現状ハチナイ では「誰でも限界突破できる用キャラクター」・「特定のシーン用キャラクター」がいました。今回は同じキャラクターであれば限界突破できる用のキャラクターを追加することになりました。

現状のシステムを流用できて簡単そうに見えますがそのままでは無理でした。同じキャラクターかどうかを見分けるにはキャラクターidを見れば良いです。しかしベアマックスにはベアマックス用のキャラクターidをつける必要があり一致しているかどうかという判定ができません。そのためベアマックスのidと対応するキャラのidの対応を管理する必要があります。

既存テーブルにカラムを増やすと無駄が多い、限界突破用キャラは全キャラ同時に実装されるとは決まっていないため種類が増えた時にコードをいじりたくないなどの理由から新規に対応テーブルを作成することにしました。

実際に動作するために必要なコードは10行くらいでテストを書いたりseed checkerというデータ投入時のチェック用コードなどで全285行とかになっています(終わってから見直して少し驚いた)

初めてクライアントやプランナー・デザイナーの方達と話し合いながらプロジェクトを進める経験ができてとても楽しかったです!!ちなみにクライアントは同時期に居たインターン生の方が取り組んでくださりました!!

プレゼントの一括受け取り

概要と現状のパフォーマンス

現状ハチナイ ではプレゼントを1ページ(10個)ずつしか受け取ることができません。全て一気に受け取れたら良いのにな〜と思っていました。実際に要望として上がっていたので取り組めることになりました。まず現状のシステムで仮に一気に受け取った時にどれくらいパフォーマンスに影響が出るのかを調べました。

その結果から数が増えるにつれてレスポンスにかかる時間も非常に伸びてしまうことがわかりました。(レスポンスが帰るまでに遅いのはDockerを使っているからかもしれません)特にActiveRecordの処理に非常に時間がかかっており、実際にコードを見ても受け取れるプレゼント一覧の取得->1つずつ受け取るというN+1問題と呼ばれる状況になっていました。

じゃあN+1問題を解決すれば良いじゃんと思ったんですが、実際にはアイテムの種類によって必要な処理などが変わっているため簡単にBulk Updateのような一括処理を行うことが難しい状況でした。そこで、並列化により全体の処理を高速に行うのはどうかと思いました。

並列化

幸い、Parallelという並列化を簡単に行うことができるgemが存在します。これを使えば処理を並列化することは非常に容易いです。尚、rubyにおいてマルチスレッドによる高速化はあまり期待できないため以下はマルチプロセスの話です。ここにとても大きな問題がありました。以下のように1つ1つの受け取り結果をクライアントに返す必要があるためreceive_resultsへ結果を入れています。コードで言えばresultがreceive_resultsの中に入っていきます。

gift_list = DBから受け取るプレゼントを取ってくる処理

receive_results = Parallel.map(gift_list) |g|
   ..プレゼントの受け取り処理...
 result
end

プロセスはメインプロセスとメモリ空間を共有しないためパイプなどを使用して変数の値などを渡したりする必要があります。そのためにParallelではmarshal.dumpという関数を使っています。しかし、この関数は全てのオブジェクトに適用できるわけではないのです。今回問題となったのはクラスメソッド(特異メソッド)を持っているものは扱えないと言う点でした。結果用のResultクラスもその1つだったのですがそれ自体は必要な情報を別のクラスメソッドのない構造体へ移せば良いです。しかしException(例外)クラスも特異メソッドを持っていました。それに加えresultの中には受け取るプレゼントの種類によって違うクラスが入るためフィールドなども不確定です。流石にそれらを適切に移して返したり、例外を別構造体に移す・map外で再構成するのはリスクが高い・複雑になりすぎると言う結論になりました。

本格的に設計変更も含めて改善を行えば可能だったかも知れませんがインターン期間中に行うことは難しそうで断念することとなりました…

脆弱性チェックの自動化

脆弱性チェックは大事ですが担当者以外にも重要性を伝えるためにCIの定期実行機能で脆弱性チェックを行い、それをSlackに通知する機能を実装しました。

Trivyとは

Trivyはコンテナイメージを指定するとそのOSイメージ自体に脆弱性がないか・Bundlerやyarnなどで管理されている依存関係にも脆弱性がないかチェックしてくれる優れものです。導入も非常に簡単なので使いやすくて良いです。

実装方法

ハチナイ ではCIツールとしてCircleCIが回っています。CircleCIには定期実行する機能があるためそれを用いてtrivyを1ヶ月に1度実行しslackへ通知するように設定しました。

どちらも初めて触る技術だったため4日くらいかかるかと思ったら1日ちょっとで終わってしまいました。見積もりをちゃんと立てられるようになりたいですね…

SlackにはTrivyの全体結果ではなくTotal: ○(CRITICAL:□,HIGH:△)みたいにしたかったので

trivy コンテナ名 | grep Total: -B 2

したものをslackに投げています。

コードについてはほぼREADME通りなので省略させていただきます。

リザーブドインスタンス購入のための調査

リザーブドインスタンスとはAWSでインスタンスを決まった期間使うことを決めておくと割引してくれるやつです。来年分の申請をするために現在使われているインスタンスで無駄なものはないかなどの調査をしました。

業務規模のAWSをみたのは初めてだったんですが規模が違いすぎてビビりましたね…

CPU使用率が高いことの調査

テスト環境として利用しているAWSインスタンスのCPU使用率が50%に届きそうな状態でした。結果としてはログ収集用に使っていたソフトウェアに必要なファイルがなく、トライ&エラーを繰り返していたことが原因でした。

その後修正したイメージをオートスケーリング用に設定しました。この辺りの経験がなかったので一般的に見れば簡単かも知れませんが楽しかったです。

インターンを通して

正直なところ「良かった」が多すぎて逆にこの一言しか出て来ないです。頑張って言語化していくと

チームの雰囲気が良い

すごく雰囲気が良いんですよね。毎日夕会と言う形でZoomミーティングがあったんですがクソ真面目に淡々と進むのではなく少し雑談を交えながら楽しい雰囲気で進んでいました。slackなどでも冗談が飛びあったり面白い反応が来たりと一緒に過ごすのが楽しいチームでした。

もう少し真面目なところで言うと「これどう思いますか?」とグループ内でメンションをつけずに聞いた時にも必ず返事が帰ってくることがすごいです。丁度僕の所属している団体ではこれに対して返事をもらえず非常に悩んでいました。誰かがやってくれると人任せにするのではなく1人1人が自分の担当範囲を認識していたり反応することの重要性をわかっているのは当たり前のようで難しいことだと思っていたので流石だなぁと感じました。

他にも、ランチを社員の方と一緒に取らせてもらう機会を多くいただけてとても良かったです。自分が参加しているプロジェクトだけではなく他のプロジェクトの様子を知れたりその方の就職に対する考えを聞けたり、純粋に技術について話せたりととても楽しかったです。

また、slackの絵文字が非常に充実していてリアクションを取りやすかったのでとても良かったです。

色々なことができる

僕が行ったタスクを見てもらえばわかるようにサーバーサイドの中でも色んな分野に手を出させて貰えました。また、その多くはメンターさんから指示されたものではなく自分で探したり、積まれてるタスクからやりたいものを選ばせていただいたものでした。もちろんそれぞれに適切なサポートを得られて非常にやりやすかったです。

また、日報を書くのですがただ書くだけではなくメンターの方から振り返りをいただけたのも非常に嬉しく、モチベーションが上がるきっかけとなりました。

色々なことが自動化されている

slackでは日常茶飯事のように色々なbotが動いていてすごくびっくりしました。

githubのcommitなどの通知はもちろん、その日のDAU(デイリーアクティブユーザー数)やメンテ時の進行度合いなどを通知してくれたり本当に多種多様でした。もちろんslackだけではなくプランナーさんの作業をエンジニアの方が自動化したりとミスが起きやすい場所などの必要な場面では自動化がどんどん進められていてすごかったです。個人的にも色々やってみたい!!と言う気持ちにすごくなりました。

最終的な目標や実装理由を定める重要さ

個人開発では「かっこいい」「楽しそう」などの理由で機能を追加することが多いですが実務では「なぜそれが必要なのか」を考える必要があることを再認識しました。

最後に

3週間という期間でしたが色々なことに取り組めたんじゃないかなと思っています。やはり社員の方ほどの進捗を出せなかったのは悔しいところではありますが今後も更に力をつけていきたいと思えるきっかけになりました!

最後になりましたがメンターさんを始め人事の方・受け入れてくださったチームの方やご飯を一緒に食べてくださった方など本当にみなさんお世話になりました!!とても楽しかったです!