Programming is in large part about managing complexity and imposing structure onto a problem domain in order to make it simple (simple enough for a machine to be able to do the solution, as well as simple enough for human programmers to be able to build it).
Something struck me about a technique that I used when I was developing my game last weekend.
The code that handles the setup of the simulated atari 2600 console is full of conditionals like this:
if PowerPlug.is_plugged_in && (console.switch_power.position == POWER_ON)
&& (TV.switch_power.position == POWER_ON) && Cartridge.is_plugged_in &&
Joystick.is_plugged_in
{
//simulate the game
}
So one thing that I had to deal with as I was building this was all the preliminary stuff’ you know, to create all the objects that needed to be checked in the conditional statement above. Rather than do that, all at once, and have a lot of conditions that could have bugs in them, any one of which could make the thing not work, and be hard to figure out since multiple bugs could end up canceling each other out, or mask one another in some way, I opted to simplify things at first:
if true
{
//simulate the game
}
The advantage here is obvious. It’s simple, and you KNOW that conditional is always going to evaluate to true! So you can get right into working out the code inside the branch, without worrying for now about the conditional logic that would cause it to execute.
Once that was working, I added in stuff:
if PowerPlug.is_plugged_in
{
//simulate the game
}
else
{
if PowerPlug.was_plugged_in_previously
{
kill_game();
}
}
Then from there it became easier to elaborate on the conditional:
if PowerPlug.is_plugged_in
{
if Console.switch_power.position == POWER_ON
{
//simulate the game
}
}
else
{
if PowerPlug.was_plugged_in_previously
{
kill_game();
}
}
//etc.
(Note, the above isn’t the exact code from my project, which is a bit messy at the moment as I have some refactoring to do, but it illustrates the point.)
I found that by coding it in this way, I could iterate and test each little piece of the logic easily, and make sure it was working before trying the next piece.
I found that doing it this way made it much, much easier to handle the complex nested if
business, and as well I found it easier to know which branches of the complex conditional tree the next bit of code needed to belong in.
Now that I did it this way, it seems obvious, nothing of great insight… but 6 years ago I would have tried to code the whole thing out, and then pulled my hair out swearing at myself when it didn’t work as expected, and I had to untangle all the logic to figure out wtf it wasn’t working.
Back then I would have thought that a really superior version of me who I aspired to be would be able to code out all the conditions in one go without making a mistake.
Today a really superior version of me knows better. Start simple, add elaboration through iteration.
This is a good lesson to hang onto. And to pass on.
Of course, there’s also often ways to avoid having to code conditionals at all, but that’s a topic for another post.