Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There’s more than one way to do it, but sometimes consistency is not a bad thing either. (TIMTOWTDIBSCINABTE)
Now is better than never.
Although later is often better than right now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
* Borrowed from Python zen with slight modifications. [+]
- JavaScript style guide
-
kebab-case
for folders.Covers if folder will be extracted to its own package some day. [+]
-
camelCase
orPascalCase
for files.Has problems on commiting case-sensitive filename changes with Git. [+]
✔️ Good
. └── src/ ├── product/ │ ├── application/ │ │ └── services/ │ │ └── SearchProductsService.js │ ├── domain/ │ │ └── services/ │ │ └── SearchProductsBySKUService.js │ └── infrastructure/ │ └── stores/ │ └── ProductAPIStore.js └── app.js
* Generated with https://tree.nathanfriend.io/.
-
A file that exports only one class, function, or constant should be named for that class, function or constant.
❌ Bad
// file name: programstore.js export class ProgramStore { ... }
✔️ Good
// file name: ProgramStore.js export class ProgramStore { ... }
-
Files whose exports multiple things, the file name should be kept short, meaningful and easily understandable to others.
-
Avoid
index
as a file name.It does not reflect the content of the file.
The file can’t live outside of the folder, because breaks the chain between folder name and file name.
NodeJS has a special treatment for
index
files, but other engines like Deno don’t.❌ Bad
. └── src/ └── program-filters/ ├── isNotOldFilter.js ├── hasMonthlyDownloadsFilter.js └── index.js
✔️ Good
. └── src/ └── program-filters/ ├── isNotOldFilter.js ├── hasMonthlyDownloadsFilter.js └── programFilters.js
-
Avoid generic names for folders. Be precise.
❌ Bad
. └── src/ ├── utils/ ├── config/ ├── vendors/ └── helpers/
✔️ Good
. └── src/ ├── program-guards/ ├── auth/ └── logger/
-
Pluralize only collections.
❌ Bad
class ProgramsStore { constructor() {} }
✔️ Good
class ProgramStore { constructor() {} }
✔️ Good
customers.forEach((customer) => { ... });
-
Use singularPlural for a list of a single property. [+]
✔️ Good
const programs = [{ id: 1, }, { id: 2, }]; const program = programs[0]; const programId = 1; const programIds = [1, 2];
-
Use pluralOfSingular for a list of single item list.
✔️ Good
const program = { topics: ['addons'], }; const topicsOfProgram = ['addons'];
-
Use pluralOfPlural for a list of lists.
✔️ Good
const programs = [{ topics: ['addons'], }, { topics: ['skins'], }]; const topicsOfPrograms = ['skins', 'addons'];
-
camelCase
for variables.❌ Bad
const firstname = 'Benadryl'; const first_name = 'Benadryl'; const FIRSTNAME = 'Benadryl'; const FIRST_NAME = 'Benadryl';
✔️ Good
const firstName = 'Benadryl';
-
UPPERCASE
for acronyms.Names are for readability, not to appease a computer algorithm. [+]
❌ Bad
const { XMLHttpRequest } = require('...'); const xmlHttpRequest = { ... }; function requestIpAddress() { ... } function dbmxmlParse() { ... }
✔️ Good
const { XMLHTTPRequest } = require('...'); const xmlHTTPRequest = { ... }; function requestIPAddress() { ... } function dbmXMLParse() { ... }
-
camelCase
for abbreviations.❌ Bad
const programID = 0; // Id[entifier]. const isEXEFile = true; // Exe[cutable]. const androidAPPName = 'Zoom'; // App[lication].
✔️ Good
const programId = 0; // Id[entifier]. const isExeFile = true; // Exe[cutable]. const androidAppName = 'Zoom'; // App[lication].
-
Avoid use of abbreviations for naming—be verbose.
❌ Bad
const accBalInSaving = 0; const dmgPerSec = 100;
✔️ Good
const accountBalanceInSavings = 0; const damagePerSecond = 100;
-
keyToValue or valueByKey for HashMaps.
-
No rules for keys naming.
❌ Bad
const mapStateCounty = { CA: 58, }; const numberOfCountiesIn = { CA: 58, }; const countyCountOf = { CA: 58, };
✔️ Good
const stateToCountiesCount = { CA: 58, }; const countiesCountByState = { CA: 58, };
-
UPPERCASE
for constants.Constants are string or integer literals, used as aliases for “hard-coded” values.
✔️ Good
const SECONDS = 60; const MINUTES = 60; const HOURS = 24; const DAY = SECONDS * MINUTES * HOURS; const DAYS_UNTIL_TOMORROW = 1;
-
Use affirmative names.
-
Use
is
,are
,have
,has
,can
,should
or any other prefix which indicates a yes or no as response. [+]❌ Bad
const isUsersLoggedIn = true;
✔️ Good
const isEachUserLoggedIn = true;
-
Use affirmative names.
❌ Bad
const isNotActive = true; if (!isNotActive) { ... }
✔️ Good
const isActive = true; if (isActive) { ... }
-
Use convenient name when the boolean is optional with negative default value. [+]
Avoid double negatives.
Implicit default.
❌ Bad
function createWidget(isEnabled = true) { ... }
✔️ Good
function createWidget(isDisabled) { ... }
-
Do not add redundant context to variable names when the context is already provided by the containing object or class. [+]
❌ Bad
const product = { productId: "XXX-XXX", productName: "book", }; product.userId;
✔️ Good
const user = { id: "XXX-XXX", name: "book", }; product.id;
-
Do not contextualize the naming of the provided arguments to the functions.
Easier perform massive find or replace.
❌ Bad
function findProgramById(id) { ... } const programId = 'XXXX-XXXX'; findProgramById(programId);
✔️ Good
function findProgramById(programId) { ... } const programId = 'XXXX-XXXX'; findProgramById(programId);
❌ Bad
function findProgramById({ id }) { ... } const programId = 'XXXX-XXXX'; findProgramById({ id: programId });
✔️ Good
function findProgramById({ programId }) { ... } const programId = 'XXXX-XXXX'; findProgramById({ programId });
-
Use
verbAt
.✔️ Good
const createdAt = new Date().toISOString(); const updatedAt = new Date().toISOString();
-
camelCase
for functions. -
Recommended use verbAdjectiveContextStructureHow pattern, where verb stick to action, adjective act as modifier for a context, and context is the object being interacted with. Adjective, context, structure and how are optionals. [+]
❌ Bad
function programGetActiveById(programId) { ... }
✔️ Good
function findActiveProgramById(programId) { ... }
-
Skip
get
prefix when function is returning a boolean.
Prefix | Description |
---|---|
to |
Convert object to another type. |
plus |
Returns a copy object with the amount added. |
minus |
Returns a copy object with the amount subtracted. |
with |
Return a copy with element target. |
of |
Returns an instance where the factory is primarily validating the input parameters, not converting them. |
from |
Converts the input parameters to an instance of the target object, which may involve losing information from the input. |
parse |
Parses the input string to produce an instance of the target class. |
format |
Uses the specified formatter to format the values in the temporal object. |
at |
Combines this object with another. |
get |
Return a part of the state of the object. |
list |
Return a collection of part of the state of the object. |
create |
Returns a new instance on each invocation. |
build |
Returns a new instance where many separate pieces of information are combined in some way. |
generate |
Returns a new instance where a calculation is used to produce a value from an input. |
Partial borrowed from oracle documentation. [+]
-
PascalCase
for constructors.✔️ Good
class GoodGreeter { name; constructor() { this.name = 'hello'; } }
-
Where appropriate, use a compound word for the naming. The second part of the derived name can be the name of the pattern. [+]
✔️ Good
class GetItemBySlugUseCase { constructor() {} }
-
Infer context on naming class methods.
❌ Bad
class ProgramStore { getProgramById(programId) { ... } }
✔️ Good
class ProgramStore { getById(programId) { ... } }
-
PascalCase
for enumerations and value names. [+] -
Singular type name.
Enumerations are used to represent a fixed number of possible values.
❌ Bad
const codes = { notFound: 'NotFound', badRequest: 'BadRequest', };
✔️ Good
const Code = { NotFound: 'NotFound', BadRequest: 'BadRequest', };
-
Use measures as suffix.
❌ Bad
const REQUEST_TIMEOUT = 2000; const MIN_COMPRESSION = 64;
✔️ Good
const REQUEST_TIMEOUT_MS = 2000; const MIN_COMPRESSION_BYTE = 64;
-
Use
count
as suffix to indicate quantity. [+]count
is shorter thannumberOf
.number
is ambiguous. It could be a count, or an index, or some other number. -
Use
index
as suffix to indicate sequence number0..n
.❌ Bad
const MAX_PROGRAMS = 5; const PROGRAM_NUMBER = 2;
✔️ Good
const MAX_PROGRAM_COUNT = 5; const PROGRAM_INDEX = 2;
-
Don’t use descriptive names for public modules.
Descriptive names are anti-democratic. [+].
-
Use
sync
suffix for synchronous function when you have asynchronous version of the same function.NodeJS implicit convention. [+]
-
Use
when
prefix for variables. [+]It sounds like the Promise
then
method.It should mean ‘when this happens’.
✔️ Good
async function listPrograms() { ... } const whenPrograms = listPrograms(); const programs = await whenPrograms;
❌ Bad
function listPrograms() { ... } async function listProgramsAsync() { ... } const whenPrograms = listProgramsAsync(); const programs = await whenPrograms;
✔️ Good
function listProgramsSync() { ... } async function listPrograms() { ... } const whenPrograms = listPrograms(); const programs = await whenPrograms;
-
Use
gen
suffix when you have Generator version of the same function. -
Use
iter
prefix for variables. [+]❌ Bad
function* listProgramsGen() { ... } const iterPrograms = listProgramsGen();
✔️ Good
function* listPrograms() { ... } const iterPrograms = listPrograms();
✔️ Good
async function listPrograms() { ... } async function* listProgramsGen() { ... } const iterPrograms = listProgramsGen(); const programs = []; for await (let program of iterPrograms) { programs.push(program); }
-
Delimit scope blocks with curly braces. [+]
-
Opening brace goes on the end of the current line, and the last brace in the new line.
Known as egyptian brackets. [+]
❌ Bad
if (true) doSomething();
✔️ Good
if (true) { doSomething(); }
-
Space between block scopes.
❌ Bad
if (true) { doSomething(); } if (true) { doSomethingElse(); }
✔️ Good
if (true) { doSomething(); } if (true) { doSomethingElse(); }
- Be consistent with existing code.
-
Use named exports.
To avoid interoperational problems between ES Modules and CommonJS. [+]
❌ Bad
export default class MyClass { ... }
✔️ Good
export class MyClass { ... }
-
Use function syntax for functions.
In general function syntax is preferred, in particular for top level functions (to avoid TDZ issues,
export const foo = () => {}
function will not be available to be called unless the module where it came from has already been evaluated, otherwise you'll get the temporal dead zone error, happens with circular dependencies). [+] -
Use arrow functions for callbacks.
Arrow syntax should be limited to closures.
-
Avoid use of annotations for decorations.
Are executed at time of interpretation, that could create inconvenience when you are injecting dependencies which need be initialized at tame of class instance creation (e.g.: happens on resolving with auto-wire).
❌ Bad
class MyClass { @decorate() doStuff() { ... } }
✔️ Good
class MyClass { constructor() { this.doStuff = decorate(this.doStuff); } doStuff() { ... } }
-
Use interfaces over aliases where possible.
❌ Bad
type FnAsync = (...args: any[]) => Promise<any>;
✔️ Good
interface FnAsync { (...args: any[]): Promise<any>; }
-
Use classes if you have more than one method and shared state.
❌ Bad
class RedisClient { constructor(baseURL) { ... } create() { ... } } const redisClient = new RedisClient(baseURL); const cacheClient = redisClient.create();
✔️ Good
function createRedisClientCreator(baseURL) { return function createRedisClient() { ... } } const createRedisClient = createRedisClientCreator(baseURL); const cacheClient = createRedisClient();
-
Every package should contain all the needed dependencies.
Doing this allows us to cleanly decouple projects (packages) from one another, since you don't have to merge all their dependencies in one huge unmaintainable list. [+]
-
Comments are code smell, when comment describes what the code is doing.
From a philosophical point of view, each line of code contains a technical debt for further support. Only the final functionality is the value. And if you can implement it without a single line (of commentary) at all, then everything is perfect. Otherwise, you should always have the WHY / WHY motive you added it for. Theoretically, this motive should be indicated in the commentary. The WHAT question is usually resolved by meaningful of the identifiers of classes, functions and variables. The question HOW should be clear from the code itself (also theoretically). [+] [++]
- Use composition over inheritance.
If we start from the fact that programming is a chain of taking decisions, the aim of this guide is to inspire you and facilitate to take such decisions.
Following guide is a set of different sources most of them conveniently linked.