はじめに
本記事はミノ駆動本を読んでクソゲーを神ゲーにリファクタしてみたの続編1です。
今回はミノ駆動本第4章の不変の活用に着目していきたいと思います。
可変になっている悪いコードがどれほど悪影響をおよぼすのかをちょいネタにしてみました。
また、書籍の内容をヒントにして、不変を活用した良いコードでどれだけ改善できるかを検証していきます。
参考資料
良いコード/悪いコードで学ぶ設計入門保守しやすい 成長し続けるコードの書き方
内容
今回作成したゲームの実際のコードになります。
https://github.com/kdr250/good-code-bad-code-sample
仕様変更で武器の攻撃力を変えたい!
PM 「◯◯君、マップ上の武器ごとに攻撃力を変えたいんだけど、実装お願いできるかい?」2
◯◯ 「了解しました!修正しておきます!」
◯◯ 「攻撃力の変更だから攻撃力のインスタンスの値を書き換えれば良さそうだな...(カタカタカタカタ・・・ッターン!)」
◯◯ 「ん?全部同じ攻撃力になってる... なぜだ...」
問題点
書籍でも述べられている通り、問題は可変インスタンスを使い回していることにあります。
public class AttackPower {
static final int MIN = 0;
int value; // finalが付いていないので可変
// 中略
}
AttackPower attackPower = new AttackPower(3); // 生成した攻撃力を...
Weapon weaponA = new Weapon(attackPower);
Weapon weaponB = new Weapon(attackPower); // 他の武器でも使い回しているため...
weaponA.attackPower.value = 4; // weaponAの攻撃力を変えたつもりが他の武器の攻撃力も一緒に変更されてしまう
もう少し整理すると、以下のように分解されると考えます。
- 攻撃力クラスの値が可変であり、後から変更できてしまうこと
- 攻撃力のインスタンスを複数の武器で使い回されていること
改善策
上記の問題点を踏まえ、改善策は以下になると考えました。
- 攻撃力クラスの値を不変にすること
- 攻撃力インスタンスを複数の武器で使い回さずに、個別に生成すること
public class AttackPower {
private static final int MIN = 0;
private final int value; // finalで不変にする
// 中略
}
AttackPower attackPower = AttackPower.random(); // 攻撃力のインスタンスを個別に生成する
return new Weapon(attackPower);
期待した効果が得られたか
不変にすることで予期せぬ値の書き換えを防止できるというのが最大のメリットだと感じました。
今回のバグを解消するのはもちろん、そもそもバグになりにくい構造になったのかなと思います。
実際にゲームを一本作ってみて、(ネタ関係なしに)うっかり可変のまま放置していた箇所が後々バグの原因になる、ということが度々発生しました。しかし、不変を活用することでバグがそもそも発生しにくくなったりするので非常に効果は大きいと感じました。ゲームに限らず、他のプロダクトにおいても不変を活用すれば品質の向上につながるのではないかと思います。
その後...
◯◯ 「PMさん、できました!ついでにいい感じにコードをリファクタしておきました!」
PM 「お!ありがとう!」
おわりに
今回は
- 4章 不変の活用 - 安定動作を構築する -
に着目してリファクタリングに生かしてみました。
ミノ駆動本はこうした設計テクニックが満載なので、是非読んでみることをおすすめします!