programming guidelines

Dec 3, 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 Stupid Simple

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?

Nested for loops go brrr

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.

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.

Low Config

I find that a lot of the time I don’t configure my editors a lot. I will go out of way to make some obvious quality of life changes. For example, adding fzf to vim. Do I need it? No. Can I operate without it? Yeah. But the primary idea of this preference is that I can sit down at any computer, if it has it installed already just out of the box, I can get to working right away.

Keeping it Lean

This is where things really are circumstantial. I’m fortunate that most of the projects that I work with are relatively straightforward in a lot of aspects. The fun thing about large projects is that everything focuses on efficiency and quality within a span of time usually. Even as Astera approached 16,000 lines of code (in itself) I’m starting to notice a good bit of my workflow slow down. Things like clang-format on save are starting to add artificial delays. I often ask myself the following questions: Do I need all of the tools I’m using? Are any of my tools causing me to stop and break flow to accomplish something? Is my code arbitrarily verbose? Is there a simpler and more straightforward way to accomplish this? For this I refer to you, a timeless meme:

5 9s Theory

This might be something older (than I am) developers already know. But for some reason it’s fallen out of common lingo in programming lately. 5 9s refers to uptime of a given service (99.999%). I was exposed to this when working as a pseudo sysadmin which really gave me a respect for the other side of programming, those that have to live with our code. Many times you’ll be tasked with maintaining code within a company. The main sticking point is that if something were to happen, be it a career change or getting hit by a bus, there is a distinct possibility that production code you write can and will live on somewhere, maintained by someone who can’t just fix it in a few minutes.

My point being, write good tools that work. To refer back to Keeping It Simple, use what you need, and don’t settle for “just alright” if you can afford to not. I’ve found that taking the time to set myself up with stable and reliable tools (and auditing them) be it once a year or every few months is infinitely more fruitful than jumping ship to whatever bleeding edge (it’s called bleeding edge for a reason) tech there is.

Give yourself space

This is one of those things that requires constant maintenance. It’s in part brought to the forefront of my observation due to me reading Deep Work by Cal Newport. I’d sort of tried to do this prior but didn’t have a lot of the words Cal had put into writing. I find I both get into flow faster and stay in it longer if I chunk out my schedule to ignore email, discord, social media etc. Just me, some music, and the code (or whatever I’m working on). This can be a difficult one to put into practice especially if your habits conflict with it. It’s been I get some of my best work done in these times. There is the common sentiment of a “10x engineer” that many often wager as a goal. I don’t think that such exists, just a true fully realized 1x engineer.

In Conclusion

One of the common themes here is that less can be more in a lot of situations. Where is it really possible for us to improve not only as professionals but as individuals by making otherwise minor changes? If you actually read this far, I hope you take the time to try some of these ideas out for yourself. I don’t think my words do it complete justice, and am interested in your interpretations of this.