なぜKotlinを選んだのか? ゲーム作りを進化させる、サーバー共通基盤が出来るまで

ゲームの品質を向上させるサーバー共通基盤の作り方 #2/2 >> 1はこちら

アプリボットで共通基盤ができるまで

竹端尚人氏(以下、竹端):ここまで「共通基盤とはなにか?」というお話や、技術選定のお話をしてきました。ここからは少し過去に遡って、弊社の共通基盤ができあがるまでにどんな流れを踏んできたのか、共通基盤を作るためのノウハウや考え方、組織で発展させていく方法についてお話ししたいと思います。

共通基盤ができるまでということですが、アプリボットにはいくつか時代がありました。

この上の3つの時代は、ずっとJavaを使ってきました。この間も、いろいろと紆余曲折がありました。ちなみに私が入社したのは3番の頃なので、1番と2番は、人の話や過去のコードを見てのお話なので、参考までに聞いていただければと思います。

1番目が「GAE時代」です。

GAEとは、Google App Engineですね。GAEで作ったのは2010年〜2011年ぐらいなので、その当時としては先進的なことをやろうとしていたんだろうなと思います。インフラとしてGAEを使っていて、言語はJavaで、Slim3というGAE用のフレームワークを使って開発をしてきました。

この当時、かなりGAEを使っていたらしく、GAEの利用量が世界でトップぐらいになったことがあるという話でした。

作ったゲームタイトルもうまくいっていて、その頃はよかったんですが、サーバーコストが増加していました。また、新しい技術を使った時には付きものなのですが、世の中にGAEの技術者が不足していて、人材の確保にも苦労していました。

また、世の中にもあまりノウハウがなかったので、次のタイトルからは使用しないことになりました。

(GAE時代の)反省点です。

尖った技術を使っていても、流行らずに使えなくなってしまうこともあります。新しい技術を使うときには、こういったリスクはどうしても伴うものなので、仕方のないところではあります。

Seaser2時代

続いて、2番目がSeaser2時代です。このときにインフラをAWSに移行しました。現在も主にAWSを使っているのですが、フレームワークもGAE依存のSlim3からSeasar2に変更しました。

この時も、一応基盤を作って再利用していこうと考えていて、それを意識した作りではありました。ただ、Seasar2を知っている方は、話を聞いていてピンときているかもしれませんが、この後Seasar2のサポートが終了してしまいました。

またこの当時も、基盤を作るとはいえ、会社として開発体制が整っていなかった部分もあり、基盤としては使うには、パフォーマンスも含めて品質が悪かったところもありました。そんな経緯で、この基盤は捨てることになりました。

反省点としては、この当時は大人数で作っていたんですが、基盤を作るのであれば、しっかりと体制を整えて、品質高く作れるチームでないと厳しいかなと思いました。基盤や共通系のものは、少数精鋭で作ることが多いので、そこは厳しかったかなと思います。また、技術はどうしても廃れてしまうこともあります。これは(開発には)つきものかなと思いました。

Spring Framework時代

Spring Framework時代ということで、ここからは実際に私も関わっている部分になります。本格的に現在の基盤が作られ始めます。

先ほどのSeasar2の基盤をすべて捨てることになったので、今度はSpring Frameworkをベースとした基盤をゼロから開発しました。これが今の基盤の礎になっています。

そして、そのままこの基盤を使用したプロダクトをリリースしました。それがこの『グリモア~私立グリモワール魔法学園~』というプロダクトです。

このタイトルを作り始める段階で、まずは基盤部分を作り、それを使ってそのまま開発をしていきました。

ですので、作ってそのままリリースまで持っていくことができました。比較的タイトなスケジュールだったんですが、すぐにリリースまで進められたので、実績を作ることができ、そのまま「今後使っていこう」という流れに持っていけたのがよかったのかなと思います。

基盤に改修を加えていく

そのあとに、複数の新規プロダクトの開発が並行して始まりました。その開発を進めながら、基盤に改修を加えていきました。

どんなことを行ったのかというと、(スライドを指して)「Exampleプロジェクト」と書いてありますが、いまでいう「StarterKit」です。ここから、各プロジェクトがコピーして作っていました。例えば、この「A」というプロジェクトに機能追加したケースを紹介します。その時に「ほかのプロジェクトでも、共通で使えそうだな」といった部分があれば、新規プロジェクトを横断で管理しているマネージャーに「こういう機能を作りましたよ」と連絡をします。

すると、作った機能をマネージャーがExampleプロジェクトに反映して、ほかのプロジェクトのエンジニアに「こんな機能ができたよ」と伝え、同じように変更を反映して、ほかのプロジェクトに取り込むという流れでした。

この時のよかったこととしては、各プロジェクトで作ったものを、きちんとまとめて展開していたので、いわゆる車輪の再発明が減りました。

また、「基盤を作る人」みたいな役割を作ってしまうと、その人に工数が偏ってしまいます。しかし、各プロジェクトで作ったものを取り込んでいくかたちなので、そこを分散して作れたのもよかったかなと思います。いずれにせよどこのプロジェクトでも作るものなので、それを共通化して使えるということを意識して作って、まとめられたのはよかったと思います。

さらに、これは副次的な効果なんですが、この時代は、毎日夕会みたいなものを開催していました。(夕会では)新規プロダクトのサーバーエンジニアを全員集めて、「こういうものを作りました」というやりとりをしました。また、チャットでやりとりする部屋もあったのですが、そこでプロジェクトを跨いでの交流も生まれました。そもそも、新しい機能を作る段階で相談もできましたし、相談することで基盤化もしやすかったので、その点は非常によかったかなと思います。

そしてKotlin時代へ

こうして新規プロダクトをいろいろ作っているうちに、基盤が成熟してきたので、その次のステップに進もうという話になりました。それが現在で、Kotlin時代です。

去年の6月ごろなんですが、このタイミングで「A.R.T.」という組織ができました。

「Applibot Root Technologies」の略で、技術の共通化や、新たに使う技術の選定について考える組織です。これもブログで取り上げていますので、興味のある方はあとで見てみてください。

当時の基本的な技術セットとしては、先ほどお見せしたものとほとんど変わりませんが、こういった技術セットで開発をしていました。

Javaを使ってきた理由としては、Kotlinのところで話したことと同じような理由なんですが、やはり処理性能の部分や静的型付け言語で大規模の開発がやりやすかったからです。

Java自体はゲームで使っているところはそれほど多くない気はしているのですが、歴史の長い言語なので、世の中にたくさんのノウハウや、いわゆる「黒魔術的なもの」が多く存在しています。そういった部分で、非常に使いやすいです。

ただし、悩みもありました。歴史が長い言語なので、どうしてもレガシーな部分が出てきてしまいます。とくにJavaは、下位互換を意識して作られているため、ドラスティックな変更ができないこともありました。ただ最近は、思い切って変えてきているので、それによって若干使いづらくなっている部分もあります。

また「正直、そろそろ新しい技術に触りたいな」という気持ちもありました。新しい言語にチャレンジしたいという思いがあり、その中で「Kotlinがいいんじゃないか?」という話が上がりました。

再びKotlinの話になってしまいますが、昨年の5月ごろにAndroidの公式開発言語に認定され、「Googleがサポートすると言っているぐらいだから、そんなに簡単に廃れないんじゃないか」という思いもあったりします。

Springが5.0からKotlinを正式にサポートするようになったので、「これは使えそうじゃない?」となり、そこから本格的にKotlinを調べ始めました。

すると、移行するメリットがいろいろ見えてきました。Kotlinならモダンな開発ができたり、Javaと同等の性能を維持できたり……その上、移行コストが低く抑えられるメリットもありました。

Kotlinのメリット

「モダンな開発ができる」とは(どういうことかわかりますか)。これは、Kotlinの機能的な話になってしまうので、興味のある方は、JavaとKotlinの比較について調べてもらえればいいのかなと思います。簡単に説明すると、コードがシンプルだったり安全性が高いといった部分で、モダンな開発ができます。

「Javaと同等の性能を維持できる」というのは、JavaやScalaなど、そういった言語と同じJVM言語なので、最終的にコンパイルされた実行ファイルはJavaとほぼ同等です。

まったく同じではありませんが、性能を維持できるということで、パフォーマンス的な問題はないかなと思いました。

「移行コストを低く抑えられる」部分に関しては、もともとKotlinは「Javaの資産を生かして新しいモダンな開発をしたい」ということで、JetBrainsという会社が考えて作ったものだったので、そもそも移行はしやすくなっていました。

JavaからKotlinを呼んだり、KotlinからJavaを呼んだりといったことが可能です。また、Springのサポートもあるので、ほかの言語と比較しても移行コストが低く抑えられると思いました。

まとめると、モダンな実装ができて、Javaの資産を生かせて、かつ、移行コストも低く抑えられるということで、Javaを使っているシステムにはいいこと尽くしだったため、移行を決断しました。

ただ、全部Kotlinに移行したわけではありません。ほぼ移行しているんですが、右側のO/Rマッパーの部分だけは、相性の問題かKotlin化すると挙動の怪しい部分もあったので、Javaのまま使っています。

こういう時に一部はJavaのままでも使えるというのも、Kotlinのいいところかなと思います。

実際にどうだったかというと、随所でシンプルにコードが書けるようになって、コード行数も2割ぐらい減りました。あとは、先ほど言った安全性の高い言語なので、より堅牢なコードを書けるようになりました。そして、Javaエンジニアでもすんなり書き始められた、Kotlin化してよかったなと思っています。

同時期に対応したこと

続いて、同時期に対応したアップデートについてです。「Kotlin時代」といっていますが、ほかにもアップデートしているものがあります。

1つはgRPCです。

もともとgRPCやHTTP/2のパフォーマンスの高さには注目していました。HTTP/2は、例えば画像や音声ファイルなどのリソースのダウンロード部分に関して、2〜3倍のスピードになったらかなり影響があるので、注目すべきと感じて見ていました。

また、A.R.T.を設立したり、基盤をいろいろと改修するタイミングだったので、あわせてここにもチャレンジしてみようという話になりました。

先ほど言ったように、Unityが標準でgRPCに対応してなかったので、クライアント側は自前でいろいろ検証したり実装しようと考えていました。

いろいろやったんですが、ここで開発を後押しする出来事がありました。それは、最近サイバーエージェントグループでCysharpという会社を立ち上げた、元グラニのCTO河合さんの参画です。

この方は、もともとグラニでUnityとgRPCを使って開発をしていて、事例として紹介されていました。おそらく、国内で数少ないUnityとgRPCの技術を用いて開発した事例だと思います。

そんな方に参画いただき、gRPC基盤開発のサポートをしてもらいました。いろいろとレビューもしてもらっているので、基盤の完成度や信頼性も高まってきて、実際にいけそうな雰囲気が高まってきました。

あとこれはただの宣伝なんですが、その河合さんが書いたブログ記事が出たので、よろしければ見てみてください。

gRPC対応で開発したもの

gRPC対応で開発したものとしては、InterceptorやBaseControllerといった、全部のControllerで継承するクラスを、gRPCに対応したかたちに変更しました。

また、gRPCはデフォルトでJSONではなくProtocol Buffersを通信の形式として使っているので、RequestやResponseの自動生成もProtocol Buffersからできます。もともとProtocol Buffers側で用意されている自動生成の機構があるので、それを使いました。

問題だったのが、これまで負荷試験でJMeterを使っていたんですが、JMeterはgRPCに対応していませんでした。おそらく、これに対応しているものはあまりありませんが、比較的名前が通っているツールではGatlingが対応していたので、Gatlingで負荷試験シナリオを作りました。

負荷試験ができないのはサーバーとしては致命的な問題なので、ここはけっこう苦しんだところでした。

今後のプロダクトでは、標準として通信はRESTではなくgRPCを使用していこうと思います。最近、ちょうどgRPCがよく話題になるので、先に使っておいてよかったなと、非常にうれしく思っています。

その他のアップデートとしては、ローカル環境の構築をDocker化したり、SpringをSpringBootへ変更したりです。他には、ビルドツールをMavenからGradleに移行しました。また、その他にも使っているライブラリのバージョンアップをしたり、既存のもののアップデートを随時行っています。

これは、プロジェクト任せにしてしまうとなかなか進めづらいですが、基盤として作ってあるため、そこをアップデートする分にはそれほど事故も起きないです。ですので、どんどん基盤をアップデートして、現在の基盤が完成しました。

Kotlin時代で良かったこと

Kotlin時代でよかったこととしては、現状の技術に課題感があり、それを代替する強い魅力を感じるようなものがあれば、言語レベルでの変更は大変ですが、思い切って変えてみるのも良いというのが分かったことです。

また、タイトルはリリースしていませんが、技術的チャレンジをした成功事例を作れたのはよかったと思っています。JavaからKotlinへの移行に関しては、だいぶ都合がよすぎたので、ここまでやりやすいことはなかなかないとは思います。それでも、今の技術になにか強い課題を感じたら、こうしたことを考えてみるのもよいのではないでしょうか。

この章のまとめとしては、会社全体のエンジニアを巻き込んで、作る段階から協力して進めることが重要かなということです。

先ほどお話ししたとおり、基盤チームを最初から作って、そこがずっと開発していくという形にしてしまうと、その人たちに全部のしかかってきてしまいます。また、それが「各プロジェクトで絶対使ってください」ということになると、「使わされている感」が出てしまうこともあります。かつ、プロジェクトにいない人が作ることになるので、プロジェクトで使いたいものとの相違も生まれてしまいます。

しかし、こうして全体を巻き込んだことで、各プロジェクトで必要だから作った機能を全体で使う流れになる。そこを巻き込んで、協力していくのは非常に大事です。

あとは、時には失敗して作り直すことも必要です。今の基盤は(作り直しは)やらずに走っていますが、これまで2回ほど、捨てたものがありました。基盤だからといって変にこだわり続けて、品質の悪いものを使い続けるのは、それこそ本末転倒になってしまうので、そこは思い切って作り直すことも必要だと思います。

あとこれはタイミング次第ですが、共通基盤チームがあれば、よりチャレンジすることもできるかなと思います。

最初は弊社にも(そうしたチームは)なく、基盤を各プロジェクトで作ってできあがってきたなかで、メンテナンスするチームができたという流れは良かったと思います。かつ、そういうところに関わっていた人たちが、現在基盤チームとして活躍しているので、組織として浸透しやすかったのだと思います。

今後の展望

それでは最後に、今後の展望についてお話ししていきたいと思います。

今後やっていきたいこととして、1つはマイクロサービス化です。実はすでに取り組んでいて、まだプロジェクト側には導入していませんが、iOSとAndroidのプラットフォーム課金部分をマイクロサービス化したいなと考えています。

共通で使用する課金のAPIサーバーをA.R.T.で作り、そこにアクセスするためのSDKを用意しておいて、各プロダクトでは基本的にSDKを導入するだけで実装できるかたちにしていきたいと考えています。

まだ導入はこれからなんですが、すでにSDKは完成しているので、いくつか試そうかなというところです。

また、ここも力を入れているところなんですが管理画面基盤を作ろうとしています。

マスターデータの登録やデバッグ機能など、各プロジェクトで必ず作るものではありますが、後回しにされがちです。「アプリの機能のほうが大切なので」となることも多く、だいたい最後のほうにガッと作ります。

また、「本当は機能を追加するたびにデバッグ機能を追加しなきゃいけないのに、できない」といったこともよくあります。その基盤を作ってあげて、データ登録や基本的なものはそれに積んであげると……。これもStarterKitの中に入れるといいですね。

さらに、プロダクト側でも機能を追加しやすいような設計を用意したいと考えています。画面の部分を作ることは、サーバーエンジニアだと嫌がることが多いですが、そこをやりやすいようにしたいと思っています。

あとは、最新の基盤を使った開発ということで、これは半分宣伝になってしまいますが、『BLADE XLOAD』というタイトルがあり、Javaの最新版を使っています。

作り始めた時期の関係もあって、Kotlinに変えるまではいきませんでしたが、Javaのライブラリをアップデートした、最新状態のものを使っています。

また、こちらは私が関わっているタイトルです。『SEVEN’s CODE』では、KotlinとgRPCを使った最新の基盤で開発をしています。

実際、gRPCなどもここで使用して開発していて、それほど大きな問題は起きていないので、実際にリリースして実績が出たら、ゲーム業界でのUnityとgRPCの事例としても非常にいいものになるかなと思っております。

こちらは2つともTGSで、今年発表されたものになります。

共通基盤が組織にもたらすもの

最後になりますが、共通基盤の開発によって、プロジェクトの開発工数は大きく下がります。なぜこんな話をしているかというと、実際にプロジェクトで使う側として、すごく楽になったと感じているので、とても重要だなと思っています。

同時に、すでに使ったことのあるプログラムが使われているので、そこを開発する必要もないですし、品質の向上にもつながるかなと思います。

長い目で見て、「組織として良いものは再利用していく」ということを可能にするのは、すごく大事なことだと感じました。そうすることで、同じ失敗を繰り返すこともないですし、「車輪の再発明をしない」といったところは、組織全体としてとても大切なことだと思います。

プロジェクトがどのぐらいあるかによって重要度は変わりますが、共通基盤の開発を、ぜひ検討いただければと思います。

以上になります。ご清聴ありがとうございました。

(会場拍手)

Java→Kotlinに移行する上でハマったこと

司会者:ありがとうございました。質問がある方はいらっしゃいますでしょうか?

質問者1:JavaからKotlinに移行したときに、なにか苦労したポイントはありますか? Kotlin推しの印象でしたが、やはり言語を変えることで、なにかあったんじゃないかなと。

竹端:そうですね、苦労したことはいっぱいあります。細かいところはけっこう大変でした。大枠の部分は、JavaとKotlinは同じように使えるんです。書き方も、構文が違うだけで同じ設計で使えるので、基本的には問題はないです。

移行のやり方としては、IntelliJの機能を使ってJavaからKotlinに変換ということを、全部総当たりして行いました。ただ、その当時はあまり精度がわかっていなかったので、コンパイルエラーが大量に出て、それを直す作業を2ヶ月ぐらい、ずっとやっていました。

そこで、そもそもその変換がコンパイルエラーにされてしまうものもあったり、ラムダ式の書き方など似ているけど微妙に違う部分があったりしたので、それを調べて対応するのが大変でした。かつ、日本語の情報が少なかったので、Stack Overflowなどで英語の記事を調べながら進めていきました。

質問者1:なにかわからないことがあって「これだ!」と思って見てみると「僕もわからない」って並んでたりしますよね。

竹端:そうですね。Qに書いて、そのまま終わっちゃったやつとかいくつかあったりするので。

質問者1:ありがとうございます。

竹端:新しい技術を使うという話では、日本語の情報が少ないという大変さはありますね。Kotlinに限らずです。ですので、検索するときは日本語を入れないほうがいいです。調べるときは、「〇〇とは」と入力すると思いますが、「とは」を含めずに、あえて英語のワードで調べたほうがいいですね。

司会者:ありがとうございます。ほかにご質問がある方はいらっしゃいますか?

ドキュメントは用意しているか?

質問者2:「こういう技術を使っているよ」というお話がたくさん出てきましたが、基盤として成熟していく中で、使い方やドキュメントはきちんと整備されていますか?

竹端:そうですね。一応、最低限のREADMEは用意しています。細かい実装の仕方などは、例えば、もともとあるものをコピーして作ってもらえれば、なんとなくはわかるかなと思います。

また、起動する手順や自動生成する手順、Gradleの各タスクの意味など、「このタスクはこういうことをやってる」「パラメータにはこういうものが入っている」などのところは、きちんと書いてあるので、そこを押さえていれば、実装部分に関してはソースを見てもらえればだいたいできる状態にはなっていますね。

質問者2:ある程度動くようなかたちで出てくるから、見れば理解できるという考え方でしょうか?

竹端:そうですね。極論、StarterKitがあれば、それだけでちょっとしたゲームなら作れますね。

質問者2:ありがとうございました。

不具合が見つかったときは誰が直すのか?

司会者:ありがとうございます。ほかにご質問がある方いらっしゃいますでしょうか?

質問者3:以前は各プロジェクトから実装したものをデバッグして、コピーして使っているというお話がありましたが、不具合が見つかった場合は、その基盤部分にどんな形でアップデートをかけるんでしょうか?

竹端:新しい基盤を作り始めてから、これまでそういったことが起きていないので、数はありませんが、一応、各プロジェクトからプルリクを投げるようにしています。StarterKitをForkしているので、そのまま同じコミット、同じプルリクを投げることができます。そんなかたちで対応するようにしています

基盤チームで全部直すと、工数的にもそこで滞ってしまうことがあるので、各プロジェクトで気づいた人が直すかたちにしています。

質問者3:今後もそのかたちで作っていく予定でしょうか?

竹端:一応はそのつもりです。ただ、どうしても各プロジェクトで、それぞれ自分たちのタスクがあるので、それがどこまで続けられるかは、探り探りという感じですね。

質問者3:ありがとうございます。

司会者:ありがとうございます。ほかにご質問がある方はいらっしゃいますでしょうか?

質問者3:もう1ついいですか?

竹端:はい。

質問者3:7〜8年ぐらい前にScalaを学んだのですが失敗しました。Scalaは(基盤の変更の際に)話に出なかったのですか?

竹端:話には出たと思います。ただ、メリットがそこまで……。極論、Javaのままでも動くという状況だったため、そこでわざわざコストをかけて、移行してまでやる魅力はありませんでした。

Kotlinは、Springの存在が大きかったですね。フレームワークが対応しているのと、あとはGoogleがサポートしている点です。

質問者3:そこは大きいですね。

竹端:「たぶんこの技術は死なないだろ」という安心感が大きかったですね。

質問者3:ありがとうございます。

司会者:ありがとうございます。それでは、あらためて拍手をいただければと思います。

(会場拍手)