- Notifications
You must be signed in to change notification settings - Fork1
daisugiland/javascript-style-guide
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
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 thanright 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 withhttps://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.jsexportclassProgramStore{ ...}
✔️ Good
// file name: ProgramStore.jsexportclassProgramStore{ ...}
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
classProgramsStore{constructor(){}}
✔️ Good
classProgramStore{constructor(){}}
✔️ Good
customers.forEach((customer)=>{ ...});
UsesingularPlural for a list of a single property.[+]
✔️ Good
constprograms=[{id:1,},{id:2,}];constprogram=programs[0];constprogramId=1;constprogramIds=[1,2];
UsepluralOfSingular for a list of single item list.
✔️ Good
constprogram={topics:['addons'],};consttopicsOfProgram=['addons'];
UsepluralOfPlural for a list of lists.
✔️ Good
constprograms=[{topics:['addons'],},{topics:['skins'],}];consttopicsOfPrograms=['skins','addons'];
camelCase
for variables.❌ Bad
constfirstname='Benadryl';constfirst_name='Benadryl';constFIRSTNAME='Benadryl';constFIRST_NAME='Benadryl';
✔️ Good
constfirstName='Benadryl';
UPPERCASE
for acronyms.Names are for readability, not to appease a computer algorithm.[+]
❌ Bad
const{ XMLHttpRequest}=require('...');constxmlHttpRequest={ ...};functionrequestIpAddress(){ ...}functiondbmxmlParse(){ ...}
✔️ Good
const{ XMLHTTPRequest}=require('...');constxmlHTTPRequest={ ...};functionrequestIPAddress(){ ...}functiondbmXMLParse(){ ...}
camelCase
for abbreviations.❌ Bad
constprogramID=0;// Id[entifier].constisEXEFile=true;// Exe[cutable].constandroidAPPName='Zoom';// App[lication].
✔️ Good
constprogramId=0;// Id[entifier].constisExeFile=true;// Exe[cutable].constandroidAppName='Zoom';// App[lication].
Avoid use of abbreviations for naming—be verbose.
❌ Bad
constaccBalInSaving=0;constdmgPerSec=100;
✔️ Good
constaccountBalanceInSavings=0;constdamagePerSecond=100;
keyToValue orvalueByKey for HashMaps.
No rules for keys naming.
❌ Bad
constmapStateCounty={CA:58,};constnumberOfCountiesIn={CA:58,};constcountyCountOf={CA:58,};
✔️ Good
conststateToCountiesCount={CA:58,};constcountiesCountByState={CA:58,};
UPPERCASE
for constants.Constants are string or integer literals, used as aliases for “hard-coded” values.
✔️ Good
constSECONDS=60;constMINUTES=60;constHOURS=24;constDAY=SECONDS*MINUTES*HOURS;constDAYS_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
constisUsersLoggedIn=true;
✔️ Good
constisEachUserLoggedIn=true;
Use affirmative names.
❌ Bad
constisNotActive=true;if(!isNotActive){ ...}
✔️ Good
constisActive=true;if(isActive){ ...}
Use convenient name when the boolean is optional with negative default value.[+]
Avoid double negatives.
Implicit default.
❌ Bad
functioncreateWidget(isEnabled=true){ ...}
✔️ Good
functioncreateWidget(isDisabled){ ...}
Do not add redundant context to variable names when the context is already provided by the containing object or class.[+]
❌ Bad
constproduct={productId:"XXX-XXX",productName:"book",};product.userId;
✔️ Good
constuser={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
functionfindProgramById(id){ ...}constprogramId='XXXX-XXXX';findProgramById(programId);
✔️ Good
functionfindProgramById(programId){ ...}constprogramId='XXXX-XXXX';findProgramById(programId);
❌ Bad
functionfindProgramById({ id}){ ...}constprogramId='XXXX-XXXX';findProgramById({id:programId});
✔️ Good
functionfindProgramById({ programId}){ ...}constprogramId='XXXX-XXXX';findProgramById({ programId});
Use
verbAt
.✔️ Good
constcreatedAt=newDate().toISOString();constupdatedAt=newDate().toISOString();
camelCase
for functions.Recommended useverbAdjectiveContextStructureHow 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
functionprogramGetActiveById(programId){ ...}
✔️ Good
functionfindActiveProgramById(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
classGoodGreeter{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
classGetItemBySlugUseCase{constructor(){}}
Infer context on naming class methods.
❌ Bad
classProgramStore{getProgramById(programId){ ...}}
✔️ Good
classProgramStore{getById(programId){ ...}}
PascalCase
for enumerations and value names.[+]Singular type name.
Enumerations are used to represent a fixed number of possible values.
❌ Bad
constcodes={notFound:'NotFound',badRequest:'BadRequest',};
✔️ Good
constCode={NotFound:'NotFound',BadRequest:'BadRequest',};
Use measures as suffix.
❌ Bad
constREQUEST_TIMEOUT=2000;constMIN_COMPRESSION=64;
✔️ Good
constREQUEST_TIMEOUT_MS=2000;constMIN_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
constMAX_PROGRAMS=5;constPROGRAM_NUMBER=2;
✔️ Good
constMAX_PROGRAM_COUNT=5;constPROGRAM_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
asyncfunctionlistPrograms(){ ...}constwhenPrograms=listPrograms();constprograms=awaitwhenPrograms;
❌ Bad
functionlistPrograms(){ ...}asyncfunctionlistProgramsAsync(){ ...}constwhenPrograms=listProgramsAsync();constprograms=awaitwhenPrograms;
✔️ Good
functionlistProgramsSync(){ ...}asyncfunctionlistPrograms(){ ...}constwhenPrograms=listPrograms();constprograms=awaitwhenPrograms;
Use
gen
suffix when you have Generator version of the same function.Use
iter
prefix for variables.[+]❌ Bad
function*listProgramsGen(){ ...}constiterPrograms=listProgramsGen();
✔️ Good
function*listPrograms(){ ...}constiterPrograms=listPrograms();
✔️ Good
asyncfunctionlistPrograms(){ ...}asyncfunction*listProgramsGen(){ ...}constiterPrograms=listProgramsGen();constprograms=[];forawait(letprogramofiterPrograms){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
exportdefaultclassMyClass{ ...}
✔️ Good
exportclassMyClass{ ...}
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
classMyClass{ @decorate()doStuff(){ ...}}
✔️ Good
classMyClass{constructor(){this.doStuff=decorate(this.doStuff);}doStuff(){ ...}}
Use interfaces over aliases where possible.
❌ Bad
typeFnAsync=(...args:any[])=>Promise<any>;
✔️ Good
interfaceFnAsync{(...args:any[]):Promise<any>;}
Use classes if you have more than one method and shared state.
❌ Bad
classRedisClient{constructor(baseURL){ ...}create(){ ...}}constredisClient=newRedisClient(baseURL);constcacheClient=redisClient.create();
✔️ Good
functioncreateRedisClientCreator(baseURL){returnfunctioncreateRedisClient(){ ...}}constcreateRedisClient=createRedisClientCreator(baseURL);constcacheClient=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 theWHY /WHY motive you added it for. Theoretically, this motive should be indicated in the commentary. TheWHAT question is usually resolved by meaningful of the identifiers of classes, functions and variables. The questionHOW 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.
About
✏️ JavaScript Style Guide
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.