Coding Style Guide
Guiding Principles
Good style is subjective and many decisions are subjective. The project uses these guiding principles:
- Consistency. The code in the project should look as if it had been written by a single person. Don’t write code for yourself, but for the many people who will read it later.
- Clarity before performance. Write code that is easy to read, and avoid obscure constructs that may obfuscate the code to improve performance. For example, RegEx are crazy fast in all modern browsers, and trying to roll out your own pattern matching will result in more code and less performance. If you think something could be made faster, use http://jsben.ch/ to try out options in various browsers and compare the results. You might be surprised.
- Robustness Principle (Postel’s Law). “Be conservative in what you do, be liberal in what you accept from others”. For example, functions that are invoked internally do not need to check that the input parameters are valid. However, public APIs should check the validity of parameters, and behave reasonably when they are invalid.
The project is setup to use prettier
an opinionated
code formatter. You can configure your editor to apply the formatting automatically on
save, for example. See this plugin for Visual Studio Code.
In general:
- Follow the conventions already in use in the codebase
- Follow the Google JavaScript Style Guide, with the exception of the indentation with 4-spaces instead of 2-spaces.
Summary of Naming Conventions
Repo | math-json |
Directory | html-test-cases |
File | json-parser.ts |
Module | jsonParser |
Class, Enum | ComplexNumber , JsonParser |
Method, Function | readFile() Use an action verb isDirty or hasFinished for boolean |
Private Method | private resetBuffer() |
Private Function | Like function, marked @private and not exported |
Parameter | initialPosition |
Unused parameter | _initialPosition or _ |
Accessor | getContent or get content |
Constant, Enum Value | HTTP_HEADER_SIZE |
Template parameter | T , TYPE |
Other best practices
- Don’t use
default
for exports * - Avoid boolean as arguments. Instead, use an
options
object literal with key/value pairs spelling out the meaning of the boolean. - Functions should have at most 3 arguments. If additional configuration is necessary, use an optional object literal as the last argument.
// 💩
function renderText(text: string,
fontFamily = 'Helvetica',
fontSize = 12,
lineSpacing = 1.2,
style = ''
);
renderText("hello world", "Helvetica", 18, 1.5, "bold");
// 👍
function renderText(text: string, {
fontFamily = 'Helvetica',
fontSize = 12,
lineSpacing = 1.2,
style = ''
});
renderText("hello world");
renderText("hello world", {
fontFamily: "Helvetica",
fontSize: 18,
lineSpacing: 1.5,
style: "bold"
});
- Avoid providing an explicit type when the compiler can infer it.
// 💩
let action: string = 'fly';
let distance: number = 100;
// 👍
let action = 'fly';
let distance = 100;
- Use higher order functions:
.map()
,.reduce()
,.filter()
,.some()
,.every()
and.find()
. - To make a shallow clone of an object literal or of an array, use the spread operator
const array = ['Thranduil', 'Legolas', 'Thingol', 'Glorfindel', 'Galadriel'];
const object = { name: 'Gandalf', cloak: 'Grey' };
const objectCopy = { ...object };
const arrayCopy = { ...array };
- To make a deep clone of an object literal or an array, use
structuredClone()
.
const array = [
['Frodo', 'Samwise', 'Meriadoc', 'Peregrin'],
['Gandalf'],
['Legolas'],
['Gimli'],
['Aragorn', 'Boromir'],
];
const object = {
name: 'Gandalf',
aliases: ['Mithrandir', 'Tharkûn', 'Olórin', ' Incánus'],
};
const deepClone = structuredClone(object);
const arrayDeepCopy = structuredClone(array);