Latest ArticlesEngine Architecture #1
Static Shadows #1
Paint on Mesh
A Tale of the Internet
Coding Style Jul 04, 2006
I haven't written much about coding style before. There are a couple reasons for this. One is that I don't think it matters much for productivity. Of course, if you don't try to write good code you probably won't, but I don't think the specifics chosen matter, least of all formatting related specifics. I've actually changed the details of my coding style quite a few times over the years, but I can't ever remember deciding a specific style was best. Worrying too much about this just wastes time that could be spent writing and debugging code.
To me programming has always been about creating good programs, and what the code itself looks like is of no importance. Nevertheless, I try to write simple, consistent, and straightforward code. I didn't always do this. My grade school Qbasic code is now illegible to me. Even some code written after college was quite sloppy. Basically, as the size of the programs I've written has increased, the "quality" of code has become more important to write good programs. There's a big difference between writing short throwaway programs and huge programs. For example, it's unlikely avoiding global variables will make your program easier to follow if it's just a couple thousands lines.
Importance of good codeWhen I first started writing the program that became Kingdom's Creator, I didn't plan on it being a major project, so it I didn't program it to be, but it just expanded naturally. After about a year, the code actually got so confusing to understand and modify, and riddled with needless dependencies, that I rewrote the main part of the program and many of the subsystems. (The idea of throwing away code and starting from scratch has always struck me as odd, this is the closest I've gotten to that.) The ease of adding functionality to the new program easily makes up for the extra design consideration time.
Before the rewrite the program was buggy and even crashed on me sometimes. Now it's mostly bug free, and there aren't any major bugs I'm aware of. I say "mostly" because if anyone claims to write completely bug-free code, they're either lying, or they're just writing simple little programs. Even if a program works perfectly for you on your computer, that doesn't mean it works perfectly for all users on all computers. Once a few years ago my program was crashing on startup on one computer. It turns out it didn't have a sound card and I had forgot to avoid all Direct Sound calls if initializing was unsuccessful... maybe I should have given an example that wasn't careless stupidity on my part =) but that's why testing is good.
Variable namingClearly named variables are important, although you shouldn't need to think too much about it. I'm actually using fewer abbreviations now. I figure I'm a fast typist, and every once in a while I even find one of my own abbreviations ambiguous. I still use prefix notation where it is deemed to be helpful, but I don't use it religiously. When I started using prefix notation, one thing I would do is put an n before every variable declared as an integer, even if the variable wasn't used as a number. I later decided that this was pointless. It's not as much about the type a variable was declared as( which intellisense can show you,) as about variable use. You can see the specific guidelines I use in 3DKC here.
Reusing CodeWhen writing a new section code, if I don't have any idea how I'd reuse it, I ignore reusability concerns as unimportant. If it turns out later I need it elsewhere, then I'll take more time and rewrite the code to be reusable.
What I do feel is extremely important is only having code that performs a certain function in one place. This make changes much easier, because you don't have to worry about hidden dependencies that you might forget to update. In addition by reusing the same code whenever possible you can be more sure that it's bug-free, as any bugs have more places to show up. Finally, I admit that I find shorter code more elegant.
Similarily it's usually good to have one and only one function to do a specific task, such as changing a piece of data. This way you can alter this function to update any dependent data, or to gather complete statistics. I try to avoid dependent data when possible, but sometimes it's necessary to store the same information in multiple ways for optimization. Any extra functions to perform a task in different ways will then call this one function. So for example we will only have one add object function, and cloning will call add object.