Aの攻撃でBが死亡することになるのですが、その後、B自体がBattleクラスから削除されるのは、次のUpdateの時なのです。よって、死亡しているにもかかわらずBの毒ダメージが処理されてしまい、死亡処理が2回走って、スコアも2回加算される、という状況なのでした。RecvDamage()の最初で、HPが0かどうかをチェックして、死亡処理が2回走らないようにすればいいね!解決!・・しかし、この時、私達は知りませんでした。時は過ぎ、リリース後のアップデートで、様々機能が入りました。時とともに、プログラムはどんどん大規模に、複雑になっていきます。新しいBattleObjectクラスそしてある時また、ユーザーさんから報告が入ったのです。調査をするのですが、再現率が低い上、クラッシュログ等を見てみても、どうやらメモリ破壊が起きていることはわかるのですが、クラッシュするタイミングや状況もいろいろ。メモリ破壊がおきてしまう根本の原因が何なのか、わかりません。なってしまうと、調査は困難を極めます。ソースコードとにらめっこをしながら、想像するに、最初に起こったスコアの2重加算バグの様に、「何かと何かが同時に起こる」といった時に、プログラマの意図しない状況が発生し、メモリ破壊がおきそうな気がします。プログラマはコーディングを行っている時、この様な状況は、普通想像できません。「カウンター攻撃を実装して」と言われたら、ダメージ処理の中にカウンターの判定を入れて、攻撃を発動させる。それで実装完了と思ってしまうものです。「ここでこれが起こって、同じタイミングでこれが起こったら、どうなるだろう?」とはなかなか考えません。デバッグでも問題は発見されず、リリース後に、お客様からの報告で発覚する、といったことになります。「RecvDamage()の最初で、HPが0かどうかをチェックする」この対応で、不具合を回避できました。「あるオブジェクトのUpdate()が、他のオブジェクトの状態をも更新する」この様な設計である限り、今後、新規機能を実装する度に、オブジェクトとオブジェクトの影響の仕方が複雑になり、潜在的な問題が、徐々に大きくなって顕在化して来ることになります。どこで誤ってしまったのか今回経験したような、「本番環境でしか発生しない謎の落ちバグ」の様な不具合を、できるだけ起こさせないようにするには、どうしたら良いのでしょうか?前章で確認した通り、「あるオブジェクトのUpdate()が、他のオブジェクトの状態をも更新する」この設計が、良くないと考えられます。これがあるおかげで、処理が複雑になり、ソースの可読性も悪くなって・・・いつか、致命的なバグとして現れてくるんですね。それなら、各オブジェクトの状態の更新は、全てそのオブジェクト自身のUpdate()メソッドのみで行うこととすればどうでしょう?そうすれば、処理がスッキリし、わかりやすくなりそうです。攻撃など、他のオブジェクトへ影響のある出来事があった場合はどうするかと言うと、「イベントキュー」というものを用意し、ここに情報を積んでおく様にします。次のUpdate()で、各オブジェクトがイベントキューから情報を取り出し、自分に関係のある出来事だった場合は、それに従って自分の状態を更新する、とします。新しいバトル設計1回目のUpdate()で起こった出来事は、キューに積まれ、2回目のUpdate()で処理します。同様に、2回目のUpdate()で起こった出来事は、またキューに積まれ、3回目のUpdate()で処理します。このようにすることで、プログラマは、常に1つのオブジェクトの状態だけを気にするだけで良くなりますね。なにかバグが発生した時も、イベントキューに何が積まれているか、というところからスタートして、1つのオブジェクトのUpdate()処理だけを追って行けばよい、という訳です。まとめ今回紹介した問題点の難しいところは、プログラムの規模が小さいうちは、それほど問題とならず、機能追加を繰り返していくうちに、徐々に大きな問題となり、致命的な問題となった時には、もう取り返しがつかない状態になっている、ということです。取り返しがつかない、というのは、ソースの規模が大きすぎて、リファクタするには、デバッグ含めて工数がかかりすぎる。仕方がないので、場当たり的な対処でバグをつぶすのですが、またアップデートをしていくと、似たようなことでバグが発生し、悩む・・・の繰り返しになる、ということです。オンラインゲームというのは、リリース後も次々とアップデートを繰り返し、機能が増えていきます。よって、一番最初の設計で、どれだけ未来の変化を予測して、準備しておけるかが大事になってきます。後になって苦しまないために、最初は多少面倒でも、柔軟でわかりやすい、変化に耐えうる設計を心がけたいものです。2017.07.19エンジニアの吉野です。ソフトウェアエンジニアの滝です。Knightsの開発裏側みせます。2012.04.17こんにちは細田です。WordPress.。