2. Introduction
The following documents the Coding Standards Policies of Crystal-Clear Research, Inc.
Herein is accumulation of knowledge and wisdom gathered over a period from 1992 through October 2024 of software development in over 40 different languages including 7 different assembly languages. But more than that — the knowledge and wisdom shared by others in written documents and textbooks[1] that they wrote to share their discovered golden nuggets to the world of software development.
If you have, by this point, glanced forward to see how extensive this document is, you may feel like this is one set of Coding Standards that is far too long to be bothered with.
However, 20 years of practice using and polishing these Coding Standards has reaped untold rewards in terms of bugs caught and bugs avoided. In fact, taking someone else’s code with a hard-to-find bug in it, the standard practice to find the bug has been to first morph the code into compliance with these Coding Standards and in almost every case, the bug jumped out at me before I was done. Occasionally others have come to me with, “...please help me find a hard-to-find bug!” In each case I worked together with the person while they watched, and in each case, all I did to find it was morph their code into compliance with these Coding Standards and voilà — the bug jumped out.
Of course, this method is not an “end-all-be-all” to finding bugs — merely step 1 — and simultaneously a step helpful to gain a depth understanding of the code. But a high percentage of hard-to-find bugs are hidden behind:
names that say one thing, but are really another;
conflicts between signed and unsigned integers;
conflicts between integer sizes;
conflicts between other data types (e.g. casting types when they are not compatible); and
missing or limited visibility on where a value comes from (e.g. local variable, global variable, formal argument, member of a struct, macro);
what thread is calling (or may call) a function.
When such things are the source of a bug, using this Coding Standard has a high probability of smoking it out by making the bug visible where it was not visible before. If you have been using it all along, all the better, due to the number of bugs that didn’t get created because using these policies made it visible before it became part of the code you delivered.
That kind of success suggests these Coding Standards are well worth the time and effort to get to know well, plus the rationale behind them, because they have saved typically days, weeks or months per project of debugging time because of the number of bugs that were prevented in the first place.
Especially powerful in this toolbox is Design by Contract — when it finds bugs, they are usually huge time savers in hard-to-find bugs that did not have to be sleuthed out because they were found by failing contract assertions. To date, I have lost count of the number of hours, days and weeks of bug-finding Design by Contract made unnecessary because it found the bugs early in development.
As you will hopefully see, these Coding Standards can be used in most high-level languages.
2.1. Purpose
The motivations for having a Coding Standard are many, but this author believes the following two motivations are the most important of them all, and make the effort worthwhile all by themselves:
to make the code easier and therefore faster to read and fully understand (including its design rationale);
with the gains from #1 above, thereby produce more, finished, higher-quality code, with fewer bugs, in less time.
#1 has many beneficial and crucial side effects, which experienced developers are already well aware of, the most important of which is #2. #1 I am going to stress in this document, as one of the most important ingredients of quality source code just below Code Correctness. I call it Understandability.
- Understandability
Understandability is a quality of source code and its documentation. It is the ease with which the reader can fully understanding what the CPU (and any peripherals involved) will be doing when executing a block of code, plus its impacts on the rest of the system. Understandability is inversely proportional to the time it takes for a programmer to reach full understanding of the code he is reading.
Because understandability results in more, finished, higher-quality code, with fewer bugs, in less time, it can be safely said that understandability is almost the entire reason of having a Coding Standard at all. Almost every part of this Coding Standard is aimed at shortening the time it takes for a programmer to fully — I repeat: FULLY — understand the code he is looking at. The source of a variable’s content (via scope prefix), the number of bits and signed-ness of variables (via type prefixes), what it is (via precise naming), the nature of what a function returns (via type prefixes and precise naming), diagrams, peudocode illustrating a complex algorithm — all have as their primary purpose — increasing understandability.
While the quality of Readability is important, it is really a sub-part of Understandability. So it is the understandings (intentionally plural) of the reader that we focus on when we are writing and documenting code, because they are the end results results we are seeking.
2.1.1. Primary Gains
The below Coding Standards achieve #1 and #2 by increasing visibility of properties such as variable scope, data types, and meanings of things that can otherwise be obscure when reading source code. Examples:
How many bits are involved in each part of an integer computation? (This is important so as to avoid silent numeric overflows, the source of many bugs.)
Signed or unsigned? (Incautious comparing and/or moving data between signed and unsigned values is almost always an error and is the source of many bugs.)
Where is data coming from? (Which module? Which peripheral? From an argument? Local? Global? From a field of an instance of an object? Function return value? A macro?) The answer to this question then answers part of the question, “What can affect its value and/or validity?”.
Where is data going to? (Same.)
Being able to SEE these things quickly (preferably while minimizing or eliminating the need to refer to other parts of the code) helps programmers to get more things right the first time. This applies to new code as well as changes to existing code.
This increases development speed because fewer bugs result in less testing and debugging time being required to know we are delivering reliable software. As a crucial side effect, it also increases the quality of the end-user experience, as well as the maintainability of the code. (Maintainability is also impacted by the clarity of the design documentation.)
The temptation, familiar to any professional programmer, is to shortcut this to “be faster” in the short run, yet it costs more time (and customer goodwill due to bugs) in the long run. It manifests in delays getting the product to market because of bugs near the end of the development cycle, and/or lowered quality of the final product and lowered quality of the end-user experience (and lowered maintainability of the code itself, which impacts its life later if it will become the target of future enhancement and/or fixes).
The counter-tactic to use when this temptation arises is: recognize the temptation and apply the discipline of sticking to the Coding Standards. This rewards everyone in the long run.
The above is from hard-won experience. There are plenty of books out there that back this up.
2.2. Guiding Principles
Individual programmers most often do not own the source code they write. All software development that is work for hire for an employer or a client should be constructed in a workmanlike manner. This is important because other team members that may have to pick up the development where you left off, and thus need to be able to fully understand the code as quickly as possible.
It is cheaper and easier to prevent a bug from creeping into code than it is to find and fix it afterwards. A key strategy in this objective is to write code in which the compiler, linker, or a static analysis tool can detect such defects automatically — i.e. before the code is allowed to execute. (This is also why we like to turn on “Additional Warnings” and “Strict ANSI Warnings” compiler setting in C projects.)
The ISO/ANSI C Programming Language “Standard” permits a considerable amount of variation between compilers. Certain “gray areas” of code can cause identical code to behave differently when compiled under different compilers. Minimizing such gray areas automatically eliminates most of these problems. But when such gray areas of code need to be used, there are certain disciplines that, when employed, can eliminate or at least permit quick detection of portability problems.
Reliability, Readability, Understandability, efficiency and sometimes portability of source code is more important than programmer convenience.
There are many sources of defects in software. The original development team will create some defects. Programmers who later maintain, extend, port, and/or reuse the resulting source code may create additional defects, including as a result of not fully understanding the original code.
The number and severity of defects introduced by the original programmer(s) can be reduced through disciplined conformance with certain coding practices, such as writing code that is maximally readable and understandable, and documenting the design — especially the whys in the design — when it is complex.
The number and severity of defects introduced by maintenance programmers can also be reduced by the original programmer. For example, the appropriate use of portable fixed-width integer types (e.g. int32_t) helps ensure that no future port of the code will encounter an unexpected numeric overflow or underflow.
The number and severity of defects introduced by maintenance programmers can also be reduced through the disciplined use of consistent commenting and style practices, so that everyone in an organization can more easily understand the meaning and proper use of variables, functions, and modules.
The more thoroughly a proven Coding Standard is used, the more effective it is. Thus, the enforceability of such Coding Standards increases its effectiveness. Thus, when it is the case that two or more alternative rules would equally prevent defects, the more easily enforced rule is the better choice.
In the absence of a needed rule, or a conflict within the Coding Standard your team commits to follow, the spirit of the above principles should be applied — especially those that increase the code’s understandability.
2.3. Senior Policy
The following has been found to help teams of programmers more easily work together and simultaneously be able to “cover” for one another if a programmer becomes unavailable for any reason.
Editor tab settings:
- Mandatory:
Tab size 4.
- Mandatory:
Indent size 4.
- Mandatory:
Keep tabs (do NOT insert spaces) when [TAB] key is pressed.
- Mandatory:
Tabs always provide the leading whitespace in a line and are never used anywhere else in a line. Spaces are always used to provide whitespace after the first non-blank character in the line. This includes whitespace used to align columns in code or comments. (My programmable editor converts a file that violates this into one that complies with this with 2 keystrokes.)
- Optional:
Smart indenting (it helps).
Some editors (e.g. Visual Studio and VS Code and several other IDEs) now support
an .editorconfig
file placed in the root directory of a project. It works like
.gitignore
in that it can be placed at the top of any directory tree that
requires a different editor configuration: for settings covered by multiple
.editorconfig
files in a project, the setting in the closest .editorconfig
file overrides that setting set by .editorconfig
files higher up in the directory
tree. See editorconfig.org for more details.
2.4. Where to Go from Here
If you want to dive into something short to get started right away, feel free to jump to Quick-Start Rules for Embedded C Systems where most of the important stuff is all in one place. But don’t forget to come back to the details starting with the Development Definitions, because those details are the core of how these Coding Standards help the developer to smoke out bugs before they happen.
If you want to get the whole picture, with all the whys and wherefores, continue reading!