I’m baaaack! And I’m sure everyone is glad to hear it, especially the small european countries my minions are secretly holding to ransom. Give the nice countries back to their leaders, minions.
NOW! Seriously, have I taught you people nothing? We take over the world in one big sweeping dramatic move or not at all! I’ll have none of this logical behind-the-scenes war-of-attrition business.
“Can we at least keep Belgium?”
Anyway, on with the farce! I mean show. (I actually mean farce)
Bugs (of the programatic coding variety, as opposed to the six-legged chitinous-exoskeleton variety) are a programming certainty. If you’re a programmer, and assuming you’re not some kind of savant, you will put bugs into your code. Debugging often takes up just as much if not more time than writing original code. So if you’re a coder, you will learn them, you will live them, you will love them (or not, as the case may be. I’m pretty sure that’d chafe like hell, and possibly electrocute you. Unless we’re talking about the six-legged chitinous-exoskeleton vari- WHAT THE HELL IS WRONG WITH MY BRAIN).
There are a number of different types of bugs. Now, the following isn’t official. I remember researching the “official” categories of programming bugs a few years back, for a Uni course I think, but my categories here are not official. If you use them around official people you’ll get weird looks. They’re about as far from official as it is possible to be while still living in a society that considers officiality to be a real thing. Even the most anarchial systems of government have deliberate exceptions for shit like this. They’re so unofficial they approach officiality from the other direction. Am I making myself clear here?
Compile Time Bugs
These bugs are the simplest: typos and mistakes that coding environment can detect, often before you even compile the program. If I tell the program to store a character string in a number, or to modify a value that hasn’t been assigned yet, or to access a class that isn’t even a part of this class, then this’ll happen. Effectively, it’s a mistake so blatently stupid that the computer itself is calling you out on it. They’re not even really a part of the debugging process, since you have to deal with them before you can test the program.
Simultaniously the best and worst of bugs, exceptions are what the program throws at you when it simply cannot do what you’ve told it to do. Remember “This program has performed an illegal operation and will be shut down”, and all it’s variants in Windows OS’s since then? Those are exceptions.
Exceptions are bad for obvious reasons: they stop the program instantly and you lose all your work. But they’re also excellent, because they’re things Visual Studio understands. An exception is by far the easiest type of bug to debug: running in debug mode, it will show you the exact line of code that threw the exception, give you an explanation as to why it threw that exception, and allow you to look into why that line of code threw that particular exception at that particular time. A program that has exceptions in anything more than the remotest reaches of obscurity is a program that hasn’t been debugged enough.
Unfortionately, a game like Species thrives in the remotest reaches of obscurity, so when I do release the alpha expect at least a few exceptions now and then. Thankfully, there will be an autosave function to neutralise the ‘lost data’ problem.
Logic bugs are bugs that don’t break the rules of the operating system or the compiler, but that do break the rules of the program. My energy cycle bugs are (were) logic bugs: things that do work, but that don’t work the way they should.
Logic bugs can be far, far more annoying than exceptions, because the program doesn’t know it’s doing anything wrong. It’s like the difference between a trained dog that knows not to come inside after it plays in the mud, and an untrained dog that bounds into your house with endless enthusiasm, smothering every available surface in material you’d rather not know about.
But they can also be a lot of fun. Out of the hundreds of bugs I’ve put into Species over the course of it’s development, a small number have been both coherent and hilarious. Like the time I put a divide into the vision calculations…
… or the time I forgot to limit the ‘scale’ values to >0…
… or the mistake in the culmative ‘Species Average’ calculations…
… or the time the creatures learned how to fly.
About that last one: I ended up putting in a placeholder fix and just amplifying gravity to Jupiter levels to make sure they’d stay on the ground. It was only several months later that I found out why they were flying and could put gravity back to normal levels.
For the most part, though, they’re annoying. Logic bugs are the reason deadlines are all but impossible to define. It can take anywhere from seconds to days to fix a particularly obscure logical bug. I mostly deal with them with a combination of analytical deduction and throwing code at it and seeing what sticks. Which brings me to my third category…
While debugging without knowing exactly where the bug is, I tend to put in small and temporary bits of code and re-run the program, watching to see if the bug’s cause or effect are influenced. When it is, it’s often easier to manipulate the temporary code to make it fix the bug, rather that re-writing to whole section with the bug in mind. Other times, it’s even possible to simply forget bits of debug code after fixing it, and leave them in there while we move on.
These sort of small, thrown-together segments of code are like cancerous tumours in a big project: often harmless on their own, but as more and more of them appear and grow they can start to conflict with original code and with other tumours. This can cause exceptions or logic bugs, and can often be harder than usual to debug because unlike original code, it’s easy to forget what purpose a tumour had when it was added.
If you’re a programer, check out the QuadTerrain class. There’s a segment in the comments in there that says something along the lines “I have no clue what this does, I can’t even remember writing it, but it stops working if I take it out.” That’s what I’m referring to. (Although to be fair, that particular case may have had less to do with debugging and more to do with coding while drunk).
Debug bugs are often a sign the original organisational design of a project is breaking down, and it’s time to rewrite a segment of code, consolidating all the bug fixes into an improved design. The Species project, because of it’s “evolving prototype” nature, has had it’s fair share of these.
Sometimes, you’ll design something that simply won’t work. This happens. Nobodies perfect. A good example in Species is the Tree of Life graph: I wanted each different species on the screen to have an independant population line you could drag from left to right across the screen, putting them in the order you wanted, rather than a static graph. It wasn’t to be. Thanks to the way RenderTargets have to work and an unexpected limitation on how many you can have at once, (one day I will write a post on RenderTargets. It will consist entirely of the capital letter “A” repeated one thousand, three hundred and twenty-seven times) it’s not possible to draw each and every Species history in a seperate pass… at least, not with any sort of decent performance. (As it turned out, the memory bug that stopped Development Video #2 was directly related to this) So, after quite a few weeks working on it, that idea had to be scrapped. The species history is now a static graph.
Sometimes you’ll write some code and suddenly your frame-rate will plummet. Other times there will be no definate point at which you lose decent performance, it’ll just slowly decrease as you add more features. In either case, optimisation is needed.
This project is particularly prone to performance bugs, thanks to the sheer scale of what I’m trying to simulate. 1500+ completely mutable semi-sapient AI creatures interacting with each other is not exactly an easy thing to simulate. For quite some time I was scared that Species simply wouldn’t be able to run with enough creatures to make the simulation worthwhile.
As it turned out though, much of the update CPU work was caught up in one or two unecessary or simply inefficient methods, and could be negated. As it turns out, the largest necessary CPU cost isn’t the CPU at all: it’s the bottleneck between the CPU and the Graphics Card (strictly-speaking this is the CPU, but it’s related to how many times I send information to the Graphics Card in the Draw() method, not the actual simulation which happens in the Update() method. I’m losing people here, aren’t I?). And that’s even with aggressive per-creature level of detail (semi-relevant to Level Of Detail algorithms), something I’ll have to expound on in a future post. So in it’s current incarnation, Species will run at a significantly better FPS rate if you’re not actually looking at anything.
Thankfully, there are tools available for this sort of bug. NProf is what I use for tracking down where all my CPU time is going, mostly because I’m cheap and it’s free. There are lots of others, too. And if all else fails, code your own! The bars visible in Development Video #2 have been invaluable for performance debugging.
Not a bug so much as an unexpected phenomena that you have to learn about and take into account if you’re going to make the most out of your program. Garbage Collection, mentioned in a previous post is this sort of thing. The parallel nature of the GPU, which I’m totally not using to it’s full potential BTW, is another. And multithreading and parallel cores, which I’m convinced were only invented because all hardware designers are secretly evil robots. Evil multithreaded robots. *shudder*
Being aware of these things, even if you don’t think you’re using them, is vital. Often you are using them without realising it, and it’s possible to lose a lot of time debugging and optimising in the wrong area if you’re not aware of what your code is doing under the hood.
So anyway, that’s how my brain breaks down software problems. It’s a purely subjective thing, of course. I don’t recommend anyone trying to use these categories in a school assignment or job interview. You’ll probably just fail or get turned away or have the police called to arrest the crazy person (if you manage all three at once, send pics!). But at least I had fun writing this post and subjecting you to the tortured organisational abilities of my gray matter cells. Both of them.
[after a proofread]… I’m starting to suspect there’s something seriously wrong with my brain. I mean, I barely remember typing half of that, and I’m sober. Seriously, how do I even get away with acting like this in the quasi-public forum of the blogosphere?
Oh yeah, orbital weaponry. I forgot.
* * * * * *
“I… I don’t think I can possibly add anything to this post. There’s a lot I could subtract, but that’d be like desecrating a shrine. A shrine to some inconcievably terrible eldritch abomination with more tentacles than PZ Myers, admittedly, but a shrine none-the-less.”