Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Rails api way in aiming

Rails api way in aiming

「ゲーム開発の【ごっついい感じ】 ~ ソーシャルゲーム開発で使える 『ゲームAPI開発』 ~ ビヨンド勉強会 #7」での発表資料です。
https://beyond.doorkeeper.jp/events/56002

Yasutomo Uemori

February 08, 2017
Tweet

More Decks by Yasutomo Uemori

Other Decks in Programming

Transcript

  1. 自己紹介 名前: 植森 康友 役職: ソフトウェアエンジニア 経歴: 2年目 担当: WebAPI

    開発 管理ツー ル開発 インフラ?( ミドルウェア~) ansible Docker td‑agent bigquery 2
  2. 採用技術の選定: 各プロジェクトが適切だと思ったものを選ぶ プロジェクトメンバー の技術スタックがさまざま C#, C++, Ruby/Rails, PHP... 外部委託をする/ しない

    開発するゲー ムの方向性 アクションがメインなのかRPG がメインなのか リアルタイムに通信をするのがどこからどこまでなのか プロジェクトごとの事情 納期 7
  3. 採用されやすい技術/ 言語 クライアント C#(Unity): 新規開発はほぼUnity C++(cocos‑2dx)、 ブラウザ: 剣と魔法のログレスなど リアルタイム C++:

    昔からPC ゲー ムなどを作ってきたエンジニアが多数在 籍している C#: クライアントと処理を共通化しやすいため、 一部プロジ ェクトが採用 WebAPI Ruby(Rails): 新規開発の多くはほぼRails Python(Flask): 剣と魔法のログレスなど 8
  4. リアルタイムサー バ エリアチャット キャラクタの位置と見た目 チャンネル情報 WebAPI サー バ 自分のレベル、 ジョブ、

    所有ポイン ト、 見た目情報などはログイン情報と してWebAPI から 剣と魔法のログレスの場合 15
  5. この画面で欲しい情報 キャラクター のステー タス キャラクター の装備アイテム キャラクター の見た目情報 各種装備のレベル アイテム所持数

    考えたいこと 全武器の情報はこの時点で必要? 他のタブの情報はこの時点で必要? 装備が変更されたらいつ送る? ステー タスはどっちで計算する? 例) 装備画面を表示する場合 16
  6. MMORPG のWebAPI 開発のポイント リアルタイム/WebAPI サー バ/ クライアントそれぞれがどこまで やるのか線引をする 一つの責務はなるべくどちらか片方のサー バだけが持つ

    なるべく通信頻度/ 通信量を減らす できるだけ一度の通信で取ってこれるようにAPI を設計する その通信でどこまで取ってくるかはクライアントと相談 「 使う側が使いやすいAPI」 を設計する 一番工数がかかるのはクライアント側 WebAPI 側の仕様に合わせてクライアント側が頑張らなくて良 いようにする 17
  7. Aiming におけるWebAPI の実装スタイル RPC スタイル REST API ではなく、RPC スタイルを採用 必要な情報群と1

    1 になるエンドポイントを作る コー ドジェネレー タの利用 メッセー ジの型と形式を定義するファイル 定義ファイルから必要なファイルを自動生成する 19
  8. 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
  9. 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
  10. なぜ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
  11. IDL( インター フェー ス記述言語) WebAPI ⇔ リアルタイムサー バー・ クライアント間の通信プロトコ ルを定義するもの

    言語間の型の違いなどを吸収する 定義から実装に必要なコー ドを自動生成する 26
  12. IDL の実装 ruby 製のパー サー( コマンドラインツー ル) パー スした内容はツリー 形式の情報になっている

    Plugin 形式を採用 パー スした内容を受け取って、template を評価してコー ドを生 成する template はerb で記述 専用のDSL で記述された内容を読み込んで、 設定された内容を出力 する 28
  13. 通信プロトコルの定義 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
  14. 通信プロトコルの定義( エンドポイント) 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
  15. 通信プロトコルの定義( エラー) 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
  16. 通信プロトコルの定義( メッセー ジの形式) 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
  17. 通信プロトコルの定義( 型定義) # 型定義 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
  18. 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
  19. 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
  20. 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
  21. 型の違いの吸収 コー ドジェネレー タが生成するファイルで吸収する 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
  22. 迫りくるマイクロサー ビスの波 以前: いくつかのプロジェクトでリアルタイムサー バが巨大化しす ぎていた リアルタイムサー バがほとんどなんでもやる WebAPI は必要最小限のサブシステム

    現在: 各々 が得意なことを役割分担する方向へ自然と移行 パフォー マンスが必要なものはリアルタイムサー バ パフォー マンスが必要ないものはWebAPI サー バ 41
  23. Pros: エコシステムが充実している Rack middleware, Gem などのエコシステム 難しい実装でも既存gem を使う、 あるいは参考にして実行すれ ば実装が楽に終わる

    ex) DB の水平分割など Rails 自体のエコシステム 長く使われてきたフレー ムワー クだけあって、rails 自体にはほ とんど手を入れる必要なくやりたい実装が出来る 「 こんな機能あったのか」 となることも少なくない 43
  24. Pros: 管理ツー ルの実装が楽 ゲー ム開発では運営・ 管理を行うためのツー ルが必須 例) ギフトの配布、 ユー

    ザサポー ト、KPI 分析など API サー バがRails で作られているため、 管理ツー ル側でmodel やモ ジュー ルなどを流用しやすい 45
  25. Cons: Rails エンジニアの数が少ない 正確には「 ゲー ム業界に来るRails エンジニア」 の数が少ない 管理ツー ルなどのWeb

    アプリケー ションから共通基盤、WebAPI と 幅広い領域をカバー するだけの人が足りていないのが現状 47