Slide 1

Slide 1 text

Rails‑API Way in Aiming 1

Slide 2

Slide 2 text

自己紹介 名前: 植森 康友 役職: ソフトウェアエンジニア 経歴: 2年目 担当: WebAPI 開発 管理ツー ル開発 インフラ?( ミドルウェア~) ansible Docker td‑agent bigquery 2

Slide 3

Slide 3 text

今回お話すること Aiming について Aiming の開発スタイル MMORPG のWebAPI 開発について Aiming でのWebAPI on Rails 3

Slide 4

Slide 4 text

Aiming について 企画、 開発~ 運営までを行うゲー ム開発会社 オンラインゲー ムの開発を得意としている 各種人材募集中です! 4

Slide 5

Slide 5 text

代表作: 剣と魔法のログレス いにしえの女神 800 万ダウンロー ド達成 スマホで簡単MMORPG 5

Slide 6

Slide 6 text

Aiming の開発スタイル 6

Slide 7

Slide 7 text

採用技術の選定: 各プロジェクトが適切だと思ったものを選ぶ プロジェクトメンバー の技術スタックがさまざま C#, C++, Ruby/Rails, PHP... 外部委託をする/ しない 開発するゲー ムの方向性 アクションがメインなのかRPG がメインなのか リアルタイムに通信をするのがどこからどこまでなのか プロジェクトごとの事情 納期 7

Slide 8

Slide 8 text

採用されやすい技術/ 言語 クライアント C#(Unity): 新規開発はほぼUnity C++(cocos‑2dx)、 ブラウザ: 剣と魔法のログレスなど リアルタイム C++: 昔からPC ゲー ムなどを作ってきたエンジニアが多数在 籍している C#: クライアントと処理を共通化しやすいため、 一部プロジ ェクトが採用 WebAPI Ruby(Rails): 新規開発の多くはほぼRails Python(Flask): 剣と魔法のログレスなど 8

Slide 9

Slide 9 text

その他 Websocket: チャットなどで一部のプロジェクトが採用 NodeJS Ruby 9

Slide 10

Slide 10 text

まとめ かなりカオスな多様性のある開発をしてきた 新規開発は大まかな構成が固まりつつある クライアント:Unity リアルタイム 大阪:C++ 東京:C# WebAPI:Rails 10

Slide 11

Slide 11 text

MMORPG のWebAPI 開発について 11

Slide 12

Slide 12 text

大なり小なりリアルタイム性が必要 大人数がそのリアルタイムを共有する 他者とのコミュニケー ションがある MMORPG の特徴 ※ 注) 剣と魔法のログレスではRails は使っていません 12

Slide 13

Slide 13 text

Q. この画面を表示するのにどういうAPI が必要でしょうか(10 秒) 13

Slide 14

Slide 14 text

リアルタイムサー バの役割はどこま で? チャットは何で通信してる? クライアントはどのデー タをどこまで キャッシュしてる? 見た目情報はクライアントが直接 WebAPI から取得する? リアルタイ ムサー バが教える? 考える事多すぎ\(^o^)/ A. 要件による 14

Slide 15

Slide 15 text

リアルタイムサー バ エリアチャット キャラクタの位置と見た目 チャンネル情報 WebAPI サー バ 自分のレベル、 ジョブ、 所有ポイン ト、 見た目情報などはログイン情報と してWebAPI から 剣と魔法のログレスの場合 15

Slide 16

Slide 16 text

この画面で欲しい情報 キャラクター のステー タス キャラクター の装備アイテム キャラクター の見た目情報 各種装備のレベル アイテム所持数 考えたいこと 全武器の情報はこの時点で必要? 他のタブの情報はこの時点で必要? 装備が変更されたらいつ送る? ステー タスはどっちで計算する? 例) 装備画面を表示する場合 16

Slide 17

Slide 17 text

MMORPG のWebAPI 開発のポイント リアルタイム/WebAPI サー バ/ クライアントそれぞれがどこまで やるのか線引をする 一つの責務はなるべくどちらか片方のサー バだけが持つ なるべく通信頻度/ 通信量を減らす できるだけ一度の通信で取ってこれるようにAPI を設計する その通信でどこまで取ってくるかはクライアントと相談 「 使う側が使いやすいAPI」 を設計する 一番工数がかかるのはクライアント側 WebAPI 側の仕様に合わせてクライアント側が頑張らなくて良 いようにする 17

Slide 18

Slide 18 text

Aiming でのWebAPI on Rails 18

Slide 19

Slide 19 text

Aiming におけるWebAPI の実装スタイル RPC スタイル REST API ではなく、RPC スタイルを採用 必要な情報群と1 1 になるエンドポイントを作る コー ドジェネレー タの利用 メッセー ジの型と形式を定義するファイル 定義ファイルから必要なファイルを自動生成する 19

Slide 20

Slide 20 text

RPC スタイル 20

Slide 21

Slide 21 text

RPC? Remote Procedure Call プログラムからネットワー クを通じて手続きを呼び出す 実行する手続きと引数を要求メッセー ジとしてサー バに送信する 21

Slide 22

Slide 22 text

RPC スタイルなRails ‑ routes G E T / v 1 / s a m p l e / g e t P O S T / v 1 / s a m p l e / c r e a t e P O S T / v 1 / s a m p l e / u p d a t e P O S T / v 1 / s a m p l e / d e l e t e P O S T / v 1 / s a m p l e / n a m e / u p d a t e G E T / v 1 / c h a r a c t e r / g e t G E T / v 1 / l o g i n _ c h a r a c t e r / g e t HTTP メソッドはPOST とGET のみ GET 不要説も リソー ス名/ 動詞 をエンドポイントとしてルー ティング ネストもOK 22

Slide 23

Slide 23 text

RPC スタイルなRails ‑ controller m o d u l e V 1 m o d u l e S a m p l e c l a s s G e t C o n t r o l l e r r e s c u e _ f r o m ( A c t i v e R e c o r d : : R e c o r d N o t F o u n d ) d o r e n d e r _ e r r o r ( : r e c o r d _ n o t _ f o u n d ) e n d d e f s e r v i c e s a m p l e = S a m p l e . f i n d ( p a r a m s [ : c h a r a c t e r _ i d ] ) r e n d e r _ a p i ( s a m p l e : s a m p l e ) e n d e n d e n d e n d コントロー ラはルー ティングと1 1 コントロー ラはservice アクションだけを持つという規約 render_api, render_error などrender をラップした専用メソッドでレ スポンスを送る 23

Slide 24

Slide 24 text

なぜRPC スタイルなのか クライアント→WebAPI の部分はラップして抽象化されている どうせURL もメソッドも利用側から見えていない リソー ス指向のメリットが薄い G E T / v 1 / l o g i n _ c h a r a c t e r みたいなのが大量に作られる とある場面でだけ必要なオー ルインワンな取得系API 開発中は要件が変わりやすいので柔軟に対応する必要がある 仕様変更時にURL が変わらなくても良いようにしたい… Unity 側(WWW クラス) の仕様の問題 POST とGET にしか対応してなかった GET 時のクエリストリングを自前で組み立てる必要があった Unity5.4 から提供されるUnityWebRequest クラスでかなりマ シにはなった 24

Slide 25

Slide 25 text

コー ドジェネレー タ 25

Slide 26

Slide 26 text

IDL( インター フェー ス記述言語) WebAPI ⇔ リアルタイムサー バー・ クライアント間の通信プロトコ ルを定義するもの 言語間の型の違いなどを吸収する 定義から実装に必要なコー ドを自動生成する 26

Slide 27

Slide 27 text

プロトコル定義の目的 クライアント・ リアルタイムサー バ・API サー バでの設定の共有 実装が独自に進んでいく危険性を防ぐ 破壊的変更が入ったときにCI で検知する ドキュメントの生成がより用意になる クライアントに対する mock サー バー、 あるいは サー バー に対する テスト用クライアントの自動生成がより容易になる 27

Slide 28

Slide 28 text

IDL の実装 ruby 製のパー サー( コマンドラインツー ル) パー スした内容はツリー 形式の情報になっている Plugin 形式を採用 パー スした内容を受け取って、template を評価してコー ドを生 成する template はerb で記述 専用のDSL で記述された内容を読み込んで、 設定された内容を出力 する 28

Slide 29

Slide 29 text

通信プロトコルの定義 r p c ( : s a m p l e _ c r e a t e ) { u r l ' / s a m p l e / c r e a t e ' m e t h o d ' P O S T ' d e s c r i p t i o n ' サンプルを作るよ' e r r o r s { i t e m : r e c o r d _ n o t _ u n i q u e , ' 名前が重複したよ' } r e q u e s t { p a r a m ' n a m e ' , : s t r i n g , ' 素敵な名前' } r e s p o n s e { p a r a m ' s a m p l e ' , : s a m p l e , ' 作成したさんぷる' } } 29

Slide 30

Slide 30 text

通信プロトコルの定義( エンドポイント) r p c ( : s a m p l e _ c r e a t e ) { u r l ' / s a m p l e / c r e a t e ' # U R L のエンドポイントを指定 m e t h o d ' P O S T ' # H T T P M e t h o d を指定 d e s c r i p t i o n ' サンプルを作るよ' # R P C の説明 } R a i l s . a p p l i c a t i o n . r o u t e s . d r a w d o n a m e s p a c e : v 1 d o n a m e s p a c e : s a m p l e d o n a m e s p a c e : c r e a t e d o m a t c h ' c r e a t e ' , c o n t r o l l e r : : c r e a t e , a c t i o n : : s e r v i c e , v i a : : p o s t e n d e n d e n d e n d 30

Slide 31

Slide 31 text

通信プロトコルの定義( エラー) r p c ( : s a m p l e _ c r e a t e ) { e r r o r s { # エラー の名前と説明 i t e m : r e c o r d _ n o t _ u n i q u e , ' 名前が重複したよ' } } m o d u l e S a m p l e m o d u l e C r e a t e m o d u l e E r r o r # e r r o r _ c o d e : 1 0 0 1 # d e s c r i p t i o n : 名前が重複したよ c l a s s R e c o r d N o t U n i q u e < : : R p c E r r o r : : R p c E r r o r B a s e d e f s e l f . e r r o r _ c o d e 1 0 0 1 e n d e n d e n d e n d e n d 31

Slide 32

Slide 32 text

通信プロトコルの定義( メッセー ジの形式) r p c ( : s a m p l e _ c r e a t e ) { # リクエストの定義 r e q u e s t { # キー 名、 型、 説明 p a r a m ' n a m e ' , : s t r i n g , ' 素敵な名前' } # レスポンスの定義 r e s p o n s e { p a r a m ' s a m p l e ' , : s a m p l e , ' 作成したさんぷる' } } c l a s s R e q u e s t T y p e < T y p e : : B a s e a t t r i b u t e : n a m e , S t r i n g e n d c l a s s R e s p o n s e T y p e < T y p e : : B a s e a t t r i b u t e : s a m p l e , T y p e : : S a m p l e e n d 32

Slide 33

Slide 33 text

通信プロトコルの定義( 型定義) # 型定義 t y p e ( : s a m p l e ) { p a r a m ' i d ' , : i n t , ' I D ' p a r a m ' n a m e ' , : s t r i n g , ' 名前' } r p c ( : s a m p l e _ c r e a t e ) { r e s p o n s e { # 利用例 p a r a m ' s a m p l e ' , : s a m p l e , ' 作成したさんぷる' } } c l a s s T y p e : : S a m p l e < T y p e : : B a s e a t t r i b u t e : i d , I n t e g e r a t t r i b u t e : n a m e , S t r i n g e n d c l a s s R e s p o n s e T y p e < T y p e : : B a s e a t t r i b u t e : s a m p l e , T y p e : : S a m p l e e n d 33

Slide 34

Slide 34 text

ここまでのコー ドをすべて自動生成する routing, controller, type class などをすべて自動生成 拡張しているプロジェクトでは以下のようなものも テストコー ド (request spec) fixture (factory_girl) service class / service class spec 34

Slide 35

Slide 35 text

Rails 側の実装例 35

Slide 36

Slide 36 text

Rails 側の実装例 d e f p a r a m s # パラメー タの検証を行い、 失敗したらエラー を発生させる # S t r o n g P a r a m e t e r とは違い、 型など厳密なチェックを行なう R e q u e s t T y p e . n e w ( s u p e r ) e n d d e f s e r v i c e s a m p l e = S a m p l e . c r e a t e ! ( n a m e : p a r a m s [ : n a m e ] ) r e n d e r _ a p i ( s a m p l e : T y p e : : S a m p l e . n e w ( i d : s a m p l e . i d , n a m e : s a m p l e . n a m e ) ) e n d 36

Slide 37

Slide 37 text

Rails 側の実装例 d e f r e n d e r _ a p i ( r e s p o n s e ) # パラメー タの検証を行い、 失敗したらエラー を発生させる b o d y = R e s p o n s e T y p e . n e w ( r e s p o n s e ) r e s p o n d _ t o d o | f o r m a t | f o r m a t . m s g p a c k d o r e n d e r ( c o n t e n t _ t y p e : ' a p p l i c a t i o n / x ‐ m s g p a c k ' , b o d y : b o d y . t o _ m s g p a c k ) e n d # 開発時のみJ S O N を許可する事もできる f o r m a t . j s o n d o r e n d e r j s o n : b o d y . t o _ j s o n e n d i f R a i l s . d e v e l o p m e n t ? e n d e n d 37

Slide 38

Slide 38 text

Client 側の実装例 p r i v a t e v o i d S e n d S a m p l e C r e a t e R e q u e s t ( s t r i n g n a m e ) { S a m p l e C r e a t e R e q u e s t r e q u e s t = n e w S a m p l e C r e a t e R e q u e s t ( ) ; r e q u e s t . n a m e = n a m e ; / / U R L , メソッドなどがラップされた、 自動生成されるクラス S a m p l e C r e a t e a p i = n e w S a m p l e C r e a t e ( r e q u e s t ) ; / / コー ルバックの登録 a p i . o n C o m p l e t e = O n S a m p l e C r e a t e C o m p l e t e ; a p i . o n E r r o r = O n S a m p l e C r e a t e E r r o r ; W e b R e q u e s t e r . R e q u e s t ( a p i ) } 38

Slide 39

Slide 39 text

型の違いの吸収 コー ドジェネレー タが生成するファイルで吸収する t y p e ( : s a m p l e ) { p a r a m : i d , : i n t 6 4 } c l a s s T y p e : : S a m p l e a t t r i b u t e : i d , I n t e g e r # r u b y 側はI n t e g e r として扱う e n d c l a s s S a m p l e { p u b l i c l o n g i d ; / / C # 側はl o n g として扱う } s t r u c t S a m p l e { i n t 6 4 _ t i d ; / / C + + 側はi n t 6 4 として扱う } 39

Slide 40

Slide 40 text

WebAPI 開発でRails を使うこと 40

Slide 41

Slide 41 text

迫りくるマイクロサー ビスの波 以前: いくつかのプロジェクトでリアルタイムサー バが巨大化しす ぎていた リアルタイムサー バがほとんどなんでもやる WebAPI は必要最小限のサブシステム 現在: 各々 が得意なことを役割分担する方向へ自然と移行 パフォー マンスが必要なものはリアルタイムサー バ パフォー マンスが必要ないものはWebAPI サー バ 41

Slide 42

Slide 42 text

Pros: 実装の速さ 実装だけで見れば、 簡単なAPI ならテスト込みでも1~2 時間程度で 実装できる 難しいところも、 実装よりも要件定義などの方が時間がかかること がほとんど 42

Slide 43

Slide 43 text

Pros: エコシステムが充実している Rack middleware, Gem などのエコシステム 難しい実装でも既存gem を使う、 あるいは参考にして実行すれ ば実装が楽に終わる ex) DB の水平分割など Rails 自体のエコシステム 長く使われてきたフレー ムワー クだけあって、rails 自体にはほ とんど手を入れる必要なくやりたい実装が出来る 「 こんな機能あったのか」 となることも少なくない 43

Slide 44

Slide 44 text

Pros: アー キテクチャが枯れている 実装面のベストプラクティスが豊富 fat controller, fat model などの問題を経て設計パター ンが成熟 している 社内に経験豊富なエンジニアがいるというのも強み 44

Slide 45

Slide 45 text

Pros: 管理ツー ルの実装が楽 ゲー ム開発では運営・ 管理を行うためのツー ルが必須 例) ギフトの配布、 ユー ザサポー ト、KPI 分析など API サー バがRails で作られているため、 管理ツー ル側でmodel やモ ジュー ルなどを流用しやすい 45

Slide 46

Slide 46 text

Cons: パフォー マンス やはりパフォー マンスは静的言語に比べると劣る 最近はGolang やPhoenix などの台頭もある 46

Slide 47

Slide 47 text

Cons: Rails エンジニアの数が少ない 正確には「 ゲー ム業界に来るRails エンジニア」 の数が少ない 管理ツー ルなどのWeb アプリケー ションから共通基盤、WebAPI と 幅広い領域をカバー するだけの人が足りていないのが現状 47

Slide 48

Slide 48 text

そこで、 48

Slide 49

Slide 49 text

We are hiring! Aiming ではゲー ム開発に興味のある、 ゲー ムの好きなWeb エンジニアを募集しています! https://aiming‑inc.com/ja/jobs/ 49

Slide 50

Slide 50 text

ご静聴ありがとうございました 50

Slide 51

Slide 51 text

質疑応答 51