Best Practices for Writing Super Readable CodeEN

lang
EN
date
Dec 16, 2021
Property
slug
write-readable-code
status
Published
tags
JavaScript
summary
Code readability is fundamental for development — it is key to maintainability and working together with a team. This article will detail the best practices when writing readable code in JavaScript.
type
Post
Code readability is fundamental for development — it is key to maintainability and working together with a team. This article will detail the important best practices when writing readable code in JavaScript.
notion image

Variables

1. Redundant variable

🙅‍♂️ Bad code
let kpi = 4; // Create but never used function example() { var a = 1; var b = 2; var c = a + b; var d = c + 1; var e = d + a; return e; }
🙆‍♂️  Good code
// let kpi = 4; // Delete useless variable function example() { var a = 1; var b = 2; return 2 * a + b + 1; }
Don't need to create extra variable which only uses once

2. Variable naming

🙅‍♂️ Bad code
let fName = 'jackie'; // WTF is `fName` let lName = 'willen';
🙆‍♂️  Good code
let firstName = 'jackie'; let lastName = 'willen';
Naming variables in a more clear way instead of commenting them

3. Extract constants

🙅‍♂️ Bad code
if (value.length < 8) { // What this '8' stands for? ... }
🙆‍♂️  Good code
const MAX_INPUT_LENGTH = 8; // Easy to understand and maintain. if (value.length < MAX_INPUT_LENGTH) { ... }
Extract inline parameter to scope constant makes others easy to understand and change its value.

4. Explainable variables

🙅‍♂️ Bad code
const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; saveCityZipCode( address.match(cityZipCodeRegex)[1], // WTF should I use this funtion address.match(cityZipCodeRegex)[2], );
🙆‍♂️  Good code
const address = 'One Infinite Loop, Cupertino 95014'; const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/; const [, city, zipCode] = address.match(cityZipCodeRegex) || []; // Easy to understand the return value and debug saveCityZipCode(city, zipCode);
Explain the returned value by assigning it to a variable, which can make your code more clear and easy to debug.

4. Variable fallbacks

🙅‍♂️ Bad code
const MIN_NAME_LENGTH = 8; // What if `fullName = ['jackie']`, your app will crash let lastName = fullName[1]; if(lastName.length > MIN_NAME_LENGTH) { ... }
🙆‍♂️  Good code
const MIN_NAME_LENGTH = 8; let lastName = fullName[1] || ''; // Simplest way to give a fallback value if(lastName.length > MIN_NAME_LENGTH) { .... } let propertyValue = obj.prop || 0; // `obj.prop` could be empty let attrValue = obj?.prop?.value ?? 0; // ES2020 (Nullish coalescing operator)

Functions

1. Function naming

🙅‍♂️ Bad code
function showFriendsList() {...} // Unable to guess the returned type
🙆‍♂️  Good code
function shouldShowFriendsList() {...} function isEmpty() {...} function canCreateDocuments() {...} function hasLicense() {...}
It is a good way to naming the function including its returned type, if the function only return a specific type.

2. Dry functions

🙅‍♂️ Bad code
function plusAbc(a, b, c) { // The return value will affect by api changes var c = fetch('../api'); return a + b + c; }
🙆‍♂️  Good code
function plusAbc(a, b, c) { return a + b + c; }
Keep function dry makes it easy to debug this code logic and unit test.

3. Describe the parameters

🙅‍♂️ Bad code
page.getSVG(api, true, false); // How should I use the second and third params?
🙆‍♂️  Good code
page.getSVG({ imageApi: api, includePageBackground: true, // Just easy to understand compress: false, })
It is better to pass the params as an object, if the function has multiple params, such as a global config function.

4. Split functions

🙅‍♂️ Bad code
function sendEmailToClients(clients) { clients.forEach(client => { const clientRecord = database.lookup(client) if (clientRecord.isActive()) { email(client) } }) }
🙆‍♂️  Good code
function sendEmailToActiveClients(clients) { clients.filter(isActiveClient).forEach(email) } function isActiveClient(client) { const clientRecord = database.lookup(client) return clientRecord.isActive() }
Each function should does its own things, split your code depending on its function makes it easy to refactor and maintain.

5. Function prioritized

🙅‍♂️ Bad code
for(i = 1; i <= 10; i++) { // Hard to understand a[i] = a[i] +1; }
🙆‍♂️  Good code
let b = a.map(item => ++item)

6. Better way instead of "if else"

🙅‍♂️ Bad code
if (a === 1) { ... } else if (a ===2) { ... } else if (a === 3) { ... } else { ... }
🙆‍♂️  Good code
let handler = { 1: () => {....}, 2: () => {....}. 3: () => {....}, default: () => {....} } handler[a]() || handler['default']()
Instead of write your logic inside a heavy if else group, bundle your logic with objects is easier to call and maintain

Syntax

1. Variable destruction

🙅‍♂️ Bad code
const obj = { player: 'john', age: 21 } const player = obj.player const age = obj.age
🙆‍♂️  Good code
const obj = { player: 'john', age: 21 } const { player, age } = obj
Instead of write your logic inside a heavy if else group, bundle your logic with objects is easier to call and maintain

2. Class

🙅‍♂️ Bad code
function Animal (name, energy) { this.name = name this.energy = energy } Animal.prototype.eat = function (amount) { console.log(`${this.name} is eating`) this.energy += amount } // extends function Dog (name, energy, breed) { Animal.call(this, name, energy) // get properties this.breed = breed } // Dog's constructor is point to Animal!!! Dog.prototype = Object.create(Animal.prototype) // get methods Dog.prototype.constructor = Dog // fix constructor Dog.prototype.bark = function () { console.log("Woof") this.energy -- }
🙆‍♂️  Good code
class Animal { constructor (name, energy) { this.name = name this.energy = energy } eat (amount) { console.log(`${this.name} is eating`) this.energy += amount } } class Dog extends Animal { constructor (name, energy, breed) { super (name, energy) this.breed = breed } bark () { console.log("Woof") this.energy -- } }
 

© Matoz 2021 - 2024