This document serves as a reference regarding my coding style and conventions moving forward. This document will be continuously updated as I fix any typos, add or clarify content, or even change my style over time. As such, the style guidelines for previous projects may differ from the guidelines shown here.
The following rules cover C/C++ and JavaScript, both of which I have used on a regular basis for the majority of my projects, and where I have developed my own style over time. For most other languages, I follow whichever style guides are standard for that language, such as the style guides for Ruby and Ruby on Rails.
Each indentation level is 2 spaces long, and spaces are used instead of tab characters.
The maximum number of characters per line varies on a per-project basis, but 80 characters is a general starting point that can be adjusted depending on the code.
Names of variables, class instances (objects), and functions follow lowerCamelCasing
, while names of classes follow UpperCamelCasing
. Constant variables, however, are CAPITALIZED_WITH_UNDERSCORES
. These names should be descriptive enough to understand their purpose but not too descriptive so that they are too long. There is no hard limit to the maximum name length, which should be left to individual judgement.
Global variables should be avoided wherever possible.
Brackets that denote the start and end of a scope (usually {}
), usually for a control structure or a function, follow this format:
if (condition) {
// do something
return;
}
The exception to this is when the enclosing code consists of two statements at most and is short enough to fit on one line, so the brackets should be on the same line as well. They can even be omitted entirely in the case of only one statement.
if (condition1) { foo(); return; }
if (condition2) break;
For other brackets like ()
and []
, matching pairs should stay on one line unless the enclosing code is too long to fit on one line, such as when listing function parameters or array elements. In either case, they are formatted as such:
void foo(
type1 param1,
type2 param2,
// ...
typeN paramN,
) {
// do something
}
const string STATE_NAMES = [
"Alabama",
"Alaska",
// ...
"Wyoming",
];
Also note that trailing commas are preferred when listing elements this way (except for cases when there is only one function parameter or array element).
For readability, I generally wrap at least one whitespace character around both sides of every keyword and binary operator, and around the outsides of each pair of brackets.
int x = a + b;
if (x > 0) return;
Common exceptions include:
- no whitespace before semicolons:
foo(a, b);
instead offoo(a, b) ;
- function calls or declarations:
foo(a, b);
instead offoo (a, b);
Nesting if statements inside one another should be avoided wherever possible, as the multiple scope levels can make it hard to follow the logic or track every single case this way. Combining conditions with and
, or
, etc. is one common way to achieve this. The else
keyword is also unnecessary if the preceding if
statement contains keywords that exit the current scope (such as continue
, break
, or return
).
double abs(double x) {
if (x >= 0) return x;
return x * -1.0;
}
With for loops, however, there can be as much nesting as the program requires. The below example iterates through a multi-dimensional array.
for (size_t i = 0; i < dim1Length; i++) {
for (size_t j = 0; j < dim2Length; j++) {
for (size_t k = 0; k < dim3Length; k++) {
// ...
}
}
}
While loops usually start with while (true)
so that the loop can be exited at any point with a terminating condition, thus eliminating the need for do-while loops.
while (true) {
// some code here
if (terminatingCondition) break;
// some code here
}
If there is no code above the terminating condition in the loop, then the terminating condition can replace true
instead (but remember to negate its value when doing this).
while (!terminatingCondition) {
// some code here
}
Switch statements should be avoided in favor of an if-else if-else
statement. If the switch statement is inside a loop, then it can be replaced by multiple if-continue
statements instead, one for each case.
{
if (case1) {
// code for case 1 here
continue;
}
if (case2) {
// code for case 2 here
continue;
}
// ...
if (caseN) {
// code for case N here
continue;
}
// code for default case here
}
In principle, all function parameters should be passed in by value rather than by reference. This is to avoid complex pointer logic in C/C++ as well as avoid any bugs associated with modifying parameter values. In addition, be sure to limit the number of parameters for each function (7 is a generally accepted limit), and limit each function to work on a singular task. Break up large functions/tasks into smaller tasks if necessary.
- Written by: Edward Ly
- Last Updated: 18 December 2019
- Written in Atom with markdown-writer and linted with linter-markdown
This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.