その他
    ホーム 職種別 エンジニア ソーシャルゲームにおけるミッション機能のサーバーサイド実装の考察:問題編
    ソーシャルゲームにおけるミッション機能のサーバーサイド実装の考察:問題編
     

    ソーシャルゲームにおけるミッション機能のサーバーサイド実装の考察:問題編

    アピリッツ コンテンツデザイン部の金井と申します。幾つかに渡ってソーシャルゲームにおけるミッション機能に対して書いていこうと思います。

    関連:第二回「思索編」はこちら! → ソーシャルゲームにおけるミッション機能のサーバーサイド実装の考察:思考編

    前置き:ミッション機能の構造的問題

    新しいプロジェクトに入り、ミッション機能の秘伝のソースを目の当たりにしたエンジニア

     ソーシャルゲームにおけるミッション機能というものは、サーバーサイドにおける実装を極めて慎重に行わなければいけないものである。
     理由としては、

    • リリース後の改修が困難になり易い
    • 負荷的な問題になりやすい
    • マスタ、ユーザーデータが膨大になる

     という、サーバーサイドにしては一つ一つが重大な問題を抱えるからである。
     一つ一つに対して詳細を追っていく。

    リリース後の改修が困難になりやすい

     まず一つ目として、ソーシャルゲームにおけるミッションというものはユーザーの様々な行動で更新が発生する。ユーザーの所持するユニット/カードなどを成長させる、ログイン日数が一定数に達成する、指定のダンジョン/楽曲を指定のスコアでクリアする等々。
     即ち、ゲーム全体で実装する全てのAPIにおいてトリガーとなる事象が発生する可能性があるという事だ。それが意味する事とは、ミッションにおける根幹の部分を変更しようと思った場合には、全てのAPIに影響が及ぶ事を想定しなければいけない。
     それへのQAコストを考えた場合、リリース後の改修が困難になりがちである。

    負荷的な問題になりやすい

     一つのAPIに対して、複数のミッション種が更新される、となった場合の処理を考えてみる。
     例えば、ダンジョン/楽曲をクリアした時などで考えると、
     ゲームクリアに紐付いて起こる事柄は例えば、
    ・パーティの経験値が増加する
    ・報酬が貰える
     等と言った事がある。さて、ここでそれらに紐付く、カードのレベルが指定に達する指定のアイテムを手に入れると言ったミッションがあったとする。
     サーバー側で行わなければいけない処理は簡単に書いても
    ・対象のミッションを探す
    ・対象のミッションの数値を達成数分加算する
    ・対象のミッションの達成条件を満たしたら達成状態に変化させる、もしくは報酬を付与する
     となる。しかも上記は、愚直に行うのならば、レベルアップしたカードの数手に入れたアイテムの種類数、更にミッションを達成して手に入れたアイテムの種類数だけの回数を繰り返さなければいけない。
     下手な実装をしたら、あっという間にレスポンスが返って来るまで5秒、10秒と掛かってしまう事の想像は難くない。

    マスタ、ユーザーデータが膨大になる

     負荷、改修コストの問題にも紐付くが、それに拍車を掛けるのがこの問題だ。
     リリース直後にはミッションデータは少なく、負荷的な問題にならなかったとしても、リリースして暫く時間が経って来ると色んな施策を実践していくに連れてミッションマスタ、それに紐付くユーザーデータというものは肥大化していく。
     新たな施策の為にユーザーデータにカラムを追加したい、と言った事をしたくとも、その膨れ上がったデータベースに対してカラムを追加しようとした時、それだけでも数時間掛かる……即ちそれだけの時間は少なくともメンテナンスに入れなければいけない、と言った事も容易に発生する。

    ミッション機能の構造的問題の纏め

     簡単に纏めてしまえば、ミッション機能と言うのはサーバー側にとって、

    • 全てのAPIに影響が及ぶが故に改修へのQAコストが非常に高く
    • 処理に時間が掛かりやすく
    • ユーザーデータが膨大になるが故にそれらの問題が更に面倒な事になりやすい

     と言う三拍子揃った非常に厄介なものとなりやすい。
     勿論、仕様次第ではもっと厄介な事になる事も十分にある、と言うか問題が上記だけで済むのならばとても喜ばしいとまで言える。

    必死に読み解いていたらそれらを更に複雑にする仕様の改修を依頼されたエンジニア

    ミッション機能の実現の為に

     サーバーサイドで実装すべき機能は大まかに分けて以下の3つになる。

    • ミッション受注処理
    • ミッション進捗処理
    • ミッション報酬受取処理

     同様に一つ一つ詳細に見ていこう。

    ミッション受注処理

     問題になりやすい部分。
     ただ受注させるだけならマスタデータ参照してユーザーデータ作るだけでしょ? と思っても、些細な問題が色々と発生し易い。
     例えば、15:00から受注出来るミッションに対して、14:58にゲームを開始して15:02にゲームをクリアした、と言った事柄を考えてみる。
     この場合、15:02にゲームクリアのAPIを叩かれた時にはユーザーはミッションを受注していない状態である訳だ。
     その場合に15:00から受注出来るミッションを進ませたい、とプランナーから要望を受けた場合、エンジニアとしてはミッションの受注処理をゲームクリアAPIの最初に仕込む必要が出て来る。
     さて。時が経つに連れて、似たような事柄がポンポン出て来てしまった。この処理の前にもミッション受注処理を入れる。この処理の前にもミッション受注処理を入れる。この処理の前にもミッション受注処理を入れる。この処理の前にも……。殆どの場合に何も発生しない処理が至る所に埋め込まれる。これだけでも香ばしいクソコードの出来上がりだ。
     後から考えれば、プランナーにゴメンナサイしてゲームクリアAPI以外では基本的にログインさせ直すように仕向けた方が良かったとか、期間前であろうとも受注させておいて進捗だけは進ませないようにしておくとか、そういうもっと良い対応も取れたけれど、もう後の祭りである。
     運用に乗っているクソコードはもうずっとそこにあるのだ。直そうとしてもQAコストを余計に掛ける余裕も無いのだ。

    ミッション進捗処理

     問題になる部分。
     端的にやるべき事は、トリガーとなる処理にミッション進捗処理を引っ掛けて、対象のミッションを探し出し、進捗を進める。
     ただそれだけである。しかし、色んな仕様がここにくっついたりすると一気に複雑になってくる。
     良く見る機能としては、ミッションA1をクリアした場合、ミッションA2が解放されるというもの。
     そうなるとミッション進捗機能にミッション受注処理がくっついてくるのだ。さて、これだけでも頭が痛くなって来る。ミッション受注処理自体は、その上記で書いたように時間制限とかを鑑みずにA2だけを解放すれば良いのだろうが、問題はそこではない。ミッション受注処理が複数種類生まれて来るという事がよりコードを複雑にさせる。
     他にもA1の進捗が4/5で、その場合に進捗を2進めた場合にA2の進捗は1進んだ状態であって欲しいとか言われたらさあ大変。受注の後に更に進捗処理が発生する。ぐるぐるぐるぐる処理が回るよどこまでも。こういうループ処理はとても危険で、もしかしたらQAも気付かずに極めて限定的な条件で無限ループに入ったりする時もある。
     更に、この処理は根幹のトリガーとなる処理にミッション進捗処理を引っ掛けて、対象のミッションを探し出し、進捗を進めるという部分で時間が掛かり易いという部分もある。
     簡単に考えても、対象の種別のミッションマスタ群の中で進捗可能な時間内にあるものを引っ張って来る、ユーザーがまだクリアしていないもの、という両方ともクエリを掛けないと引っ張ってこれないものが必要になってくる。
     そして、更に問題なのは、そんな時間が掛かる処理が何度も回る可能性がある、という事だ。カードのレベルアップ処理にミッション処理を紐づけて、上記でも書いた、ゲームクリア時にカードがレベルアップした、とするとどうなるか考えてみよう。
    ・使用したデッキのカード群それぞれに対して
     ・カードのレベルが上がる
     ・レベルが上がったのでミッション進捗処理が走る
     ・ミッションが達成状態になったらそれに紐付くミッションの解放処理が走る
     これだけで最悪数秒掛かりそうな予感がする。
     更にここに、上記で言うアイテムを手に入れた場合にミッション進捗処理が走ると考えると、
    ・使用したデッキのカード群それぞれに対して
     ・カードのレベルが上がる
     ・レベルが上がったのでミッション進捗処理が走る
     ・ミッションが達成状態になったらそれに紐付くミッションの解放処理が走る
      ・達成したミッションからアイテムが手に入ったらそれに紐付くミッションの進捗処理が走る
      ・そのミッションがクリアしたらそれに紐付くミッション解放処理が走る

       ・達成したミッションからアイテムが手に入ったらそれに紐付くミッションの進捗処理が走る
       ・そのミッションがクリアしたらそれに紐付くミッション解放処理が走る

     うわあああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああああ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛!!!!!!!!!???????????!!!???!!?!?!?!?!?!?!?!

    ※ここまでなるのは達成状態になったら、このミッション区分に関してはユーザーが能動的に受け取るAPIを叩かずとも報酬が自動的に付与されるとか、そんな仕様がある場合に限る

    ミッション受け取り処理

     そんなに問題になる可能性は低い部分。
     けれどミッションを受け取り完了状態にしてアイテムを付与すると同時に、別のミッションが解放されるとか、別のミッションの進捗が進むとかそんな事があると更に頭が痛くなってきますね!!

    実装面での障害の纏め

     主に3つと書いたが、問題なのは、書いたようにその3つは仕様次第で複雑に絡み合っていく事である。
     ただでさえ色んな問題が起き易いのに、コードがイタリア人がターボ機能を仕込んだ靴で助走をつけてパイルバンカーを顔面に叩き込みそして馬乗りになり原型がなくなっても憤怒の表情を浮かべながら打ち込み続ける程の作り方で仕上げられた、見るからに、そして実際吐いてしまう程のスパゲッティのようになり易いのである。

     次回はどう実装すれば、よりマシになるかを考察していく。

    マンガの推しが前触れなく本誌にて急逝した事により急遽休みを入れたエンジニアに対して、休みの内容は私用だと伝えられていたが実際の理由は周知の事実であり、彼のバレバレなtwitterを覗くと発狂ツイートが羅列されている事に色んな意味で涙を禁じ得ないチームメンバー

    関連:第二回「思索編」はこちら! → ソーシャルゲームにおけるミッション機能のサーバーサイド実装の考察:思考編

    記事を共有