C++ Coding Guidelines

Priorities

At first it seemed really dumb to me to list priorities. No one disputes the following items are important. But it is easy to mistakenly prioritize a less important priority over a more important priority. So below are my priorities, listed most important first. And I endeavor to always value all of these priorities, and yet never reorder them.

Correctness. There can be nothing more important than code that robustly works as advertised with no surprises. Faster code that gets the wrong answer is not superior to correct code. The act of writing code that is testable (and writing those tests) greatly lends itself to writing correct code. Run time performance. If the code is correct, but runs so slow that nobody can use it, then nobody will use it. "Slow" is defined by the client though. What may be too slow for some clients may be fine for others. Code should be as fast as possible, but no faster. Code size, memory usage and disk usage is also included in this category. Any resource that your code uses at run time, be it processor cycles, ram, network I/O bandwidth, disk space or disk I/O bandwidth, is a limited resource and if your code squanders any resource, this will cause problems for your clients. Compile time performance. Code should compile as fast as possible, but without compromising correctness nor run time performance. This is especially true for code that lives in headers, as it is compiled more often than code that lives in source files. Additionally code should be designed to not require excessive ram to compile. Use of excessive ram can also lead to needlessly long compile times due to paging. Maintainability / Easy to read. These are really two closely related goals. Code that is hard to read is not maintainable, and generally code that is not maintainable will turn out to be difficult to read as well. What makes code maintainable and easy to read? Simplicity goes a long way. It is easy to get carried away with over-generalizing everything on the off chance you may need it one day. Code should be as simple as possible to meet the task at hand, and no simpler. Simplicity will positively feed back into our other priorities. Note however that more verbosity does not always translate into easier to read code. Identifiers should be long enough to give meaning, but short enough that a line of code does not expand into a paragraph of code. Easy to write. Making code easy to write is important. However it is the least important of all of our goals. Code is read (by humans) far more often than it is written. Thus a good programmer will optimize their code for being read, even at the expense of making their code harder to write.

Never sacrifice a higher priority for a lower priority. All of these priorities are "mom and apple pie" (no one could disagree they are good ideas). But an engineer knows that there are always tradeoffs, and knows which priorities should be sacrificed for other priorities (and when).

Measure

If you think something is correct, prove it with a test. If you think something is fast, time it. If you think one algorithm is better than another, find some way to make a measurement to support your argument.

Do not depend only upon your "common sense." Do not depend only on theory. It is good to use theory to help guide you to an optimum solution. But without measuring, you have no way of knowing (nor convincing others) of the correctness of your theory. Without measurement, you have a faith-based system, not a scientific theory.

If what you need to measure is too complicated to measure, break the problem down into a collection of smaller problems that can be measured. Making some measurement is infinitely better than making no measurements. And whatever you do, do not depend upon yourself or someone else just saying: "trust me, I know what I'm talking about." If we all did that, all of the time, the earth would be flat and at the center of the universe.

Testing

Not only do you need to test that something works, you also need to test that it fails when and how you expect it to. For example make sure asserts fire when they are supposed to. Make sure that what you assume won't compile actually doesn't compile. Make sure that the exception actually is thrown, and that no resource leaks happen during stack unwinding. Test corner cases such as 0, 1, -1, INT_MIN, INT_MIN+1, INT_MAX-1, and INT_MAX.