Blog-Risingstack-Com - Translate.goog-Prácticas Recomendadas de Codificación Limpia de JavaScript

También podría gustarte

Está en la página 1de 9

Prácticas recomendadas de codificación limpia de

JavaScript
blog-risingstack-com.translate.goog/javascript-clean-coding-best-practices-node-js-at-scale

December 13, 2016

Ingeniería RisingStack

Escribir código limpio es lo que debes saber y hacer para poder llamarte un
desarrollador profesional. No hay excusa razonable para hacer algo menos que lo
mejor posible.

“Incluso el código incorrecto puede funcionar. Pero si el código no está limpio, puede poner
de rodillas a una organización de desarrollo”. — Robert C. Martin (tío Bob)

En esta publicación de blog, cubriremos los principios generales de codificación limpia


para nombrar y usar variables y funciones, así como algunas mejores prácticas de
codificación limpia específicas de JavaScript.

Node.js at Scale es una colección de artículos que se centran en las necesidades de las
empresas con instalaciones más grandes de Node.js y desarrolladores avanzados de Node.
Capítulos:

Vea todos los capítulos de Node.js a escala:

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


La codificación limpia significa que, en primer lugar, escribe código para usted mismo y
para sus compañeros de trabajo y no para la máquina.

Su código debe ser fácilmente comprensible para los humanos.

Usted sabe que está trabajando en un código limpio cuando cada rutina que lee resulta ser
más o menos lo que esperaba.

1/9
Ahora que sabemos a qué debe apuntar todo desarrollador, ¡repasemos las mejores
prácticas!

¿Cómo debo nombrar mis variables?

Utilice nombres que revelen la intención y no se preocupe si tiene nombres de


variables largos en lugar de guardar algunas pulsaciones de teclado.

Si sigue esta práctica, sus nombres se pueden buscar, lo que ayuda mucho
cuando hace refactorizaciones o simplemente está buscando algo.

// DON'T
let d
let elapsed
const ages = arr.map((i) => i.age)

// DO
let daysSinceModification
const agesOfUsers = users.map((user) => user.age)

Además, haga distinciones significativas y no agregue sustantivos adicionales


e innecesarios a los nombres de las variables, como su tipo ( notación húngara ).

2/9
// DON'T
let nameString
let theUsers

// DO
let name
let users

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

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

// DON'T
let fName, lName
let cntr

let full = false


if (cart.size > 100) {
full = true
}

// DO
let firstName, lastName
let counter

const MAX_CART_SIZE = 100


// ...
const isFull = cart.size > MAX_CART_SIZE

En resumen, no provoques un mapeo mental adicional con tus nombres.

¿Cómo debo escribir mis funciones?

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

Las funciones deben hacer una cosa. Deberían hacerlo bien. Deberían hacerlo solo. —
Robert C. Martin (tío Bob)

3/9
// DON'T
function getUserRouteHandler (req, res) {
const { userId } = req.params
// inline SQL query
knex('user')
.where({ id: userId })
.first()
.then((user) => res.json(user))
}

// DO
// User model (eg. models/user.js)
const tableName = 'user'
const User = {
getOne (userId) {
return knex(tableName)
.where({ id: userId })
.first()
}
}

// route handler (eg. server/routes/user/get.js)


function getUserRouteHandler (req, res) {
const { userId } = req.params
User.getOne(userId)
.then((user) => res.json(user))
}

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

Use nombres largos y descriptivos

El nombre de una 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 descriptivo largo es mucho mejor que un nombre enigmático y corto o un


comentario descriptivo largo.

// DON'T
/** * Invite a new user with its email address * @param {String} user email
address */
function inv (user) { /* implementation */ }

// DO
function inviteUser (emailAddress) { /* implementation */ }

Evite la lista larga de argumentos


Utilice un único parámetro de objeto y una asignación de desestructuración en su lugar.
También facilita mucho el manejo de parámetros opcionales.

4/9
// DON'T
function getRegisteredUsers (fields, include, fromDate, toDate) { /*
implementation */ }
getRegisteredUsers(['firstName', 'lastName', 'email'], ['invitedUsers'], '2016-09-
26', '2016-12-13')

// DO
function getRegisteredUsers ({ fields, include, fromDate, toDate }) { /*
implementation */ }
getRegisteredUsers({
fields: ['firstName', 'lastName', 'email'],
include: ['invitedUsers'],
fromDate: '2016-09-26',
toDate: '2016-12-13'
})

Reducir los efectos secundarios

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

// DON'T
function addItemToCart (cart, item, quantity = 1) {
const alreadyInCart = cart.get(item.id) || 0
cart.set(item.id, alreadyInCart + quantity)
return cart
}

// DO
// not modifying the original cart
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 by invert 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
}
})

Organice sus funciones en un archivo de acuerdo con la regla de


reducción
Las funciones de nivel superior deben estar en la parte superior y los niveles inferiores
debajo. Hace que sea natural leer el código fuente.

5/9
// DON'T
// "I need the full name for something..."
function getFullName (user) {
return `${user.firstName} ${user.lastName}`
}

function renderEmailTemplate (user) {


// "oh, here"
const fullName = getFullName(user)
return `Dear ${fullName}, ...`
}

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

// "I use this for the email template rendering"


function getFullName (user) {
return `${user.firstName} ${user.lastName}`
}

Consulta o modificación
Las funciones deben hacer algo (modificar) o responder algo (consultar), pero no ambas
cosas.

A todos les gusta escribir JavaScript de manera diferente, ¿qué


hacer?
Como JavaScript es dinámico y está poco tipeado, es especialmente propenso a los errores
del programador.

Use reglas de linter y estilo de formato según el proyecto o la empresa.

Cuanto más estrictas sean las reglas, menos esfuerzo se dedicará a señalar el mal formato
en las revisiones de código. Debe cubrir cosas como nombres consistentes, tamaño de
sangría, ubicación de espacios en blanco e incluso punto y coma.

El estilo JS estándar es bastante bueno para empezar, pero en mi opinión, no es lo


suficientemente estricto. Puedo estar de acuerdo con la mayoría de las reglas al estilo de
Airbnb .

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


Usa Promesas siempre que puedas.

Las promesas están disponibles de forma nativa desde el nodo 4. En lugar de escribir
devoluciones de llamada anidadas, puede tener llamadas de promesa encadenables.

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

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

La mayoría de las bibliotecas que existen tienen interfaces de devolución de llamada y


promesa, prefiera la última. Incluso puede convertir las API de devolución de llamada en
una basada en promesas envolviéndolas con paquetes como 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) })

// PREFER
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 generators con co (≥ Nodo


4) para lograr flujos de control síncronos para su código asíncrono.

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

// PREFER
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
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))

8/9
¿Cómo debo escribir un código de alto rendimiento?
En primer lugar, debe escribir un código limpio y luego usar la creación de perfiles para
encontrar cuellos de botella en el rendimiento.

Nunca intente escribir código inteligente y de alto rendimiento primero, en su lugar,


optimice el código cuando lo necesite y consulte el impacto real en lugar de micro-
benchmarks.

Sin embargo, hay algunos escenarios sencillos como inicializar con entusiasmo lo que
pueda (por ejemplo, esquemas joi en controladores de ruta, que se usarían en cada
solicitud y agregarían una sobrecarga importante si se recrean cada vez) y usar código
asíncrono en lugar de código de bloqueo.

Siguiente paso en Node.js a escala


En el próximo episodio de esta serie, discutiremos las mejores prácticas avanzadas de
Node.js asíncrono y cómo evitar el infierno de la devolución de llamada .

Si tiene alguna pregunta sobre la codificación limpia, ¡no lo dude y hágamelo


saber en los comentarios!

9/9

También podría gustarte