アピリッツ コンテンツデザイン部の金井と申します。前回から一年半以上が経過し、自らが携わっているゲームも無事リリースまでこぎつけ、そして暫くの時間が経過しました。
その中で、こういう改修はすべきではなかったなー、という事を書いていこうと思います。
結論
状態の増える改善は改悪!
過程
引き継いだソースは、基本的に全てのAPIでミッションの受注処理が含まれていました。
その受注処理は煩雑であり、その処理が入っているが為に、許容出来るものだとは言え、全体的にレスポンスの遅延が発生していました。
私はそれを嫌い、ログインの段階で必ず通るAPIにのみ、ミッションの受注処理を仕込むように変更しました。
すると、日付変更、データ更新などの、必ずログインに戻されるタイミング以外でのミッション……例えば、イベント開始と同時に有効にしたいミッションの受注が不可能になりました。
それへの解決の為に、私は、未来のミッションを予め受注しておく、という処理を組み込みました。
ま、多少問題もあったものの、負荷試験も大丈夫だったし、受注処理も1APIでのみ対応になってソースコード的にもスッキリ!
リリース後もミッション関連でバグは起きて……しまった。
問題
さて……これの何がいけなかったでしょうか。
私はリリース後までこの改修で発生してしまう問題に気付けませんでした。
また、これが引き起こす特殊な事象に関しては、運用になってからやっと気付けるような代物で、リリース前のQAでも素通りしてしまいました。
また、上記の改修が顕在化した要因として以下の事柄があります。
- この頃のソーシャルゲームでは、ミッションを達成した瞬間、通知がゲームの端に飛んでくるような仕組みが良くあると思うのですが、それが一つ。
- そして、未来のミッションを予め受注しておく、という処理を組み込んだとは言え、そのプロセスは基本的な受注処理と同じ部分を通っているという事が一つ。
…………。
はい。
例えば、初心者の為のイベントミッションで、累計*回**をする、みたいなミッションがあったとします。
ここで重要なのは、開始してからのカウントではなくこれまでの累計という事です。
初心者でもゲームを遊んでいれば簡単に達成出来るようなミッションで、既に長時間遊んでいれば即時達成しているようなミッションです。
要するに、こういうミッションでは予め受注して即時達成するという事が起きる訳ですね。
そこで私は、考慮漏れを引き起こしました。
即時達成したミッションの通知が、ミッション開始前の時刻なのにユーザーに飛んでしまったんですね。
ユーザーからしたら、何か通知飛んできたけど、ミッション一覧にそんなミッションないし、受け取る事も出来ないしで、訳が分かりませんね!
他にも一定の操作をしていると、一部のミッションが達成不可能になったりだとか、そういう事まで起きてしまい。
後から補填の為のバッチ処理を組み込んだりする必要が出て来ました。
まあ……後から補填処理を組み込んで修正出来るくらいの代物で、本当に大事には至らなかったのですが。それでも不具合としては結構大きめな部類で、結構凹みました。
原因
改修によって、状態が増える、それに対する影響などを考慮出来ていなかった事ですね。
今回の未来のミッションを受注するという改修に関して言えば、
- 未来のミッションを受注しておらず、まだ有効でもない時間
- 未来のミッションを受注しており、まだ有効でない時間
- 未来のミッションを受注しており、有効となっている時間
という3つの状態が新規に発生してしまった訳です。そして、それらへの考慮が足りなかった。
いや、そもそも、そんな新たに発生した状態を考慮する必要が出てくるような改修はするべきではなかった。
修正するにせよ、その未来受注をそのままにして対応しようとした場合、
- 予め受注、即時達成したミッションを開始時刻が過ぎた直後のAPIで達成通知を送る必要がある
- 累計カウントのミッションの場合、予め受注し、そして有効でない時間に進捗した分への考慮
等々、とてもじゃないけれど、やってられないような、やったとしてもエンバグを発生させそうな複雑な処理になりそうですし。
対応
結局、未来のミッションを予め受注するという処理をやめました。
詳しくは書きませんが、全てのAPIにミッション受注処理を入れ直すというような汚い事はせず、それだけはしないようにする、という対応が出来たので。
その修正を反映して、無事に本番で機能している事も確認出来て、やーっと、ほっと出来ました。
反省
最初にも書いた通り、リファクタリングにおいては、状態の増える改修はすべきではない、という事ですね。
良かれと思ってやった事が、実は改悪だった。そんな事を今回、自分はやらかしました。
なので、思いついたような実装方法や改修が、どんなに素晴らしいものに見えても、着手する前に距離を取って考えてみる時間が必要だと実感しました。
特にそれがシステムの根幹に位置するものに関しては、寝かせて翌日に見直してみたりだとか、どんなに一任されている事柄だろうと他者の目もしっかりと入れたりだとか、そういう事をした上で着手に入る必要がある。
そう、実感しました。
また、後から色々考えた結果、今回に関しての最善策は、
全てのAPIにミッション受注処理を入れる事は変えずに、受注する必要があるかどうかを軽い処理で判定出来るようにする。
という所感です。
それがクライアントもサーバーも、多少コードとしては煩雑でも一番安心出来る、簡潔な受注処理になりそうだと思っています。