Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキが運営しています。

【LT会】Akatsuki Geek Live開催レポート!Vol.2

こんにちは、エンジニア採用担当の花田です。

元号を跨ぐ大型GWも終えましたが、去る4/26(金)に学生向けLT会「Akatsuki Geek Live Vol.2」を開催いたしました!

2月の初開催に次ぐ、2度目の開催となりましたが、今回もリピーターを含む約30名の学生の方に集まっていただき、序盤から大いに盛り上がりました!この記事では、その様子を紹介いたします。

 「Akatsuki Geek Live」とは...

学生エンジニアと、アカツキエンジニアが登壇するLT会です。今回は学生3名、アカツキメンバー5名の計8名が発表しました。その後、参加メンバーで懇親会を実施、学生同士やアカツキメンバーとの交流をいたしました。

▼イベント概要はこちらから

aktsk.connpass.com

▼なぜLT会を開催するに至ったのか

初回の開催レポートに開催の思いを綴っていますのでご興味ある方は、こちらから

hackerslab.aktsk.jp

 #当日の様子

前回、前半のLT会はかなり真面目な雰囲気で進んでいき、後半の懇親会では、わいわいと盛り上がりました。それはそれで良かったのですが、今回は序盤から更に盛り上げていきたいと思い、LT会スタート時から参加者の方にドリンクを取っていただきました。カジュアルな空気で開始したこともあり、Twitterも序盤から活発に動く中、早速スタートです。

 

▼1人目:@3nan3さん(アカツキ)

「Ruby/Railsで、key-valueなオブジェクトから値を取得するイディオム」

1人目は、アカツキメンバーから!Ruby on Railsで「おれはHashから値を取り出したいだけなんだ!」という熱い思いを語ってくれました。

f:id:kenji-hanada:20190509203211j:plain

発表資料

qiita.com

 

▼2人目:@カレーエンジニアkomaiさん(アカツキ)

「世界最大級のゲームカンファレンスGDCって何?どんな雰囲気なの?どうやったら行けるの?」

2人目もアカツキから、絶品カレーを振舞うエンジニアが3月にサンフランシスコで開催されたGDC 2019の紹介をしてくれました!

f:id:kenji-hanada:20190509203208j:plain

発表資料

speakerdeck.com

 

▼3人目:@諏訪さん(アカツキ)

「What's "Google Cloud Next"?」

3人目もアカツキから諏訪さん。GDCに続いて、4月にサンフランシスコで開催されたカンファレンスの参加レポートを紹介!

f:id:kenji-hanada:20190509203205j:plain

発表資料

speakerdeck.com

 

▼4人目:@きょーまさん(アカツキ)

「C#のリフレクションを使ってみよう」

4人目はアカツキ枠からきょーまさん!C#のリフレクションについて基本的な使い方と便利な使用方法を紹介してくれました。

f:id:kenji-hanada:20190509203202j:plain

発表資料

speakerdeck.com

 

▼5人目:@yasu0327さん(学生)

「ゼロから始めるGo Modules」

5人目は学生枠からyasu0327さん。Go Modulesの管理機能とその流れを紹介してくれました!最近Goに取り組まれている学生さん多いですね!

f:id:kenji-hanada:20190509203157j:plain

発表資料(speakerdeckには代理で登録しています)

speakerdeck.com

 

▼6人目:@給前さん(アカツキ)

「Unityエンジニアを目指す方が、学生のうちに学んでおいてほしい技術」

6人目はアカツキから、Unityエンジニアを目指す方向けに、自身の学生時代の学習方法・内容を交えながら語ってくれました。勉強量がとにかくすごい。

f:id:kenji-hanada:20190509203151j:plain

 

▼7人目:@Matts966さん(学生)

「Go言語で書くLispインタプリタ」

7人目は学生枠からMatts966さん!この発表では特に「タイトルがもう強い」「Lispインタプリタすごい」とTweetが盛り上がっていました!

f:id:kenji-hanada:20190509203148j:plain

発表資料

 

▼8人目:@takanakahikoさん(学生)

「学生がOSSに挑戦するということ」

トリを務めるのは学生枠よりtakanakahikoさん!OSSへの挑戦について語ってくれました。実は私も彼が作った拡張機能を使わせて頂いています!

f:id:kenji-hanada:20190509203140j:plain

発表資料

speakerdeck.com

 

8名による熱のこもったの発表はあっという間にすぎ、懇親会へと移ります。

今回も学生 x アカツキメンバーの交流が盛んで、至るところで笑い声が聞こえました。中にはセグウェイに乗りながら懇親会に参加するメンバーも笑

f:id:kenji-hanada:20190509203137j:plain


参加者のみなさん、お疲れ様でした!

今回、アカツキの技術領域の話はもちろん、海外カンファレンスの話や、学生同士の交流を通して、これからの一歩を踏み出す一つのきっかけとなったのではないでしょうか。

次回は7/1(月)に開催予定です!またエネルギー溢れる皆さんにお会いできることを楽しみにしています^^

f:id:kenji-hanada:20190509203134j:plain

 ▼次回予約はこちらから

aktsk.connpass.com

RubyKaigi 2019 に SAKE Sponsor として参加してきました!

こんにちは、18卒で入社したサーバサイドエンジニアの氏平です。
普段はゲームコンテンツの運用をしています。

アカツキが4/18(木)〜20(土)に福岡国際会議場で開催された、RubyKaigi2019 に SAKE Sponsor(Platinum)として参加してみてきましたのでレポートをしたいと思います!

はじめに

アカツキでは Ruby on Rails を使用して、ゲームのサーバーサイド(APIサーバ・管理画面・インフラ)の開発・運用を行っています。普段業務で使用している言語の最新の情報をキャッチアップしてこようと今回 RubyKaigi 2019 に参加しました。
アカツキからは8名の参加です。

RubyKaigi とは

Ruby の中で最大級の国際会議。 

rubykaigi.org

世界中からコミッターや開発者が集まり、Ruby の新機能の情報や開発事例などが紹介されます。
RubyKaigi 2019 では主に 現在開発中の Ruby 2.7 と Ruby 3.0 の機能紹介が行われました。

f:id:sejimhp0808:20190425220455j:plain

 

アカツキブース出展

今年はアカツキとしてスポンサーブースも出展したので紹介させていただきます!

アカツキから配信している「八月のシンデレラナイン」(通称ハチナイ)をベースにブースを出展しました。
野球盤を用意し*1ヒットを打てた方にオリジナルカレーをお渡しするというゲーム形式です。 

ハチナイのアニメもちょうど4月から始まり、見てくれた方もいたので楽しくコミュニケーションを取ることができました。

f:id:yusi:20190426170649p:plain

 

Matz さんもブースに来てくださって、オリジナルカレーを持って帰っていただきました!

f:id:sejimhp0808:20190425220816p:plain

 

SAKE Sponsor として参加して

RubyKaigi の後、毎夜パーティーが開かれました。
その中で RubyKaigi 2019 Official Party で我々がスポンサリングしたお酒が配られました!

f:id:sejimhp0808:20190425220514j:plain

中洲川端商店街を貸し切りのイベントでお酒以外にも地元の名物も多数配られました。
美味しいご飯を頂きながら、いろんな方とお話することができました!

f:id:yusi:20190426170926p:plain

KBC九州朝日放送のニュースにも取り上げられたようです!
地元の方にも喜んでいただけてよかったです!

kbc.co.jp

 

さいごに

目黒周辺では Meguro.rb という Ruby の Meetup が定期的に開催されています。
5月開催はアカツキではないですが、LT大会や懇親会などございますのでぜひお越しください!

megurorb.connpass.com

 

f:id:yusi:20190426171125p:plain

*1:エポック社さんの許可をいただき、野球盤をアレンジしました。

インターンで好き勝手働かせていただいた話

エンジニアインターンとして二週間アカツキで就業したstalagmiteさんの体験記をお届けします。「自分の理想とするエンジニア」を意識して働いたインターン、どのような経験をされたのでしょうか。その様子をレポートいただきます。

自己紹介

この度アカツキのもとで内定後インターンをさせていただきました。その時のことについて、主に自分が何を考えながら動いたかを書きたいと思います。 とても自分語りが多くなるかもしれませんが、多分アカツキの社風的に大丈夫だと踏みました。

所属当初の背景

大学では情報系の専攻をしていた。
大学での研究はOpenStreetMapのことについてやってる。
ゲーム製作サークルに所属していて、学祭でゲームの展示をしたりしていた。

プログラミング経験

C++,Haskell,C#,Unity,GLSL

隙間時間で調べてること

数学(圏論、集合論、確率論)
シェーダ
VR

普段やっていること

DxLibやOpenSiv3Dを触りつつゲームの部品を作ったりモックを考えたりしている
しかし完成したものはないという地獄

所属時の話と自分語り

大学でプログラムの勉強をしていると、プログラマーというのは「厳密に仕様を決めて高い水準で要求に答える」みたいな、専門家としてのSE像があった。 ただ、もともと大雑把な性格で緻密なことが苦手な自分は、「そういうイメージのプログラマになれるのか」という漠然とした不安があった。(もちろん、ある程度のコード力はあると自負はしているけれども、その専門家としての価値と自分の性格って合わないような気がしていた)
就職活動をしている中の、そんな漠然とした不安のを抱えているときに、アカツキとの面談や、会社の説明を聞く中で、

「うちで働いているエンジニアはそれぞれ違う部分で価値を出し働いている。」
「インフラのことについての専門性で貢献しているエンジニアもいれば、プランナーなどの別職と連携をとったり、自分で案を出しつつ実装までするエンジニアもいる」
「全員が自分で考えていて、受け身なだけの人はいない」

という社風に興味をひかれ、アカツキの入社を希望した。

インターンの目標

インターン初日、メンターの方に言われたのは、
「このインターンでの目標を決めましょう」 という抽象的なものだった。 働き方も、目指すものも、全部自分で決めて良い。
具体的な課題をひたすら潰すもよし、実際のプロダクトの小さい機能を設計から作ってもよし、「 インターンで僕が何か良いものが得られたと感じられる、それがこのインターンの意義です」と説明してくださった。
僕は、大手のゲーム業界でたまに、規模は大きいのにゲーム性そのものがイマイチなゲームというのがあるのが嫌だった。
これは入社前から持っていた偏見であるが、「イマイチになってしまうのは、プランナーが仕様を考えてエンジニアが実装して、それをプランナーに戻してまたフィードバックして、というサイクルが重いのが原因なんじゃないか」と思っていた。だから、僕はこのインターンの目標として
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニアになりたいです」
と答えた。
一つ重大な問題がある。僕は自分の「ゲームエンジニア」としての像をここに置いた。この作業はいわゆる「ヒアリングから問題点を聞き出し解決策に落とし込む」というまさにSEとしての分野であり、
僕は大学でこの内容の授業の単位を落としているのである。
ついでに言うともともと僕はコミュ障であって、就活中にも自己嫌悪で大変なことになっていたほどだ。もう不安しかない

最初の1週間

目標を決めた後、ソーシャルゲームの開発(クライアント)チームに配属された。このチームでは、プランナーエンジニア問わず、Trelloに

「何か改善すべき問題」
「さらにゲームを面白くするためのコンテンツ案」
「UIUXの改善案」

など、色々な抽象段階の案を共有することができることを教えてもらった。
ここから自分が面白そうな案、実現できそうな案を拾い、話を聞きに行く。
プランナーがしたいことを、現在実装がどうなっているかを把握できるエンジニアが聞き、仮設計を考え形にする
これは結構自分がやりたい立ち回りに近いものだと思えた。

ここで色々な意見を聞いていく中で、「ゲーム内のキャラクターの編成を組むときの、画面遷移を伴う操作が煩雑であり、それを改善したい」という意見をプランナーSさんに頂き、これは手を付ける影響も少なくて済みそうだし、いい感じに抽象的だったので、担当することにした。 幸い、個人的にプログラムのバイトの経験があったので、さほど時間を取られずに自力で規模の大きいコードを読みつつ、既存コード内のでのゲームデータの扱い方や簡単な画面遷移の処理を頭に入れ、最初の1週間のほとんどをヒアリングに使った。
ここで最初の山を迎えた。最初の実装、設計案を考えたときに、「これは難しい。既存の画面遷移の中にどうUIUXをいじっても、複雑な操作が発生してしまい、意味がなくなってしまう」という結論になってしまった。このことをプランナーSさんに相談しにいくと、
「もっと根本から考えてみたほうが良い。本当は、編成なんて1タップでできるんじゃないか?それが実現できたら、最も便利なんじゃないか?
僕は仕事として、与えられた役割としてプログラマを引き受ける時に、どうしても今確実にできることベースで物事を考えてしまう癖がある。それは情報系プログラマ、エンジニアとして大事な要素ではあるが、何かを解決したいときの思考方法ではない。なまじコードが読めるから、設計案が頭に浮かぶから、わかる範囲で片付けようとしてしまっていた。
なので僕は「1タップで自動編成」を一番上に置いて、それにもっとも近づくように、要求を分析することにした。これは、他のエンジニアに相談すると、「完全に自動編成するためには、キャラごとに編成する際の評価値を計算する必要があるが、その厳密な計算は難しい」
ということになってしまったのだが、
「他ユーザの編成を分析してそれを元に評価値を作れば、厳密な計算はいらないし、信頼性も高いのではないか」
という案が浮かび、既存の資産も活かせるということで、落とし所として、
「同レベル帯で成績の良い他ユーザの編成(=クリアログ)を自分の手持ちキャラなるべく似せて自動編成できる機能を作る」
とういことになった。(プランナーとエンジニアを行ったり来たりして解決案をだすというムーブ、これがしたかった)

これが決まった後、既存のコードを利用した設計と実装案、ドキュメントを書くことができた。
ここまで来るのに二度提案を練り直した。 この時点のドキュメントで
関数の影響範囲
この提案で操作が便利になるユーザー層の想定
までは書くことができた。ここまでは、いいペースだったと思う。

次の1週間

手をつけた課題についてドキュメントを書き、仮のコードも書いて、最初のプルリクエストを飛ばした。 当初の予想では、もっと議論が活発になると予想していた。というのも、僕が担当したのはロジックで、仮提案であり、現状のコードや設計により詳しい人にコメントがもらえるだろうと予測していた。ロジックだけでなく、本実装する際はUIUXの話も絡んでくるだろうと思っていたので、正直なところ「あれ、ウケが悪いな」と思った。
この時、元々の提案を出してくれたプランナーSさんが別の部署に行ってしまい、次にやることも含めて自分で考える必要が出てきて、3日ほど右往左往してしまった。

その後なんとか僕は、「現時点での提案の「自動編成の精度」が、どの程度良いのか分析できていないから、皆現在の提案の進捗が想像が難しいんだ」、と考えた。それは部分的には真で、自分でも「じゃあこの自動編成を使うと、どう便利になるの?具体的にどのユーザがどのように便利になるの?」という風に疑問に思っていた。なので次は、
「既存のユーザの分析」
「この提案で便利になるユーザとはどのような状況の人間か」
を調べることにした。

最後の1週間

mysqlをいじってアプリで使われているデータから、ユーザの手持ちキャラ、自動編成の通してみた結果を比較したデータを用意し、分析した。具体的には、自動編成後の編成のスコアの分布ごとに、
「編成結果のスコアがここのユーザたちは、ゲーム内ではこのコンテンツをするためにこの操作をすると考えられる」
編成結果の低いここのユーザ層は、そもそもここのコンテンツを触らないな。より良いコンテンツへの推奨はUIUXでこう解決できるな」
というところを分析し、ドキュメント化した。
また、このデータを他のエンジニアが検証できるよう、デバッグメニューの実装し、プルリクエストを飛ばした。 これによって、2回目のコメントもらい、時間的にも区切り的にもちょうど良いので本インターンでの作業を終了した。

総評

一応、ヒアリング、提案、実装、分析、デバッグメニューで他者に検証してもらうフロー、今後の展望のドキュメント、までを、いろんな人に話を聴きながら作り上げることができたので、最初の目標である、
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニアになりたいです」
という動きはできたのではないかと思う。
ただ反省点として、
「プランナーSさんがいなくなったタイミングで、この提案の実現の進路を考える人が自分以外にいなくなったことに気づかず、失速していた」 というのがあげられる。
本来これにすぐに気づき、次に決めるべき内容、この提案について本腰を入れて一緒に考えてくれる(自分以外の)人間を巻き込む必要があった。 (ずっとメンターにも相談していたのだが,いつも「次どうすればいいですかね」と聞いてしまった。僕が考えるべきだったことなのに)
確かに、僕はプルリクを飛ばしてエンジニアとしてコードを書いてドキュメントを書いて分析もできたが、じゃあこれが何かの役にたったのかというと、正直よくわからない。なぜなら
提案の進路、実現の持っていき方を考えていなかった

or
それを考えてくれる人間の確保が必要なことに気づかなかった
からだ。
「プランナーの考えている抽象度の高い案をとっととモックを作って実現して改善する、というプロセスをぶん回すエンジニア」
のそれっぽい動きはできたけれども、そういう立ち回りののオリジナルな価値を生み出せたかというと、それは少なかったように思う。
そもそも僕がやりたいこの動きって、「プランナー<->エンジニア間で速度の速いフィードバックをして、抽象から具体に落とし込む」というのをやりたかったのだ。 しかしそもそも、
「抽象的な目標、提案をチームの内側から通すって時は、具体的な設計、方針が決まるまでその提案の立ち位置、自分の立ち位置、他人の立ち位置をよく把握しなければならない」
、そうでなければ、空中分解しかねないという基本を、僕は知っておくべきだった。
これはものを考えるプランナーだけでなく、何かを作るという当事者全員が意識すべきことだったことに気づいた。
三週間のインターンなので、大きい規模を実現することはできないという前提があったなかで、最大限のことをしようと覚悟をしたはずなのに、その覚悟がまだ足りなかったように思う。
インターンが終わったらまた日常生活に戻る。そこには、大学でも、個人ゲーム制作チームでも、やり残していることがある。
来年アカツキに入社するまでに、それらにケリをつけて成長して出直そうと思った。

アカツキインターンで体験したこと・感じたこと

エンジニアインターンとして二週間アカツキで働いたnkzさんの体験記をお届けします。初めてのインターン、そして初めての実践的な開発に関わったということでしたが、どのような経験をされたのでしょうか。その様子をレポートいただきます。

ご挨拶

初めまして。nkzです。この度アカツキで、あるモバイルゲームのサーバサイドエンジニアとしてインターンをさせていただきました。趣味は競技プログラミングでそれ以外の開発経験はほとんどありませんでした。開発経験の無い競プロ勢がインターンに行ったらどうなるか?という一つのモデルケースにしてもらえれば幸いです。期間としては二週間ちょっと、開発環境はRuby on Railsでした。

インターンが始まるまで

アカツキのインターンに行くことを決めたのがインターン始まる二週間前とかで準備する期間はあまりありませんでした。一応メンターに「Rails Tutorialを最低7章までやっておいて」と言われたので、7章までやりました。
Webアプリケーションを作った経験はほぼ無くて、N予備校のプログラミングコースでNode.jsのExpressというフレームワークを使ってなんかやったくらいなんですが、なんかそれに比べるとかなり使いやすい印象を受けました。何となくRailsが流行っている理由が分かりました。

初日

インターンに伴うオリエンテーションや社内ツールなどの設定をやっていました。この日はメンターが不在だったので、フリースペースで人事の方とお話ししながらまったり過ごして早めに帰りました。

環境構築 〜 最初の課題(N+1問題)

二日目からメンターと顔合わせをして、まずは環境構築から始めました。ドキュメントを読みつつメンターに教えてもらいつつやりました。私が勝手にmysqlの新しいバージョンをインストールしたせいで、他の箇所でエラーが出たりして、環境構築は辛いと思いながら何とかできました。

そして最初の課題は「あるAPIでN+1問題が起こってそうだからそれを解決してみよう」というものでした。

「N+1問題」は有名な問題らしいのですが、私は「そもそもN+1問題とは……?」という状態でした(名前は何となく聞いたことがある)

幸いにも有名な問題なのでググるとたくさん解説ブログなどが出てきてくれて、以下のようなブログが参考になりました。
ruby-rails.hatenadiary.com

感覚としてはデータベースのサイズをN, クエリの数をQとするとN+1問題が起こっている状態ではO(NQ)くらいかかっている状態で、それをO(N)になるように修正したい、ということなんだろうと解釈しました(合ってるかな…?)

ともかくグーグルによってN+1問題とは何かは分かりましたが、次にそれがどこで起こっていてどう修正すればいいのか、ということを突き止めていかなければいけませんでした。

プロジェクトのソースコードは大規模でRails Tutorialで触ったようなサンプルアプリケーションとは比べ物にならないくらいファイルが多くて、まず「ソースコードを読む」ことすら困難でかなり苦労しました。

ようやく「ここかな?」と思うところを見つけてコードを書き直してみたものの、メンターに「そこじゃないよ」と言われてしまい……最終的にはお手上げ状態になってしまい、ソースコードやログの読み方を教えてもらいつつ「ここを直せばN+1問題が直るね」と教えてもらって「なるほどな〜」となってこの課題は終わりました。私は何も出来ませんでした…

とても勉強にはなりましたが、自力では何も出来なかったので落ち込みました。「まぁ何の知識も無い状態からスタートしてるしこういうもんだよね」という感じで切り替えて行くことにしました。ここまでで三日経ちました。

二つ目の課題(社内ツールのビューを作る)

二つ目の課題は「シナリオチームが使っている社内ツールがあって、変換部分は既に作ってあるから操作するためのビューを作ってください」というものでした。この辺りで私が想像していたサーバサイドエンジニアとは少し違った課題になりつつありますが、そういう仕事もやるんだという感じでやっていきました。

前回見たプロダクトのコードよりもかなり小規模で、Rails Tutorialをやったくらいの人間にはちょうどよかったです。また一から新しいものを作るというより、既存のコードを参考にしながら作れる部分がかなり多くてそれも良かったです。

またここで初めてRSpecというテストフレームワークを使ってテストを書きました。「ブラウザの操作をシミュレートして期待する動作をしているか?」みたいなこともヘッドレスブラウザを使って簡単に実装できるらしく、凄いと思いました。テストを書くのは大変だけど面白いと思いました。

この課題ではたまにメンターに助けてもらうこともありつつ(turbolinkのせいでCSSが当たらない、テストの文法が間違っていてブラウザの挙動がおかしいなど)、自分で調べたり考えたりしながら進められることも多く最終的にPRをレビューしてもらってOKを出してもらって、達成感がありましたし少し自信がついたので良かったです。自分のレベルに合った課題を割り振ってもらっているおかげですが。ここまでで五日経ちました。

三つ目の課題(社内ツールの機能修正)

次の課題は前回の社内ツールの機能に不具合があるのでそこを修正するというものでした。

この課題はそんなに難しい点は無かったので割とサクサク実装することが出来ました。先頭にBOMが付いている文字列と付いていない文字列を同値比較していてデバッグ出力してもぱっと見同じに見えるのになぜfalseが返ってくるんだ…?というところで若干ハマりそうになりましたが…

メンターには「ファイルを直接触るようなテストは環境に依存する可能性があるので、ファイルに書き出す文字列を返すような関数を作ってそれをテストする形にしたほうが良い」ということを教えてもらったりしました。

あとこの辺りからコミットメッセージを以下のgistを参考にしながら英語で書くように努めました。(あまり悩みすぎるところでは無いと思っていたので文法とか適当ですが…)
[転載] gitにおけるコミットログ/メッセージ例文集100 · GitHub

ここまでで七日経ちました。

四つ目の課題(社内ツールの入力フォームを作る)

四つ目の課題は手がけていた社内ツールの入力フォームを作って入力された値のバリデーションをしてごにょごにょやるというものでした。これがインターンの課題で一番大変でした。

とりあえず最初はモデルを作らずに入力フォームのビューを作ってバリデーションはそのままparamsに入っている値を直接見て有効な値で無かったらエラーメッセージを表示させて…みたいな方法でやろうとしていました。モデルを作らなくていいと思った理由は入力フォームの値をDBに保存したり読んだり、みたいな操作が必要無いのでモデルを作らないほうがいいのかな?と思ったからです。しかし実装している途中で「これいちいち空チェックのバリデーションを自分で実装するのは筋が悪い気がする…ActiveRecordを継承すればその辺楽になるのに…」と思って、DBにアクセスせずにモデルを作るってありなのかな?と思って調べてみると…ありました。

qiita.com

どうやら include ActiveModel::Model と書けばいい感じにバリデーションのメソッドを使えたりViewに紐付くように出来たりするようです。

というわけでモデルを作ってバリデーションはそれに任せる感じにしたらだいぶいい感じになりました。

次にやりたいのは「フォームの入力に失敗した時にフォームに入力した値を保持した状態でリダイレクトさせる」ことでした。これもなかなかいい実装が出来ず最初は失敗した時に入力フォームの値をセッションに一時的に保存してレンダーする時にその値を埋めてセッションに保持した値を消して…みたいなことをしていて「うーん」という感じでした。これもメンターに「いい書き方無いですかね…」と相談したところ、リダイレクト先にフォーム情報をクエリ文字列として渡すという方法でシンプルに解決することができました。

他にも色々メンターやWeb業界で働いていた人にもレビューをもらって様々な学びがありました(form objectの話とか)。また色々ハマったこともありました(form_withの挙動とか)。振り返ってみるとこの課題が一番苦労したなぁ…という感じです。その分達成感も一番あって自分でも頑張ったと思います。

ここまでで十一日経ちました。

五つ目の課題(社内ツールの機能追加)

インターンも終わりに近づいて残すところ後二日となりました。最後は手がけていたツールの機能追加…というか機能拡張ですかね。今まではViewを弄っていましたが今回はModelを作る感じでした。「後二日で終わるのかな…」という感じでしたが、ソースコードを読んでいると割と既存のコードを流用できる部分が多くてほとんどコピペして後は少し修正してテストを書くぐらいの作業で特にハマるポイントもあまり無く無事終わらせることができました。

開発以外にやったこと

以上がインターンでやった開発の内容です。インターンの仕事内容としては上記の開発がほとんどですが、それ以外にも色々なことを体験させてもらったのでずらっと書いていきます。

朝会(あさかい)

インターンは10:00出社なのですが、毎日10:05から朝会というものがありました。これはチーム全体で5分程度の時間を取って全体に共有したいことなどを伝える時間です。だいたいプランナーさんが売上状況とかゲームがどれくらい遊ばれているかとかイベントの状況などを共有することが多かったです。

昼会(ひるかい)

毎日14:30からは昼会というものがありました。朝会はチーム全体での共有でしたが、昼会は開発チームで集まって15分程度の時間を取って共有事項を伝えたり、「今まで自分が取り組んできたタスク・これから取り組んでいくタスク」を全員が一言二言で共有するという時間です。エンジニアは自分の開発にかかりきりになるとどうしても周りが見えづらくなってしまうことがあると思いますが、この時間があることでみんながどういうことをやっているのかを把握できるので良い取り組みだと思いました。

エンジニアミーティング

隔週火曜日17:00からはエンジニアミーティングがありました。これはチーム単位では無く社内全体でエンジニアが集まって外部から招いた人の話をしたり、インターン生の紹介をしたり、自分が作ったツールをみんなに紹介したり…という時間です。最初のエンジニアミーティングではセキュリティに強い人を招いたお話があってCTFの可視化の話があったり、バイナリかるたとかアセンブラ短歌という世界があるという話を聞いたりしてよく分からなかったですが「すげー」と思いました。

1on1

毎週火曜日は30分程度のメンターとの1on1がありました。業務中はなかなか落ち着いて話す時間も無いのでこういう時間を設けてゆっくり話をする、みたいな感じです。特に大層な話をしたわけでは無いですが、インターンのフィードバックを少しもらったりアカツキという会社について聞いたりその他は雑談をしていました。私は競プロをやっているのでその話をしていたら、この前マラソン系のコンテストで出た問題がメンターが10年くらい前の高専プロコンで取り組んだ問題と実はほぼ同じだった、という面白い話を聞けたのがよかったです。

インターンの成果報告

エンジニアのインターン生は私以外にも結構いました。インターン生は最終日に成果報告をすることになっているので、私も他のインターン生の発表を聞きに行っていたのですが、AWSの環境構築をガッツリやっている人やゲーム内のミニゲーム(正の得点を得ることすらめちゃくちゃ難しい)を作っている人の話を聞いて、みんな凄いレベル高い…と思って聞いていました。刺激を受けました。

ランチとか飲み会とか

たまにメンターが他の人を誘って一緒にランチに行ったり、インターン生が卒業するときに一回大々的に飲み会が行われたりしました。ランチでは他のプロジェクトチームの話を聞いたりすることができました。インターン卒業飲み会でアイマスにめっちゃ情熱を注いでいるインターン生がアイマスをめちゃくちゃ推してくれたのでちょっと見てみようと思いました。

インターンで感じたこと・学んだこと

ゲームはいろんな人が協力しあって出来ている

当たり前っちゃ当たり前ですが、実際みんなと同じフロアで働くことでより強くそれを感じることができました。エンジニアだけでは無く、プランナーさんが企画したりディレクションをしてくれたり、シナリオを作ってくれる人、絵を描いてくれる人、音を作ってくれる人、モーションを作ってくれる人、検証をしてくれる人……様々な人の協力で一つのゲームが作られていてそれって凄いことなんだ、と感じました。

アカツキの働く環境はめっちゃ良い

アカツキはオフィス環境作りにもかなりこだわりを持たれていて、そのおかげでみんながストレス無く働ける環境になっていると感じました。靴を脱いで素足で仕事ができるとか、各階におしゃれなカフェっぽい休憩スペースがあっていつでも自由に休めるとか、オフィスに緑があったりして心が安らぐとか(?)。オフィスにいるのが苦痛になってしまったら仕事も辛いものになってしまうと思いますが、オフィスがおしゃれで居心地が良いのでそういうことは全く無く非常に良かったです。ただトイレに行くときに靴を履かなきゃいけないのがちょっと面倒ですが…

またオフィスだけでは無く、一緒に働く人たちも皆それぞれ違った個性を持ちつつも良い人が多いんだろうという印象を受けました。今回のインターンでは他の人と一緒に仕事をするという感じでは無かったので、あくまで普段のオフィスの雰囲気を見て、という感じですが。話し合うことはたくさんあるだろうし、ときにはすれ違いなどもあると思いますが、ギスギスした感じでは無く笑いもありながら和やかな雰囲気で皆さん仕事に取り組んでいました。

終わりに

始めにインターンのお誘いをいただいたときは正直かなり悩んでいました。行った方が良いんだろうな…と思いつつ不安な部分も大きくて「行きます」と言った後も「やっぱり辞めとけば良かったかな…」と考えたりしていました。

それでも実際に来てみると、やっぱり大変なことやしんどいこともありましたが、それ以上に良い環境で働けて学ぶことや感じることも多くてトータルで見ると「来て良かった!」と思えるものでした。この度インターンでお世話になった人事の方やメンターの方、一緒に働いてくれた方々には本当に感謝しています。

それでは長くなりましたが、ここまで読んでくださってありがとうございました。

カスタマーサポートに便利なMariaDB Spider エンジンを、Docker上に移設して保守も便利にする

はじめに

ゲームの運営では日々お客様から「ログインが出来なくなってしまった」「受け取れるはずのアイテムが受け取れなかった」などのお問い合わせをいただきます。

そのお客様が仰ったことが本当に発生したかどうか、あるいは本当とすれば原因は何かを考えるために、私達はそのお客様のデータや操作ログをサーバーのデータベースに保存しております。

さらにはゲームのイベント開催情報やカードのステータスなど、運営に関わるデータ(マスターデータ)と横断的に照らし合わせた上で、判断しております。

ここではそんなカスタマーサポートに役立てているMariaDB Spiderエンジンの紹介と、今回それをDocker上に移設して保守も便利にした話を書こうと思います。

MariaDB Spider エンジンとは

Spiderエンジンはデータベースのエンジンでありながら、内部にデータを保存することは行いません。

代わりに、テーブル構造とデータのあるホストを指定すると、Spiderエンジンのテーブルでクエリを実行するたびに指定したホストからデータを取得してくれます。

Spiderエンジンについての詳細はこちら

さらにはカラムの値によってデータベースの接続先を振り分けることも可能なため、1つのSpiderエンジンのテーブルから、水平分割されたデータベースからクエリに合わせて自動的に適した場所にアクセスすることも可能になります。

なぜSpiderエンジンがカスタマーサポートで便利なのか

私達のチームではデータベースにかかるインフラの負荷上、マスターデータやユーザーデータおよびログを1台のサーバーに集約することが出来ません。

さらはユーザーデータやログについては、1台で全ての負荷を受け止めることは出来ないため、さらにユーザーごともしくはテーブルごとにそれぞれ複数台に分割してデータを管理しております。

一方で様々なデータを横断的に検索するカスタマーサポートでは、もちろん出来ればデータの内容に合わせて手動で参照先を切り替える面倒は省きたいですね。

そこで、一つのSpiderエンジンから複数に散らばった必要な全てのデータを取得できるよう構築することがカスタマーサポートに大きく役立ちます。

Docker上で使用する理由

一方でSpiderエンジンはややマイナーなエンジンであるため、AWSのRDSから作ったデータベースにはインストールされておりません。 そのためAWSを使用している場合は、RDSを使うのは諦めてEC2インスタンスの上にMySQLサーバーを立ち上げた上で、Spiderエンジンをインストールする必要があります。

従来はSpiderエンジンを直接EC2インスタンスにインストールしていましたが、以下の問題を抱えていました。

  • データ構造や設定が管理されていないので、サーバーの立て直しが困難になってしまった。
    • その結果、EC2インスタンスのOS等のバージョンアップがしづらいので古くなってしまった。
  • アプリケーションのバージョンアップに伴いデータ構造が変わる際は、Spiderエンジンのデータベースにも都度合わせて手動で差分クエリを発行して変更する必要がある。そのためミスや抜け漏れによって実データベースと構造の差異が発生しやすい。
    • 特に使用頻度の低い場所については適切なアップデートがされなかった結果、過去に発生した構造の差異を埋めるのも困難な状態になってしまった。

そこで、今回はOS等のバージョンアップのためサーバーを立て直すのと合わせて、今後保守を行いやすいようDocker化を行うことにしました。

実装

まずはDockerfileの中身から見ていただけたらと思います:

FROM mariadb:10.3-bionic

RUN apt-get update && apt-get -y install \
  ssh \
  mariadb-plugin-spider \
  gcc \
  make \
  libssl-dev \
  libmariadb-dev

RUN cp /usr/share/mysql/install_spider.sql /docker-entrypoint-initdb.d/00_install_spider.sql

COPY 01_init.sql /docker-entrypoint-initdb.d/
COPY create_tables.sql /root/scripts/

COPY spider.cnf /etc/mysql/conf.d/
COPY mysql_init.sh /usr/local/bin/

RUN sed -i -e "s/exec \"\$\@\"/exit 0;/" /usr/local/bin/docker-entrypoint.sh
ENTRYPOINT ["mysql_init.sh"]

やっている内容としましては、

1. Spiderエンジン・MariaDB起動に必要なライブラリを追加します
2. /docker-entrypoint-initdb.d/ に、Docker起動後に実行したいSQL文のファイルを指定します
  • まず、Dockerイメージの中にSpiderをインストールするためのSQLファイル /usr/share/mysql/install_spider.sql があるので、それを移します。
  • またデータベース起動時に実行させたいSQLファイルも合わせて作成し、移します。(今回は例として 01_init.sql に起動時に必要なユーザーやデータベース等の設定を記述します。)
    • なお、テーブルの追加 (create_tables.sql) については後述する理由(「ハマったポイント」を参照)から別の場所に移して別のタイミングで実行させます。
  • ファイル名の昇順に実行されるため、頭に数字等を入れると順序が整理しやすいかもしれません。

01_init.sql の中身の例としては、以下のとおりです。

/*データベースの追加*/
CREATE DATABASE {Spider側のデータベースの名前};
/*ユーザーの追加*/
CREATE USER `{作成したいユーザー名}`@'%' IDENTIFIED BY '{作成したいパスワード名}';
GRANT SELECT, SHOW VIEW ON {作成したデータベース名}.* TO '{作成したユーザー名}'@'%';
/*接続先の追加*/
CREATE OR REPLACE SERVER {サーバー名} FOREIGN DATA WRAPPER mysql OPTIONS(HOST '{リモートのホスト名}', DATABASE '{リモートのDB名}', USER '{リモートのユーザー名}', PASSWORD '{リモートのパスワード名}', PORT 3306);
3. spider.cnf を設置します。

spider.cnf の中身の例は以下のとおりです。適宜ご利用の状況に合わせて書き換えてください。 各パラメータのドキュメントはココにあります

[mysqld]
table_open_cache=6600
max_connections=100
general_log=ON
general_log_file=/var/lib/mysql/mysql-running.log
slow_query_log=ON
slow_query_log_file=/var/lib/mysql/mariadb-slow.log
tmp_table_size=167772160
max_heap_table_size=167772160
open_files_limit=65535
4. Dockerのエントリポイント用のファイルを作成して指定します。

Dockerfile の例では、 mysql_init.sh がそれに当たります。理由と詳細な中身については後述の「ハマったポイント」を参照してください。

5. 最後に、 docker-compose.yml を設置します。

docker-compose.yml の例は以下のとおりです。

version: '2'
services:
  db:
    container_name: container_name
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      MYSQL_ROOT_PASSWORD: test
    ports:
     - "3306:3306"

ハマったポイント

また一方でまだまだ発展途上のエンジンですので、以下のようなエラーも発生してしまいました。 私もまだまだ力不足ゆえ根本解決には至りませんでしたが、回避策を記したいと思います。

1回MySQLが再起動すると、SPIDERでパーティション分割されたDBを読み込めなくなってしまう。

デフォルトのエントリーポイントである/docker-entrypoint.sh mysqldを実行すると、 /docker-entrypoint-initdb.d/ 以下のSQLファイルを実行した後に一回MySQLを再起動してしまいます。

それによって再起動した際に、パーティション分割されたDBを読み込めなくなってしまう問題があるため、/docker-entrypoint-initdb.d/ にてテーブル作成SQLを書いてしまうと、正しく読み込まれなくなってしまう問題があります。

そこで、今回はDockerfileのエントリポイントを以下のファイルにすることで回避しました。(今回の例では mysql_init.sh としております。)

mysql_init.sh の中身の例

#!/bin/bash
/docker-entrypoint.sh mysqld

/etc/init.d/mysql start
mysql -u root -p${MYSQL_ROOT_PASSWORD} -h localhost < /root/scripts/create_tables.sql

while sleep 30; do
   ps aux | grep mysqld | grep -q -v grep
   PROCESS_1_STATUS=$?

  # If the greps above find anything, they exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit 1
  fi
done

内容としてはテーブル作成など再起動後に行いたい処理(この例では create_tables.sql)をその後別途行うようにエントリーポイントのファイルを上書きします。

その後はこの例ですと30秒毎にプロセスの死活監視を行い、もしプロセスが終了してしまった場合は停止させます。 こちらの記事が参考になります

また create_tables.sql の中身の例は以下のとおりです。

USE {Spider側のデータベースの名前};
CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL DEFAULT 0,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=SPIDER DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='table "users"'
PARTITION BY RANGE (`id`)
(PARTITION `p1` VALUES LESS THAN (200000000) COMMENT = 'server "{サーバー名}"' ENGINE = SPIDER,
 PARTITION `p2` VALUES LESS THAN (300000000) COMMENT = 'server "{サーバー名}"' ENGINE = SPIDER,
...)

{サーバー名} の部分には、先程の 01_init.sql にて CREATE OR REPLACE SERVER コマンドを実行した時に指定した名前が入ります。

以下の条件で、UNION ALLが正常にできないケースがある(カラムがずれる、CASE文を挿入するとエラーが発生するなど)

  • SPIDERエンジンのテーブルに対して、SELECT文に固定値もしくはcase文を入れた場合
  • かつ、partitionを使用していないテーブルに対して実行した場合

これについては、パーティションを必要としない(水平分割していない)テーブルについても、パーティションを用意することで回避しました。

Dockerを使用した効果

Docker化したことによって、課題であったサーバーの立て直しのしづらさと実データとの差異は無事解消することが出来ました。

これは実際にはデータを扱っていないことを活かして、更新する際は単にDockerイメージを自動で一から作り直してDockerコンテナを差し替える運用にした結果、以下のことが容易に出来た要因が大きいと考えます。

  • 実データと構造の差異が発生しても差分を考慮して都度クエリを発行せずに、 create_tables.sql の中身を実データベースの show create tables の内容をベースに生成してDockerイメージを差し替えることで対応できる
  • その結果、別途スクリプトで自動化してDockerイメージを作り直すのと同時に実データベースの変更を反映させることも可能になった。

一般的にはマネージドでないサービスでのデータベースの管理はDockerを使っても大変そうかと思いましたが、こと実データの取り扱いがないSpiderエンジンでは、Dockerと合わせることで想像以上に保守が楽になりました!