Namek Dev
a developer's log
NamekDev

When management says "don't refactor now" and you see this

April 24, 2017

While coding we meet sometimes one of our deamons: should I refactor what I see? When the dilemma grows it goes into: develop as it is or completely “rewrite” it?

A short story of one small refactor

Dilemmas, of course, yeah. Let’s just make it working!

Let’s look at this snippet:

// PREVIOUS CODE
var player:Object = guildUpdateFloor.player;
if (player != null && guildUpdateFloor.guild_id == _enemyGuild.name) {
	if (player.defeated == false) {
		(_enemyGuild.members[player.name] as GuildMember).cooldown = -1;
	} else {
		(_enemyGuild.members[player.name] as GuildMember).cooldown = int(player.defeated);
	}
}

It stood untouched for some longer time in there. And then another developer adds this:

else if (player && guildUpdateFloor.guild_id == _playerGuild.name) {
	if (player.defeated == false) {
		(_playerGuild.members[player.name] as GuildMember).cooldown = -1;
	} else {
		(_playerGuild.members[player.name] as GuildMember).cooldown = int(player.defeated);
	}
}

I couldn’t resist to rewrite all of that by actually understanding what it does.

// LITTLE BETTER
var playerData:Object = guildUpdateFloor.player;
if (playerData != null) {
	var guildMember:GuildMember = _enemyGuild.members[playerData.name] as GuildMember;

	if (guildUpdateFloor.guild_id == _enemyGuild.name || guildUpdateFloor.guild_id == _playerGuild.name) {
		guildMember.cooldown = player.defeated ? int(player.defeated) : -1;
	}
}

What have I changed? It’s shorter and some variables are introduced / changed.

(Asking about the language? ActionScript 3.)

Refactor and afterthoughts

Comparing the previous and “better” version it may look like - hey, yeah, code is shorter but now we can’t see logical paths at first look.

However, after deep insight you’ll notice this fact: previous snippet had 4 cases where 2 were rather virtual. In reality, it happened to have only two different cases which were easy and quite readable to be rewritten as one logical condition:

if (guildUpdateFloor.guild_id == _enemyGuild.name || guildUpdateFloor.guild_id == _playerGuild.name) {
    guildMember.cooldown = player.defeated ? int(player.defeated) : -1;
}

If you would be interested making those cases independent then why not:

if (guildUpdateFloor.guild_id == _enemyGuild.name) {
    guildMember.cooldown = player.defeated ? int(player.defeated) : -1;
}
else if (guildUpdateFloor.guild_id == _playerGuild.name) {
    guildMember.cooldown = player.defeated ? int(player.defeated) : -1;
}

But how do you feel now? Do you expect cooldown  to be calculated differently in some longer time?

If not, then why not doing another trick?

if (guildUpdateFloor.guild_id != _enemyGuild.name) { }
else if (guildUpdateFloor.guild_id != _playerGuild.name) { }
else {
    guildMember.cooldown = player.defeated ? int(player.defeated) : -1;
}

Notice the != in place of ==. It may look as a stupid trick. But note the fact - two first conditions (those != IFs) are splitted and cooldown calculation is written only in one place. In case of changing only one case you would probably remove the “else” part.

Much more cases?

Your first think may be “use switch”. But what would you change that way?

var passEvent: boolean = false;

if (eventType == Events.PLAYER_KILLED) {
    passEvent = true;
}
else if (eventType == Events.ENEMY_KILLED) {
    passEvent = true;
}
else if (eventType == Events.GOLD_ACCLAIMED) {
    passEvent = true;
}
else if (eventType == Events.GOLD_SPENT) {
    passEvent = true;
}

if (passEvent) {
    dispatchEvent(event);
}

Instead, let’s try inverting checks:

var passEvent: boolean = true;

if (eventType == Events.PLAYER_KILLED) { }
else if (eventType == Events.ENEMY_KILLED) { }
else if (eventType == Events.GOLD_ACCLAIMED) { }
else if (eventType == Events.GOLD_SPENT) { }
else {
    // now it's easier to not omit this line in all needed cases!
    passEvent = true;
}

if (passEvent) {
    dispatchEvent(event);
}

Or if your code is really as simple as the above you could indeed introduce a switch expression.

var passEvent: boolean = false;
switch (eventType) {
    case Events.PLAYER_KILLED:
    case Events.ENEMY_KILLED:
    case Events.GOLD_ACCLAIMED:
    case Events.GOLD_SPENT:
        passEvent = true;
}

if (passEvent) {
    dispatchEvent(event);
}

Sometimes just looking at code in an inverted way than it is written helps to keep it more clean and less buggy when another person develops it more in a hurry.

Summary

My message here is only this - developers, look at and look into the code of your fellows! You are as responsible for old production code snippets as the authors.

Clean Code, Daj Się Poznać, Get Noticed 2017, actionscript3, gamedev
comments powered by Disqus