programming guidelines

Sep 19, 2022

One of the more useful things I feel a programmer can do is to create their own programming guidelines. I’m not saying reinvent the wheel and create a new language standard, but rather a set of rules/guidelines you tend to work with. This post serves as my rough, mostly complete, list of that.

KISS - Keep It Simple Silly

When I say keep it simple, I don’t mean endlessly remove features until you’re left with no program at all. But the goal of keeping a program, function, or line of code simple is to maintain legibility and more importantly usability. I’m willing to wager that all programmers write code they’re not going to recognize in a given period of time. Oftentimes that length of time is much shorter than you might think. Writing clear, concise statements in your program can lead to a clear trail to follow. Writing clear, concise functions can make a program easier to dissect. It’s awfully difficult to optimize or even just maintain a code base if things aren’t easily parsed by our squishy brains. This serves in the way of not over complicating your end goal as well. Do you need 16 ways to update a row in a database or just the one or two?

Use the smallest possible data type

This isn’t necessarily the best practice to do for optimization. Rather my goal with this is about understanding the scope of the variable needed. It forces me to think about what I’m writing instead of just writing out int for every single counting number that I need. There are plenty of talks on Data Oriented Design that address this topic significantly better than I will within the scope of this list.

Be Consistent

When you’re learning something difficult oftentimes you’ll be told,”Consistency is key”. Cliches aside, it’s an important factor in programming. Consistently writing code that is laid out similarly across the program can give you an added efficiency bonus when debugging or optimizing. By consistency I mean functionally. When I write my physics logic for games, I tend to lay it out in the same fashion where possible. If I use common functions amongst many different scopes it leaves me with a common denominator to debug at. Yes it creates a point of failure, but I also don’t like maintaining 18 versions of the same thing. Which leads me to my next guideline:

DRY - Don’t Repeat Yourself

This is directly lifted from The Pragmatic Programmer. There are certain cutoffs to this sentiment, especially in games. But generally I stick to the goal of not repeating common functionality more than twice in separate functions. Usually this ends up being look up functionality, adding or removing something from an array that isn’t just as simple as changing the index, or context changes.

Have a naming convention

The goal of a naming convention is to be consistent. Yes, it’s sort of a repeat of the ‘Be Consistent’ guideline, but it’s important enough to separate out. Having consistent naming means you’ll not have to rely upon recalling a function name. You can figure it out on your own. Here’s an example of my naming convention:

In my game engine, astera, I write out several different files of functionality useful for working on games. The first character of my function names signify the subsystem (rendering, audio, collision, etc). Followed by the data type/struct, then operation. So say I want to create the rendering context at startup. I start off with the subsystem r then context in my keyword list is defined as ctx so it becomes r_ctx. The operation is create so the function name is r_ctx_create. I have keywords I often repeat in places so that it’s not a guessing game as to what I should name something as well. Am I wanting to destroy/exit the render context? That’s r_ctx_destroy. What if I want to update the listener’s position for audio? a_listener_set_pos.

This is one of those rules that generally applies to bigger projects but is easily ignored by smaller ones. What do I define as a larger project? Anything greater than 50 lines of code usually.

Snake Case and Lowercase

Like all of these guidelines, this is my personal preference. It’s also generally one of the first ones to go out the window when working with others. Adding the extra underscore character is often considered excessive. But by having snake case and lowercase, I don’t generally have to worry about capitalization and can easily see individual words. a_listener_set_pos feels a bit more natural to me than aListenerSetPos.

Use a code formatter

Yes, seriously. This is huge. Having consistently laid out files is essential for your sanity the second you have to use pull requests or merge in other people’s code. I can’t tell you how many days of my life have been lost to simply having to correct merge conflicts that were generated by whitespace. Consistent layout generally prevents most of these conflicts, and saves you time. The tool I prefer for this is clang-format. There’s a plugin for just about every editor out there I can think of. I know even Visual Studio now supports it (crazy, right?). Here’s my clang format file I use for just about everything C/C++ related.

Backup your configuration files

Shit happens. Your computer’s current state is not guaranteed. There are plenty of tools out there to backup your configuration files, generally called dot file managers. I’ve seen people write their own scripts that just make symlinks to a central folder that they have as a repository on their github to automatically backup their files. There are programs as well. Or you can just drop the updated files into a repository you backup inconsistently to tell yourself you’re responsible. Either way, having a solid point to recover from reduces the time you’re having to spend setting up your development environment again.

Test your work

There might come a day where you think you know everything you need to in relation to a certain project. But the simple fact of the matter is that we are not computers. Static analysis, unit tests, whatever version of testing you want to do, you should have at least something. No, you don’t need a whole suite to perform regression testing and spit out fancy graphs showing you how shit one of your updates was. But when left in the darkness, you simply cannot know exactly what is happening. Clang has one built in, there are plenty of others like Cppcheck out there. I recommend you get comfortable using one. As well, use an AddressSanitizer. Modern compilers have native support built in, oftentimes are just a few optional package installs away at most.

I hope at least some of this information is of use to you! Exciting things are happening in Devon land currently. I hope to share all the updates with you soon!

See you later!