Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs.
Effective Coding: Don't Repeat Yourself
An in-depth overview of a very important programming principle often used in game code: Don't Repeat Yourself.
I've written about making sound effects, writing music, and even creating pixel art, all from the perspective of a programmer, so I figured at some point I should actually write about programming.
I was going to write the typical article that reads "8 weird habits of effective programmers, number 5 will literally make your brain explode", but then I realized I have really a lot to say on these subjects and a brief overview just wouldn't be sufficient.
So, instead I will be doing a deep dive into one particular subject, and if enough people find it useful, I'll write more articles like this.
But first, if you're one of the many people who learns better by listening and watching, I put together a video that goes over all these points.
So what's the subject?
I'll be discussing a programming principle called Don't Repeat Yourself, or "DRY". It's an extremely useful principle to follow for all programming, not just game code.
The basic premise is to never have duplicate code in your program. It may sound obvious, why would anyone just copy and paste code? But code duplication is actually a surprisingly common programming problem that I've seen from both beginner and senior level programmers.
This typically manifests itself when you want to write two functions that are similar, but have a few differences. Instead of following the DRY principle, the programmer in question will copy and paste the function, only to change the few lines that are needed. This leaves much of the code in the two functions duplicated.
Consider this example of Code duplication:
shoot() {
ammo--
spawnProjectile()
}
shootUnlimited() {
spawnProjectile()
}
In this example, spawnProjectile() is duplicated. Yes it's just one line, but it's a contrived example and represents potentially many lines of copied code.
Why is this a problem?
Code duplication is very bad for several reasons.
1. It's a maintenance nightmare
Every time you update your code, you have to then find everywhere else you have copied it and update it there also. This is especially problematic if you are working with a team of programmers who may need to edit your code - how will they know that you've copied it, and where?
The maintenance problem leads into problem #2:
2. It introduces bugs
When you update your code, you might accidentally miss one of the spots where it has been copied, causing an error. You might correctly update all the spots, only to realize that the new code wasn't intended to be copied elsewhere.
Sound confusing? It is. In fact, that's problem #3:
3. It's confusing
It's difficult to parse multiple similar functions in your head. Why are there so many? What's the difference? Which one do I call? It's just more total code that your brain needs to read and process. Less code to do the same thing is often better, and avoiding duplicated code is always better.
Common rebuttals
For much of my career in the games industry I've been a lead programmer, which means I am often reviewing other people's code and potentially asking them to change it... for the greater good! All too often, programmers will become defensive and try to justify why they have violated the DRY principle. These are some of the common rebuttals excuses I have encountered:
1. It's impossible to write it any other way
Beginner programmers will give you this one. "It can't be done!" they will say. Here's an example which will elict the response: "There is no way to write this without copying that line".
if (isEmpty()) {
if (canReload()) {
reload()
spawnProjectile()
} else {
playEmptySound()
}
} else {
spawnProjectile()
}
There is always a way to avoid code duplication. Sometimes it's as easy as rearranging the code.
if (isEmpty() && !canReload() {
playEmptySound()
} else {
if (isEmpty() && canReload()) {
reload()
}
spawnProjectile()
}
The programmer might protest further... "Ah but now you have a condition copied! You wrote isEmpty() && canReload() twice! Sort of! See? It is impossible!"
So you write...