¿Como limpiar tu código JavaScript con las mejores prácticas de codificación?

Escribir código limpio es lo que debe saber y hacer para llamarse un desarrollador profesional. No hay una excusa razonable para hacer algo menos que lo mejor que puedes hacer.

En esta publicación del blog escueladeJavaScript.com, cubriremos los principios generales de codificación limpia para nombrar y usar variables y funciones, así como algunas de las mejores prácticas de codificación limpia específicas de JavaScript.

En primer lugar, ¿qué significa codificación limpia?

La codificación limpia significa que, en primer lugar, escribe un código para que él mismo pueda revisarlo después y para sus compañeros de trabajo, y no para la máquina.

Usted sabe que está trabajando en un código limpio cuando cada rutina que lee resulta ser prácticamente lo que esperaba.

Las mejores prácticas para tener un código limpio en JavaScript

Ahora que sabemos a qué debe aspirar cada desarrollador, ¡Analicemos las mejores prácticas!

¿Cómo debería nombrar mis variables?

Usa nombres que revelen intenciones y no se preocupe si tiene nombres de variables largos en lugar de guardar algunos golpes de teclado.

Si sigues esta práctica, tus nombres se pueden buscar, lo que ayuda mucho cuando haces refactores o simplemente estás buscando algo.


// Intenta evitar hacer esto
let d;
let dpfg;

// En cambio puedes hacer esto
let dias_para_la_entrega;
let numero1;

Además, has distinciones significativas y no agregues nombres adicionales e innecesarias a los nombres de variables, como su tipo ( notación húngara ).


// trata de evitar hacer esto
let nombreString;
let losUsuarios;

// Mejor cambialo por eso
let nombre;
let usuarios;


Has que los nombres de sus variables sean fáciles de pronunciar, porque para la mente humana se necesita menos esfuerzo para procesarlos.

Cuando haces revisiones de código con sus compañeros desarrolladores, es más fácil hacer referencia a estos nombres.


// evita hacer esto
let pNombre, sNombre;
let cntr;

let lleno = false;
if (tamaño > 100) {
lleno = true
}

// cámbialo por esto
let primerNombre, segundoName;
let contador;

const Tamaño_máximo = 100
// ...
const estaLleno = tamaño > Tamaño_máximo

En resumen, no cause mapeo mental adicional con sus nombres.

¿Cómo debo escribir mis funciones?

Sus funciones deben hacer una cosa solo en un nivel de abstracción.


// evita hacer esto
function Obtener_Manejador_Rutas_Usuario (req, res) {
const { userId } = req.params
// consulta SQL en línea
knex('usuario')
.donde({ id: userId })
.primero()
.luego((usuario) => res.json(usuario))
}

// trata de hacer
const tablaDeNombres = 'usuario'
const Usuario = {
getUno (userId) {
return knex(tableName)
.where({ id: tablaDeNombres})
.primero()
}
}

// encargado de ruta (eg. server/routes/user/get.js)
function Obtener_Manejador_Rutas_Usuario (req, res) {
const { userId } = req.params
User.getOne(userId)
.then((usuario) => res.json(usuario))
}


Después de escribir sus funciones correctamente, puede probar qué tan bien lo hizo con el perfil de la CPU , lo que le ayuda a encontrar cuellos de botella.

Usa nombres largos y descriptivos

Un nombre de función debe ser un verbo o una frase verbal, y debe comunicar su intención, así como el orden y la intención de los argumentos.

Un nombre largo y descriptivo es mucho mejor que un nombre corto y enigmático o un comentario largo y descriptivo.


// evita hacer eso
/**
* Invitar a un nuevo usuario con su dirección de correo electrónico
* @param {String} dirección de correo electrónico del usuario
*/
function inv (usuarior) { /* implementacion */ }

// trata de hacer esto
function invitarUsuario (direccionDeEmail) { /* implementacion */ }

Evita la larga lista de argumentos

Utiliza un único parámetro de objeto y la asignación de desestructuración en su lugar. También hace que el manejo de parámetros opcionales sea mucho más fácil.


// Intenta hacer
function manejoDeUsuarios (fields, include, fromDate, toDate) { /* implementacion */ }
manejoDeUsuarios(['primerNombre', 'segundoNombre', 'email'], ['invitarUsuarios'], '2016-06-26', '2016-12-18')

// En cambio intenta hacer esto
function manejoDeUsuarios ({ fields, include, fromDate, toDate }) { /* implementacion */ }
registroDeUsuario({
fields: ['primerNombre', 'segundoNombre', 'email'],
include: ['invitarUsuarios'],
fromDate: '2016-06-26',
toDate: '2016-12-18'
})

Reducir los efectos secundarios.

Usa funciones puras sin efectos secundarios, siempre que pueda. Son realmente fáciles de usar y probar.


//intenta no hacer esto
function addItemToCart (cart, item, quantity = 1) {
const alreadyInCart = cart.get(item.id) || 0
cart.set(item.id, alreadyInCart + quantity)
return cart
}

// has esto
// sin modificar la carta original
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
}

// o invirtiendo la ubicación del método
// 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
}
})

Organice sus funciones en un archivo de acuerdo con la regla de reducción de nivel
Las funciones de nivel superior deben estar en los niveles superior e inferior a continuación. Hace que sea natural leer el código fuente.


// evita hacer esto
// "necesito un nombre súper largo"
function getFullName (user) {
return `${user.firstName} ${user.lastName}`
}

function renderEmailTemplate (user) {
// "o esto"
const fullName = getFullName(user)
return 'Dear ${fullName}, ...'
}

// Intenta hacer esto
function renderEmailTemplate (user) {
// "I need the full name of the user"
const fullName = getFullName(user)
return 'Dear ${fullName}, ...'
}

// "Uso esto para la representación de la plantilla de correo electrónico"
function getFullName (user) {
return `${user.firstName} ${user.lastName}`
}

Consulta o modificación

Las funciones deben hacer algo (modificar) o responder algo (consulta), pero no ambas cosas.

A todos les gusta escribir JavaScript de manera diferente, ¿qué hacer?
Dado que JavaScript es dinámico y está escrito de forma flexible, es especialmente propenso a errores de programación.

Utilice las reglas de trabajo y el estilo de formato de la empresa.

Cuanto más estrictas sean las reglas, menor será el esfuerzo por señalar el formato incorrecto en las revisiones de código. Debería abarcar cosas como nombres consistentes, tamaño de sangría, ubicación de espacios en blanco e incluso puntos y coma.
Para empezar, el estilo estándar de JS es bastante bueno, pero en mi opinión, no es lo suficientemente estricto. Puedo acordar la mayoría de las reglas en el estilo de Airbnb .

¿Cómo escribir código asíncrono agradable?

Usa las promesas siempre que puedas.

Las promesas están disponibles de forma nativa desde el Nodo 4. En lugar de escribir devoluciones de llamadas anidadas, puede tener llamadas de promesas viables.


// Evita
asyncFunc1((err, result1) => {
asyncFunc2(result1, (err, result2) => {
asyncFunc3(result2, (err, result3) => {
console.lor(result3)
})
})
})

// utiliza
asyncFuncPromise1()
.then(asyncFuncPromise2)
.then(asyncFuncPromise3)
.then((result) => console.log(result))
.catch((err) => console.error(err))

La mayoría de las bibliotecas tienen interfaces de devolución de llamada y promesa, y prefieren la última. Incluso puede convertir las API de devolución de llamada para prometer una basada envolviéndolas con paquetes como es6-promisify .


// evita
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) })

// utiliza
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))
El siguiente paso sería usar async/await(≥ Nodo 7) o generatorscon co(≥ Nodo 4) para lograr flujos de control similares a los síncronos para su código asíncrono.

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
})
}

// o utiliza
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]
}

// o puedes usar:
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))

¿Cómo debo escribir código performant?

En primer lugar, debe escribir un código limpio y luego usar el perfil para encontrar cuellos de botella en el rendimiento.

Nunca intente escribir código de desempeño e inteligente primero, en su lugar, optimice el código cuando lo necesite y haga referencia al impacto real en lugar de los micro-puntos de referencia.

Sin embargo, hay algunos escenarios sencillos como inicializar con entusiasmo lo que puede (por ejemplo, esquemas joi en los manejadores de rutas, que se usarían en cada solicitud y agregarían sobrecarga si se recreaban cada vez) y usar un código asíncrono en lugar de un código de bloqueo.