Writing clean code is what you need to know and do to call yourself a professional developer. There is no reasonable excuse for doing anything less than the best you can do.
In this blog post schoolofJavaScript.comWe will cover general clean coding principles for naming and using variables and functions, as well as some of the JavaScript-specific clean coding best practices.
First of all, what does clean coding mean?
Clean coding means that you write code first for yourself to review later and for your co-workers, and not for the machine.
You know you're working on clean code when every routine you read turns out to be pretty much what you expected.
Best practices for clean JavaScript code
Now that we know what every developer should aspire to, let's take a look at best practices!
How should I name my variables?
Use names that reveal intentions and don't worry if you have long variable names instead of saving a few keystrokes.
If you follow this practice, your names can be searched, which helps a lot when doing refactors or just looking for something.
// Try to avoid doing this let d; let dpfg; // Instead you can do this let days_para_la_deliverga; let number1;
Also, make significant distinctions and do not add additional and unnecessary names to variable names, such as their type (Hungarian notation).
// try to avoid doing this let stringname; let the Users; // Better change it so let name; let users;
Make its variable names easy to pronounce, because it takes less effort for the human mind to process them.
When you do code reviews with your fellow developers, these names are easier to refer to.
// avoid doing this let pName, sName; let cntr; let full = false; if (size> 100) {full = true} // change it to this let firstName, secondName; let counter; const Max_Size = 100 // ... const isFull = size> Max_Size
In short, don't cause additional mind mapping with their names.
How should I write my functions?
Your functions should do one thing only at an abstraction level.
// avoid doing this function Get_User_Route_Manager (req, res) {const {userId} = req.params // SQL query online knex ('user') .where ({id: userId}). first () .then (( user) => res.json (user))} // try to make const nametable = 'user' const User = {getOne (userId) {return knex (tableName) .where ({id: nametable}). first () }} // route manager (eg. server / routes / user / get.js) function Get_User_Routes_Handler (req, res) {const {userId} = req.params User.getOne (userId) .then ((user) => res.json (user))}
After you've written your functions correctly, you can test how well you did with the CPU profile, helping you find bottlenecks.
Use long, descriptive names
A function name must be a verb or verb phrase, and it must communicate its intent, as well as the order and intent of the arguments.
A long, descriptive name is much better than a short, enigmatic name or a long, descriptive comment.
// avoid doing that / ** * Invite a new user with their email address * @param {String} user's email address * / function inv (user) {/ * implementation * /} // try do this function inviteUser (emailaddress) {/ * implementation * /}
Avoid the long list of arguments
It uses a single object parameter and the destructuring mapping instead. It also makes handling of optional parameters much easier.
// Try to do function handlingUsers (fields, include, fromDate, toDate) {/ * implementation * /} handlingUsers (['firstName', 'secondName', 'email'], ['inviteUsers'],' 2016-06-26 ',' 2016-12-18 ') // Instead try to do this function UserManagement ({fields, include, fromDate, toDate}) {/ * implementation * /} UserRegister ({fields: [' firstName ',' secondName ' , 'email'], include: ['inviteUsers'], fromDate: '2016-06-26', toDate: '2016-12-18'})
Reduce side effects.
Use pure features without side effects, whenever you can. They are really easy to use and test.
// try not to do this function addItemToCart (cart, item, quantity = 1) {const alreadyInCart = cart.get (item.id) || 0 cart.set (item.id, alreadyInCart + quantity) return cart} // do this // without modifying the original card function addItemToCart (cart, item, quantity = 1) {const cartCopy = new Map (cart) const alreadyInCart = cartCopy.get (item.id) || 0 cartCopy.set (item.id, alreadyInCart + quantity) return cartCopy} // or reversing the method location // you can expect that the original object will be mutated // addItemToCart (cart, item, quantity) -> cart. addItem (item, quantity) const cart = new Map () Object.assign (cart, {addItem (item, quantity = 1) {const alreadyInCart = this.get (item.id) || 0 this.set (item.id , alreadyInCart + quantity) return this}})
Organize your functions in a file according to the downgrade rule
The top-level functions must be at the top and bottom levels below. Makes it natural to read the source code.
// avoid doing this // "I need a super long name" function getFullName (user) {return `$ {user.firstName} $ {user.lastName}`} function renderEmailTemplate (user) {// "or this" const fullName = getFullName (user) return 'Dear $ {fullName}, ...'} // Try to do this function renderEmailTemplate (user) {// "I need the full name of the user" const fullName = getFullName (user) return ' Dear $ {fullName}, ... '} // "I use this for email template rendering" function getFullName (user) {return `$ {user.firstName} $ {user.lastName}`}
Consultation or modification
Functions must do something (modify) or answer something (query), but not both.
Everyone likes to write JavaScript differently, what to do?
Since JavaScript is dynamic and flexibly written, it is especially prone to programming errors.
Use the business rules and formatting style of the company.
The stricter the rules, the less effort to point out the wrong format in code reviews. It should cover things like consistent names, indent size, white space placement, and even semicolons.
For starters, the standard JS style is pretty good, but not strict enough in my opinion. I can agree to most of the rules in the Airbnb style.
How to write nice asynchronous code?
Use the promises whenever you can.
Promises are natively available from Node 4. Instead of writing nested callbacks, you can have viable promise calls.
// Avoid asyncFunc1 ((err, result1) => {asyncFunc2 (result1, (err, result2) => {asyncFunc3 (result2, (err, result3) => {console.lor (result3)})})}) / / uses asyncFuncPromise1 () .then (asyncFuncPromise2) .then (asyncFuncPromise3) .then ((result) => console.log (result)) .catch ((err) => console.error (err))
Most libraries have callback and promise interfaces, preferring the latter. You can even convert callback APIs to promise based one by wrapping them with packages like es6-promisify.
// avoid const fs = require ('fs') function readJSON (filePath, callback) {fs.readFile (filePath, (err, data) => {if (err) {return callback (err)} try {callback (null , JSON.parse (data))} catch (ex) {callback (ex)}})} readJSON ('./ package.json', (err, pkg) => {console.log (err, pkg)}) // use const fs = require ('fs') const promisify = require ('es6-promisify') const readFile = promisify (fs.readFile) function readJSON (filePath) {return readFile (filePath) .then ((data) = > JSON.parse (data))} readJSON ('./ package.json') .then ((pkg) => console.log (pkg)) .catch ((err) => console.error (err)) The next step would be to use async / await (≥ Node 7) or generatorscon co (≥ Node 4) to achieve synchronous-like flows of control for your asynchronous code. const request = require ('request-promise-native') function getExtractFromWikipedia (title) {return request ({uri: 'https://en.wikipedia.org/w/api.php', qs: {titles: title, action: 'query', format: 'json', prop: 'extracts', exintro: true, explaintext: true}, method: 'GET', json: true}) .then ((body) => Object.keys ( body.query.pages) .map ((key) => body.query.pages [key] .extract)) .then ((extracts) => extracts [0]) .catch ((err) => {console. error ('getExtractFromWikipedia () error:', err) throw err})} // or use async function getExtractFromWikipedia (title) {let body try {body = await request ({/ * same parameters as above * /})} catch (err) {console.error ('getExtractFromWikipedia () error:', err) throw err} const extracts = Object.keys (body.query.pages) .map ((key) => body.query.pages [key] .extract) return extracts [0]} // or you can use: const co = require ('co') const getExtractFromWikipedia = co.wrap (function * (title) {let body try {body = yield request ({/ * same parameters as above * /})} catch (err) {console.error ('getExtractFromWikipedia () error:', err) throw err} const extracts = Object.keys (body.query.pages) .map ((key) => body. query.pages [key] .extract) return extracts [0]}) getExtractFromWikipedia ('Robert Cecil Martin') .then ((robert) => console.log (robert))
How should I write performant code?
You need to write clean code first and then use the profile to find performance bottlenecks.
Never try to write smart and performance code first, instead optimize code when you need it and reference actual impact instead of micro-benchmarks.
However, there are some simple scenarios like eagerly initializing what you can (e.g. joi schemas in route handlers, which would be used on every request and would add overhead if recreated each time) and using asynchronous code instead of a lock code.