0% encontró este documento útil (0 votos)
5 vistas46 páginas

Mejores Prácticas de Código Limpio en JavaScript

El documento presenta directrices para escribir código limpio en JavaScript, basadas en los principios de ingeniería de software de Robert C. Martin. Se enfoca en la legibilidad, reutilización y refactorización del código, abarcando temas como el uso de nombres significativos para variables, la estructura de funciones y la importancia de evitar efectos secundarios. Estas pautas son recomendaciones y no reglas estrictas, destinadas a mejorar la calidad del código en el desarrollo de software.

Traducido por

ScribdTranslations
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
5 vistas46 páginas

Mejores Prácticas de Código Limpio en JavaScript

El documento presenta directrices para escribir código limpio en JavaScript, basadas en los principios de ingeniería de software de Robert C. Martin. Se enfoca en la legibilidad, reutilización y refactorización del código, abarcando temas como el uso de nombres significativos para variables, la estructura de funciones y la importancia de evitar efectos secundarios. Estas pautas son recomendaciones y no reglas estrictas, destinadas a mejorar la calidad del código en el desarrollo de software.

Traducido por

ScribdTranslations
Derechos de autor
© All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

código-limpio-javascript

Tabla de Contenidos
[Link]ón
[Link]
3. Funciones
[Link] y Estructuras de Datos
[Link]
6.SÓLIDO
[Link]
[Link]
[Link] de Errores
[Link]
[Link]
12. Traducción

Introducción

Figura 1: Imagen humorística de la estimación de la calidad del software como un conteo de cuánto
muchos expletivos gritas al leer código

Principios de ingeniería de software, del libro de Robert C. MartinCódigo Limpio,


adaptado para JavaScript. No es una guía de estilo. Es una guía para producir
legible, reutilizable y refactorizablesoftware en JavaScript.
No todos los principios aquí presentes deben ser seguidos estrictamente, y aún menos lo serán.
universalmente aceptados. Estas son directrices y nada más, pero son
códigos codificados a lo largo de muchos años de experiencia colectiva por los autores de Clean
Código.
Nuestro oficio de ingeniería de software tiene un poco más de 50 años, y todavía estamos
aprendiendo mucho. Cuando la arquitectura de software es tan antigua como la arquitectura misma, tal vez
entonces tendremos reglas más estrictas a seguir. Por ahora, que estas pautas sirvan como una
piedra de toque para evaluar la calidad del código JavaScript que tú y
tu equipo produce.

1
Una cosa más: saber esto no te hará inmediatamente un mejor software
desarrollador, y trabajar con ellos durante muchos años no significa que no cometerás
mistakes. Every piece of code starts as a first draft, like wet clay getting shaped
en su forma final. Finalmente, esculpimos las imperfecciones cuando lo revisamos
con nuestros compañeros. No te castigues por los borradores iniciales que necesitan mejora.
¡Golpea el código en su lugar!

Variables
Usa nombres de variables significativos y pronunciables

Malo
constyyyymmdstr=moment().format("YYYY/MM/DD");
Good:
constantecurrentDate=moment().format("YYYY/MM/DD");

volver arriba

Usa el mismo vocabulario para el mismo tipo de variable


Malo:
getUserInfo();
obtenerDatosDelCliente();
obtenerRegistroDeCliente();
Bueno
obtenerUsuario();
Volver arriba

Usa nombres buscables


Leeremos más código del que nunca escribiremos. Es importante que el código que
escríbalo es legible y buscable. Al no nombrar variables que terminan siendo
significativo para entender nuestro programa, lastimamos a nuestros lectores. Haz tu
nombres buscables. Herramientas [Link] ayudar a identificar lo no nombrado
constants.
Malo
// ¿Para qué diablos es 86400000?
setTimeout(blastOff,86400000);
Bueno:
//Decláralos como constantes nombradas en mayúsculas.
constMILLISECONDS_PER_DAY=60*60*24*1000;//86400000;

2
setTimeout(blastOff, MILISEGUNDOS_POR_DÍA);
volver arriba

Utiliza variables explicativas

Malo:
constaddress="One Infinite Loop, Cupertino 95014";
constcityZipCodeRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
guardarCodigoPostalCiudad(
[Link](cityZipCodeRegex)[1],
[Link](cityZipCodeRegex)[2]
);
Buen:
constaddress="One Infinite Loop, Cupertino 95014";
constantecityZipCodeRegex=/^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
constante[_,ciudad,códigoPostal]=direcció[Link](expresionRegularCiudadCódigoPostal)||[];
saveCityZipCode(city,zipCode);
volver arriba

Evitar el Mapeo Mental


El explícito es mejor que el implícito.

Malo:
constlocations=["Austin","New York","San Francisco"];
[Link](l=> {
hacerCosas();
hacerOtrasCosas();
// ...
// ...
// ...
// Espera, ¿para qué es `l` otra vez?
despachar(l);
});
Bueno:
constantelocations=["Austin","New York","San Francisco"];
[Link](location=> {
doStuff();
hacerOtrasCosas();
// ...
// ...
// ...

3
despachar(lugar);
});
volver arriba

No añadas contexto innecesario

If your class/object name tells you something, don’t repeat that in your variable
nombre.
Malo
constCar={
carMake:"Honda",
carModel:"Accord",
carColor:"Blue"
};

funciónpintarCoche(coche,color) {
[Link]=color;
}
Bueno:
constCar={
make:"Honda",
model:"Accord",
color:"Blue"
};

funciónpintarCoche(coche,color) {
[Link]=color;
}
⏎ volver arriba

Usa parámetros predeterminados en lugar de cortocircuitar o condicionales


Los parámetros predeterminados a menudo son más limpios que la interrupción corta. Ten en cuenta que si
los usas, tu función solo proporcionará valores predeterminados para indefinido
argumentos. Otros valores "falsy" como '', "", false, null, 0 y NaN, serán
no ser reemplazado por un valor predeterminado.

Malo:
funcióncreateMicrobrewery(name) {
constbreweryName=name||"Hipster Brew Co.";
// ...
}
Good:

4
funcióncrearMicrocervecería(nombre="Hipster Brew Co.") {
// ...
}
volver al principio

Functions
Argumentos de función (idealmente 2 o menos)
Limitar la cantidad de parámetros de función es increíblemente importante porque
hace que probar tu función sea más fácil. Tener más de tres lleva a una combina-
explosión de tutorial donde tienes que probar toneladas de casos diferentes con cada separado
argumento.
Uno o dos argumentos es el caso ideal, y tres deberían ser evitados si es posible.
Cualquier cosa más que eso debería ser consolidada. Normalmente, si tienes más de
dos argumentos entonces tu función está tratando de hacer demasiado. En casos donde es
no, la mayor parte del tiempo un objeto de nivel superior será suficiente como argumento.

Dado que JavaScript te permite crear objetos sobre la marcha, sin una gran cantidad de clases
plantilla, puedes usar un objeto si te ves necesitando mucho de
argumentos.
Para hacer obvias las propiedades que la función espera, puedes usar el
La sintaxis de desestructuración de ES2015/ES6. Esto tiene algunas ventajas:

1. Cuando alguien mira la firma de la función, es inmediatamente claro qué


se están utilizando propiedades.
2. Se puede utilizar para simular parámetros nombrados.
3. La desestructuración también clona los valores primitivos especificados del argumento
objeto pasado a la función. Esto puede ayudar a prevenir efectos secundarios. Nota:
los objetos y arreglos que son desestructurados del objeto argumento son
NO clonado.
Los linters pueden advertirte sobre propiedades no utilizadas, lo que sería imposible.
sin desestructuración.
Malo:
funcióncreateMenu(title,body,buttonText,cancellable) {
// ...
}

crearMenú("Foo","Bar","Baz",verdadero);
Bueno:
funcióncreateMenu({ title,body,buttonText,cancellable }) {
// ...
}

5
createMenu({
title:"Foo",
body:"Bar",
buttonText:"Baz",
cancellable:verdadero
});
Volver arriba

Las funciones deben hacer una cosa


Esta es, con mucho, la regla más importante en la ingeniería del software. Cuando las funciones
hacer más de una cosa, son más difíciles de componer, probar y razonar sobre ellas.
When you can isolate a function to just one action, it can be refactored easily
y tu código se verá mucho más limpio. Si no te llevas nada más de esto
guía además de esto, estarás por delante de muchos desarrolladores.

Malo:
funciónemailClients(clients) {
[Link](cliente=> {
constanteclientRecord=[Link](client);
si([Link]()) {
email(client);
}
});
}
Bueno:
funciónemailActiveClients(clients) {
[Link](esClienteActivo).forEach(correo);
}

funciónesClienteActivo(cliente) {
constclientRecord=[Link](client);
[Link]();
}
volver arriba

Los nombres de las funciones deberían decir lo que hacen


Malo
funciónañadirADate(fecha, mes) {
// ...
}

constantedate=nuevoDate();

6
Es difícil saber por el nombre de la función qué se agrega
agregarAFecha(fecha,1);
Bueno:
funciónagregarMesALaFecha(mes,fecha) {
// ...
}

constantedate=nuevoDate();
agregarMesAFecha(1,fecha);
volver arriba

Las funciones deben tener solo un nivel de abstracción


Cuando tienes más de un nivel de abstracción, tu función generalmente está haciendo
demasiado. Dividir funciones lleva a la reutilización y a pruebas más fáciles.
Malo:
funciónparseBetterJSAlternative(code) {
constREGEXES=[
// ...
];

conststatements=[Link](" ");
const tokens=[];
[Link](REGEX=> {
[Link](declaración=> {
// ...
});
});

constast=[];
[Link](token=> {
// léx...
});

[Link](nodo=> {
// analizar...
});
}
Bueno:
funciónparseBetterJSAlternative(code) {
consttokens=tokenizar(código);

7
constantesyntaxTree=parse(tokens);
[Link](nodo=> {
// analizar...
});
}

funcióntokenizar(código) {
constREGEXES=[
// ...
];

const statements=[Link](" ");


consttokens=[];
[Link](REGEX=> {
[Link](declaración)=> {
[Link](/* ... */);
});
});

regresartokens;
}

funciónanalizar(tokens) {
constantesyntaxTree=[];
[Link](token=> {
[Link](/* ... */);
});

devolversyntaxTree;
}
volver arriba

Eliminar código duplicado


Haz tu mejor esfuerzo absoluto para evitar código duplicado. El código duplicado es malo porque
significa que hay más de un lugar para alterar algo si necesitas cambiarlo
algo de lógica.

Imagina si tienes un restaurante y llevas un control de tu inventario: todo tu


tomates, cebollas, ajo, especias, etc. Si tienes múltiples listas que mantienes
esto, entonces todos tendrán que ser actualizados cuando sirvas un plato con tomates en
ellos. Si solo tienes una lista, ¡solo hay un lugar para actualizar!
A menudo tienes código duplicado porque tienes dos o más ligeramente diferentes.
ferent things, that share a lot in common, but their differences force you to have
dos o más funciones separadas que hacen muchas de las mismas cosas. Eliminar du-

8
el código plicate significa crear una abstracción que pueda manejar este conjunto de diferentes
cosas con solo una función/módulo/clase.
Ajustar la abstracción correctamente es crítico, por eso deberías seguir el SOLID
los principios expuestos en la sección de Clases. Las malas abstracciones pueden ser peores que
¡Código duplicado, así que ten cuidado! Dicho esto, si puedes hacer un buen ab-
¡Abstracción, hazlo! No te repitas, de lo contrario te encontrarás actualizando
múltiples lugares en cualquier momento que quieras cambiar una cosa.

Malo
funciónmostrarListaDesarrolladores(desarrolladores) {
[Link](desarrollador=> {
constexpectedSalary=[Link]();
constanteexperience=[Link]();
constantegithubLink=[Link]();
const data={
expectedSalary,
experiencia
githubLink
};

renderizar(datos);
});
}

funciónshowManagerList(managers) {
[Link](gerente=> {
constexpectedSalary=[Link]();
constexperience=[Link]();
constportfolio=[Link]();
constdata={
expectedSalary,
experiencia
portafolio
};

render(data);
});
}
Bueno:
function mostrarListaDeEmpleados(empleados) {
[Link](empleado=> {
constexpectedSalary=[Link]();
constexperience=[Link]();

9
constdata={
expectedSalary,
experiencia
};

interruptortipo
de empleado
caso"manager":
[Link]=[Link]();
romper;
case "developer":
[Link]=[Link]();
romper;
}

renderizar(datos);
});
}
volver al principio

Establecer objetos predeterminados con [Link]

Malo:
constmenuConfig={
title:null,
body:"Bar",
buttonText:null,
cancellable:verdadero
};

funcióncrearMenu(config) {
[Link]=[Link]||"Foo";
[Link]=[Link]||"Bar";
[Link]=[Link]||"Baz";
[Link]=
[Link]!==indefinido?[Link]: verdadero;
}

createMenu(menuConfig);
Bueno:
constmenuConfig={
title:"Order",
// User did not include 'body' key
buttonText:"Send",
cancellable:verdadero

10
};

funcióncreateMenu(config) {
dejarfinalConfig=[Link](
{
title:"Foo",
body:"Bar",
buttonText:"Baz",
cancellable:true
},
configuración
);
devolverfinalConfig
// config now equals: {title: "Order", body: "Bar", buttonText: "Send", cancellable: true}
// ...
}

createMenu(menuConfig);
volver arriba

No utilices banderas como parámetros de función

Las banderas le informan a su usuario que esta función hace más de una cosa. Funciones
debería hacer una cosa. Separa tus funciones si están siguiendo un código diferente
rutas basadas en un booleano.

Malo:
funcióncrearArchivo(nombre,temp) {
si(temp) {
[Link](`./temp/${nombre}`);
} else{
[Link](name);
}
}
Bueno:
function crearArchivo(nombre) {
[Link](nombre);
}

funcióncreateTempFile(nombre) {
createFile(`./temp/${name}`);
}
volver arriba

11
Evitarefectossecundarios(parte1)
Una función produce un efecto secundario si hace algo más que tomar un valor.
en y devolver otro valor o valores. Un efecto secundario podría ser escribir en un
archivo, modificando alguna variable global, o enviando accidentalmente todo tu dinero a un
extraño.
Ahora, a veces necesitas tener efectos secundarios en un programa. Como el
en el ejemplo anterior, es posible que necesites escribir en un archivo. Lo que quieres hacer es
centralizar dónde estás haciendo esto. No tener varias funciones y clases
that write to a particular file. Have one service that does it. One and only one.
El punto principal es evitar trampas comunes como compartir estado entre objetos.
sin ninguna estructura, utilizando tipos de datos mutables que pueden ser escritos por
cualquier cosa, y no centralizando dónde ocurren tus efectos secundarios. Si puedes hacer esto,
you will be happier than the vast majority of other programmers.
Malo
// Variable global referenciada por la siguiente función.
// Si tuviéramos otra función que usara este nombre, ahora sería un arreglo y podría romperse
dejarname="Ryan McDermott";

funciónsplitIntoFirstAndLastName() {
name=[Link](" ");
}

dividirEnNombreYApellido();

[Link](nombre);// ['Ryan', 'McDermott'];


Bueno:
funciónsplitIntoFirstAndLastName(name) {
[Link](" ");
}

constname="Ryan McDermott";
constnewName=splitIntoFirstAndLastName(name);

[Link](nombre);Ryan McDermott
[Link](nuevoNombre);// ['Ryan', 'McDermott'];
volver arriba

EvitarEfectosSecundarios(parte2)
En JavaScript, algunos valores son inmutables y otros son cambiables.
tipo (mutable). Los objetos y los arreglos son dos tipos de valores mutables, así que es
es importante manejarlos con cuidado cuando se pasan como parámetros a un

12
función. Una función de JavaScript puede cambiar las propiedades de un objeto o alterar el
el contenido de un array que podría causar fácilmente errores en otras partes.

Supongamos que hay una función que acepta un parámetro de array que representa una tienda.
carrito de compras. Si la función hace un cambio en ese arreglo del carrito de compras - al agregar
un artículo para comprar, por ejemplo - luego cualquier otra función que utilice ese mismo
el arreglo del carrito se verá afectado por esta adición. Eso puede ser genial, sin embargo,
también podría ser malo. Imaginemos una mala situación:
El usuario hace clic en el botón "Comprar" que llama a una función de compra que
genera una solicitud de red y envía el array de carrito al servidor. Debido a un
mala conexión de red, la función de compra tiene que seguir reintentando la solicitud.
Ahora, ¿qué pasa si mientras tanto el usuario hace clic accidentalmente en 'Agregar al carrito'?
¿un botón en un artículo que en realidad no quieren antes de que comience la solicitud de red?
Si eso sucede y la solicitud de la red comienza, entonces esa función de compra
enviará el artículo añadido accidentalmente porque se modificó el array de la cesta.

Una gran solución sería que la función addItemToCart siempre clone el


carrito, edítalo y devuelve el clon. Esto garantizaría que las funciones que son
seguir usando el viejo carrito de compras no se vería afectado por los cambios.
Dos advertencias que mencionar sobre este enfoque:

1. Puede haber casos en los que realmente desees modificar el objeto de entrada,
pero cuando adoptes esta práctica de programación, encontrarás que esos
los casos son bastante raros. ¡La mayoría de las cosas se pueden refactorizar para no tener efectos secundarios!

Clonar objetos grandes puede ser muy costoso en términos de rendimiento.


querido/a, esto no es un gran problema en la práctica porque haygrandes bibliotecaseso
permitir que este tipo de enfoque de programación sea rápido y no consuma tanta memoria
tan intensivo como sería para ti clonar manualmente objetos y arreglos.
Malo:
const addItemToCart=(cart,item)=> {
[Link]({ item,date:[Link]() });
};
Bueno:
constanteaddItemToCart=(cart,item)=> {
volver[...cart,{ item,date:[Link]() }];
};
Volver arriba

No escribas a funciones globales


Contaminar el espacio global es una mala práctica en JavaScript porque podrías entrar en conflicto con
otra biblioteca y el usuario de tu API no se daría cuenta hasta que obtenga
una excepción en producción. Pensemos en un ejemplo: ¿qué pasaría si quisieras

13
extender el método nativo Array de JavaScript para tener un método adiff que podría
muestra la diferencia entre dos arreglos? Podrías escribir tu nueva función
to [Link], but it could clash with another library that tried to
haz lo mismo. ¿Qué pasaría si esa otra biblioteca solo usara diffto para encontrar el
¿diferencia entre el primer y el último elemento de un arreglo? Por eso sería
sería mucho mejor simplemente usar clases de ES2015/ES6 y extender el arreglo
global.
Malo
[Link]=funcióndiferencia(comparisonArray) {
constantehash=new Set(comparisonArray);
devuelve [Link](elem=> ![Link](elem));
};
Bueno:
claseSuperArrayextiendeArray {
diff(comparisonArray) {
consthash=nuevoConjunto(comparisonArray);
devuelve [Link](elem=> ![Link](elem));
}
}
volver arriba

Prefiere la programación funcional sobre la programación imperativa

JavaScript no es un lenguaje funcional en el sentido en que lo es Haskell, pero tiene una


sabor funcional. Los lenguajes funcionales pueden ser más limpios y más fáciles de probar.
Favor de utilizar este estilo de programación cuando sea posible.

Malo:
constprogrammerOutput=[
{
name:"Uncle Bobby",
linesOfCode:500
},
{
name:"Suzie Q",
linesOfCode:1500
},
{
name:"Jimmy Gosling",
linesOfCode:150
},
{
name:"Gracie Hopper",

14
linesOfCode:1000
}
];

dejartotalOutput=0;

para(dejari=0;i<[Link];i++) {
totalOutput += programmerOutput[i].linesOfCode;
}
Bueno:
constprogrammerOutput=[
{
name:"Uncle Bobby",
linesOfCode:500
},
{
name:"Suzie Q",
linesOfCode:1500
},
{
name:"Jimmy Gosling",
linesOfCode:150
},
{
name:"Gracie Hopper",
linesOfCode:1000
}
];

consttotalOutput=[Link](
(totalLines,output)=> totalLines+[Link],
0
);
volver arriba

Encapsular condicionales
Malo
si([Link]==="fetching"&&isEmpty(listNode)) {
// ...
}
Bueno
funciónshouldShowSpinner(fsm,listNode) {

15
[Link] === "fetching" && estáVacío(nodoLista);
}

si(shouldShowSpinner(fsmInstance,listNodeInstance)) {
// ...
}
volver arriba

Evitar condicionales negativos


Malo
funciónisDOMNodeNotPresent(node) {
// ...
}

si(!isDOMNodeNotPresent(node)) {
// ...
}
Bueno:
funciónisDOMNodePresent(nodo) {
// ...
}

si(isDOMNodePresent(node)) {
// ...
}
volver arriba

Evitarcondicionales
Esto parece una tarea imposible. Al oír esto por primera vez, la mayoría de las personas dicen,
¿Cómo se supone que voy a hacer algo sin una declaración if?
que puedes usar el polimorfismo para lograr la misma tarea en muchos casos. El
La segunda pregunta suele ser: “bueno, eso es genial, pero ¿por qué querría hacer eso?”
La respuesta es un concepto previo de código limpio que aprendimos: una función debe sólo
haz una cosa. Cuando tengas clases y funciones que tienen declaraciones if, tú
estás diciendo a tu usuario que tu función hace más de una cosa. Recuerda,
solo haz una cosa.
Malo
claseAvión {
// ...
getCruisingAltitude() {
interruptor([Link]) {

16
caso"777":
devuelve [Link]()-[Link]();
casoFuerza Aérea Uno
devuelve [Link]();
caso"Cessna":
devuelve [Link]()-[Link]();
}
}
}
Bueno
claseAvión
// ...
}

claseBoeing777extiendeAvión
// ...
getCruisingAltitude() {
devuelve [Link]()-[Link]();
}
}

claseFuerza Aérea UnoextiendeAvión


// ...
getAltitudDeCrucero() {
devuelve [Link]();
}
}

claseCessnaextiendeAvión
// ...
getCruisingAltitude() {
devuelve [Link]()-[Link]();
}
}
de vuelta arriba

Evitar la verificación de tipos (parte 1)


JavaScript es sin tipo, lo que significa que tus funciones pueden aceptar cualquier tipo de argumento.
a veces te muerde esta libertad y se convierte en tentadora para
realiza la verificación de tipos en tus funciones. Hay muchas maneras de evitar tener que hacerlo.
esto. Lo primero a considerar son las APIs consistentes.
Malo:

17
funcióntravelToTexas(vehicle) {
si(vehículoinstancia deBicicleta)
vehí[Link]([Link],nuevoUbicación("texas");
} sino si(vehículoinstanceofCoche) {
vehí[Link]([Link],nuevoLocation("texas"));
}
}
Bueno:
funcióntravelToTexas(vehicle) {
vehí[Link]([Link],nuevoLocation("texas"));
}
Volver arriba

Evitar la verificación de tipos (parte 2)


Si estás trabajando con valores primitivos básicos como cadenas e enteros, y tú
no puedes usar polimorfismo pero aún sientes la necesidad de verificar tipos, deberías
considera usar TypeScript. Es una excelente alternativa al JavaScript normal,
ya que te proporciona tipado estático sobre la sintaxis estándar de JavaScript. El
el problema de verificar manualmente los tipos en JavaScript normal es que hacerlo bien
requiere tanto verborrea adicional que la falsa "seguridad de tipo" que obtienes no
compensar la legibilidad perdida. Mantén tu JavaScript limpio, escribe buenas pruebas.
y tener buenas revisiones de código. De lo contrario, haz todo eso pero con TypeScript
(lo cual, como dije, es una gran alternativa!).
Malo:
funcióncombinar(val1,val2) {
si(
(tipo deval1==="número"&&typeofval2==="número")||
(tipo deval1==="cadena"&&tipo deval2 === "cadena")
) {
devolverval1+val2;
}

lanzar nuevoError("Must be of type String or Number");


}
Bueno
funcióncombinar(val1,val2) {
volverval1+val2;
}
Volver arriba

18
No sobreoptimices
Los navegadores modernos hacen mucha optimización en segundo plano en tiempo de ejecución. Mucho de
veces, si estás optimizando entonces solo estás perdiendo tu [Link]
buenos recursospara ver dónde falta optimización. Apunta a aquellos en el
mientras tanto, hasta que sean arreglados si es que pueden serlo.

Malo:
// En navegadores antiguos, cada iteración con `[Link]` sin caché sería costosa
// debido a la recomputación de `[Link]`. En navegadores modernos, esto está optimizado.
para(dejari=0,longitud=[Link];i<longitud;i++) {
// ...
}
Bueno:
para(dejari=0;i<[Link];i++) {
// ...
}
volver arriba

Eliminar código muerto

El código muerto es tan malo como el código duplicado. No hay razón para mantenerlo en tu
código base. ¡Si no se está utilizando, deshazte de él! Todavía estará seguro en tu versión
historia si todavía la necesitas.
Malo:
funciónoldRequestModule(url) {
// ...
}

funciónnewRequestModule(url) {
// ...
}

constreq=newRequestModule;
inventoryTracker("apples",req,"[Link]");
Bueno:
funciónnewRequestModule(url) {
// ...
}

constreq=newRequestModule;
inventarioRastreador("manzanas",req,"[Link]");

19
regresar a arriba

Objetos y Estructuras de Datos


Utiliza getters y setters
Usar getters y setters para acceder a datos en objetos podría ser mejor que simplemente
buscando una propiedad en un objeto. "¿Por qué?" podrías preguntar. Bueno, aquí hay un
lista desorganizada de razones por las cuales:

• Cuando quieres hacer más allá de obtener una propiedad de un objeto, no lo haces.
tienes que buscar y cambiar cada accesorio en tu base de código.
• Hace que agregar validación sea simple al hacer un aset.
• Encapsula la representación interna.
• Fácil de añadir registro y manejo de errores al obtener y establecer.
• Puedes cargar perezosamente las propiedades de tu objeto, digamos obteniéndolo de un
servidor.
Malo
funciónmakeBankAccount() {
// ...

devolver{
balance:0
// ...
};
}

constaccount=makeBankAccount();
[Link]=100;
Bueno
funciónhacerCuentaBancaria() {
// este es privado
dejarbalance=0;

// un 'getter', hecho público a través del objeto devuelto a continuación


funcióngetBalance() {
regresarbalance
}

// un "setter", hecho público a través del objeto devuelto a continuación


funciónsetBalance(cantidad) {
// ... validar antes de actualizar el saldo
balance=amount;
}

20
devolver{
// ...
obtenerSaldo
setBalance
};
}

constaccount=makeBankAccount();
[Link](100);
volver arriba

Make objects have private members


Esto se puede lograr a través de cierres (para ES5 y versiones anteriores).

Malo:
constEmployee=función(nombre) {
[Link]=name;
};

[Link]=funcióngetName() {
devuelve [Link];
};

constemployee=nuevoEmployee("John Doe");
[Link](`Nombre del empleado: ${[Link]()}`);// Employee name: John Doe
[Link];
[Link](`Employee name: ${[Link]()}`);// Employee name: undefined
Bueno
function makeEmployee(name) {
regresar{
getNombre() {
regresarname;
}
};
}

constemployee=makeEmployee("John Doe");
[Link](`Nombre del empleado: ${[Link]()}`);// Employee name: John Doe
[Link];
[Link](`Nombre del empleado: ${[Link]()}`);// Employee name: John Doe
volver al principio

21
Clases
Prefiere las clases ES2015/ES6 sobre las funciones planas de ES5

Es muy difícil obtener herencia de clase, construcción y método legibles.


definiciones para clases clásicas ES5. Si necesitas herencia (y ten en cuenta
que quizás no), entonces prefiera las clases ES2015/ES6. Sin embargo, prefiera pequeñas
funciones sobre clases hasta que te encuentres necesitando algo más grande y complejo
objetos.
Malo
constAnimal=función(edad) {
si(!(esto es una instancia deAnimal)) {
lanzar nuevoError("Instantiate Animal with `new`");
}

[Link]=age;
};

[Link]=funciónmove() {};

constMammal=función(age,furColor) {
si(!(esto es una instancia deMamífero)) {
lanzar nuevoError("Instanciar Mamífero con 'new'");
}

[Link](esto,edad);
[Link]=furColor;
};

[Link] = [Link]([Link]);
[Link] = Mammal;
[Link]=funciónnacerVivo() {};

constHuman=función(age,furColor,languageSpoken) {
si(!(esto es una instancia deHumano)) {
lanzar nuevoError("Instanciar Humano con `new`");
}

Mamá.call(esto,edad,colorDePelo;
[Link]=languageSpoken;
};

[Link] = [Link]([Link]);
[Link]=Human;
[Link]=funciónhablar() {};

22
Bueno:
claseAnimal {
constructor(edad) {
[Link]=age;
}

move() {
/* ... */
}
}

claseMamíferoextiendeAnimal {
constructor(edad,colorDePelo) {
súper(age);
[Link]=furColor;
}

nacimientoVivo() {
/* ... */
}
}

claseHumanoextiendeMammal {
constructor(edad,colorPelaje,idiomaHablado) {
super(edad,colorDePelo);
[Link]=languageSpoken;
}

hablar() {
/* ... */
}
}
volver arriba

Usa encadenamiento de métodos

Este patrón es muy útil en JavaScript y lo ves en muchas bibliotecas.


como jQuery y Lodash. Permite que tu código sea expresivo y menos verboso.
Por esa razón, digo, utiliza la cadena de métodos y observa lo limpio que está tu
el código será. En las funciones de tu clase, simplemente devuelve esto al final de cada
función, y puedes encadenar más métodos de clase a ella.
Malo:
claseCoche {
constructor(marca, modelo, color) {

23
[Link]=make;
[Link]=model;
[Link]=color;
}

setMake(make) {
[Link]=make;
}

setModel(model) {
[Link]=model;
}

setColor(color) {
[Link]=color;
}

guardar() {
[Link]([Link]);
}
}

constcar=nuevoCar("Ford","F-150","red");
[Link]("rosa");
[Link]();
Bueno:
claseCoche {
constructor(make,model,color) {
[Link]=make;
[Link]=model;
[Link]=color;
}

setMake(make) {
[Link]=make;
// NOTADevolviendo esto para encadenar
devuelve esto;
}

setModel(model) {
[Link]=model;
// NOTADevolviendo esto para encadenar
devuelve esto;
}

24
setColor(color) {
[Link]=color;
// NOTADevolviendo esto para encadenar
devuelve esto;
}

guardar() {
[Link]([Link],[Link],[Link]);
// NOTADevolviendo esto para encadenar
devuelve esto;
}
}

const car=nuevoCoche("Ford","F-150","rojo").cambiarColor("rosa").guardar();
volver arriba

Prefiere la composición sobre la herencia

Como se declaró famosamente enPatrones de diseñopor la Banda de los Cuatro, deberías preferir
composición sobre herencia donde puedas. Hay muchas buenas razones para
utiliza la herencia y muchas buenas razones para usar la composición. El punto principal para
esta máxima es que si tu mente va instintivamente hacia la herencia, intenta pensar
si la composición pudiera modelar mejor tu problema. En algunos casos puede.
Entonces podrías estar preguntándote: “¿cuándo debería usar la herencia?” Depende de
tu problema actual, pero esta es una lista decente de cuándo la herencia tiene más sentido
sentido que composición:
Tu herencia representa una relación de "es-un" y no una relación de "tiene-un".
relación (Humano->Animal vs. Usuario->DetallesUsuario).
2. Puedes reutilizar el código de las clases base (los humanos pueden moverse como todos los ani-
mals).
3. Quieres hacer cambios globales en las clases derivadas al cambiar una base
clase. (Cambia el gasto calórico de todos los animales cuando se mueven).
Malo
claseEmpleado {
constructor(nombre, correo) {
[Link]=name;
[Link]=email;
}

// ...
}

// Bad because Employees "have" tax data. EmployeeTaxData is not a type of Employee

25
claseDatosImpositivosDelEmpleadoextiendeEmployee {
constructor(ssn,salario) {
super();
[Link]=ssn;
[Link]=salary;
}

// ...
}
Bueno:
claseEmployeeTaxData {
constructor(ssn,sueldo) {
[Link]=ssn;
[Link]=salary;
}

// ...
}

claseEmpleado {
constructor(nombre, correo) {
[Link]=name;
[Link]=email;
}

setTaxData(ssn,salario) {
[Link]=nuevoEmployeeTaxData(ssn,salary);
}
// ...
}
volver arriba

SÓLIDO
Principio de Responsabilidad Única (SRP)
Como se indica en Clean Code, “no debería haber más de una razón para un
clase para cambiar”. Es tentador llenar una clase con mucha funcionalidad,
como cuando solo puedes llevar una maleta en tu vuelo. El problema con esto es
que tu clase no será conceptualmente cohesiva y le dará muchas razones para
cambio. Minimizar la cantidad de veces que necesitas cambiar de clase es importante.
Es importante porque si hay demasiada funcionalidad en una clase y modificas un
parte de ello, puede ser difícil entender cómo eso afectará a otros dependientes
módulos en tu base de código.

26
Malo:
claseUserSettings {
constructor(usuario) {
[Link]=user;
}

changeSettings(settings) {
si([Link]()) {
// ...
}
}

verifyCredentials() {
// ...
}
}
Bueno:
claseUserAuth {
constructor(usuario) {
[Link]=user;
}

verificarCredenciales() {
// ...
}
}

claseUserSettings {
constructor(usuario) {
[Link]=user;
[Link]=nuevoUserAuth(usuario);
}

changeSettings(settings) {
si([Link]()) {
// ...
}
}
}
volver arriba

27
Principio Abierto/Cerrado (OCP)

Como declaró Bertrand Meyer, “entidades de software (clases, módulos, funciones,


etc.) debería estar abierto a la extensión, pero cerrado a la modificación.” ¿Qué significa
¿Qué significa eso? Este principio básicamente establece que debes permitir a los usuarios
agregar nuevas funcionalidades sin cambiar el código existente.
Malo:
claseAjaxAdapterextiendeAdaptador {
constructor() {
súper();
[Link]="ajaxAdapter";
}
}

claseAdaptador de NodoextiendeAdaptador {
constructor() {
súper();
[Link]="nodeAdapter";
}
}

claseHttpRequester {
constructor(adapter) {
[Link]=adaptador;
}

fetch(url) {
si([Link]=== "ajaxAdapter") {
devolvermakeAjaxCall(url).then(response=> {
// transformar la respuesta y devolver
});
} sino si([Link]==="nodeAdapter") {
devolverhacerLlamadaHttp(url).entonces(respuesta)=> {
// transformar respuesta y retornar
});
}
}
}

funciónmakeAjaxCall(url) {
// solicitar y devolver promesa
}

funciónhacerLlamadaHttp(url) {
// solicitud y devolución de promesa

28
}
Bueno:
claseAdaptadorAjaxextiendeAdaptador {
constructor() {
super();
[Link]="ajaxAdapter";
}

solicitar(url) {
// solicitar y devolver promesa
}
}

claseAdaptadorDeNodose extiendeAdaptador {
constructor() {
super();
[Link]="nodeAdapter";
}

solicitud(url) {
// request and return promise
}
}

claseHttpRequester {
constructor(adapter) {
[Link]=adapter;
}

fetch(url) {
return [Link](url).then(response=> {
// transformar respuesta y devolver
});
}
}
back to top

Principio de Sustitución de Liskov (LSP)


Este es un término aterrador para un concepto muy simple. Se define formalmente como "Si S es
un subtipo de T, entonces los objetos de tipo T pueden ser reemplazados por objetos de tipo S
(es decir, los objetos de tipo S pueden sustituir a los objetos de tipo T) sin alterar ningún
de las propiedades deseables de ese programa (correctitud, tarea realizada, etc.).
Esa es una definición aún más aterradora.

29
La mejor explicación para esto es si tienes una clase padre y una clase hijo,
entonces la clase base y la clase hija se pueden usar de manera intercambiable sin obtener
resultados incorrectos. Esto podría seguir siendo confuso, así que echemos un vistazo a la
ejemplo clásico de cuadrado-rectángulo. Matemáticamente, un cuadrado es un rectángulo, pero
si lo modelas usando la relación 'es un' a través de la herencia, rápidamente te adentras en
problema.
Malo
claseRectángulo {
constructor() {
[Link]=0;
[Link]=0;
}

setColor(color) {
// ...
}

renderizar(area) {
// ...
}

setWidth(width) {
[Link]=width;
}

setHeight(height) {
[Link]=height;
}

obtenerÁrea() {
devuelve [Link]*[Link];
}
}

claseCuadradoextiendeRectángulo {
setWidth(width) {
[Link]=width;
[Link]=anchura;
}

setHeight(altura) {
[Link]=height;
[Link]=height;
}
}

30
funciónrenderizarRectángulosGrandes(rectángulos) {
[Link](rectangle=> {
rectá[Link](4);
[Link](5);
constanteárea=rectá[Link]Área();// MALO: Devuelve 25 para Cuadrado. Debería ser 20.
rectá[Link](area);
});
}

constrectangles=[nuevoRectángulo()nuevoRectángulo()nuevoCuadrado()];
renderizarRectángulosGrandes(rectángulos);
Bueno:
claseForma {
setColor(color) {
// ...
}

renderizar(area) {
// ...
}
}

claseRectánguloextiendeForma {
constructor(ancho,alto) {
súper();
[Link]=width;
[Link]=height;
}

obtenerÁrea() {
devuelve [Link]*[Link];
}
}

claseCuadradoextiendeForma {
constructor(length) {
súper();
[Link]=length;
}

obtenerÁrea() {
devuelve [Link]*[Link];
}
}

31
funciónrenderLargeShapes(shapes) {
[Link](forma=> {
const área=[Link]Área();
[Link](area);
});
}

constanteshapes=[nuevoRectángulo(4,5)nuevoRectángulo(4,5)nuevoCuadrado(5)];
dibujarGrandesFormas(formas);
volver arriba

Principio de Segregación de Interfaces (ISP)

JavaScript no tiene interfaces, por lo que este principio no se aplica tan estrictamente como
otros. Sin embargo, es importante y relevante incluso con la falta de tipos de JavaScript.
sistema.
El ISP afirma que "los clientes no deberían verse obligados a depender de interfaces que
no utilizan. Las interfaces son contratos implícitos en JavaScript debido al pato
escribiendo.
Un buen ejemplo para observar que demuestra este principio en JavaScript es para
classes that require large settings objects. Not requiring clients to setup huge
las cantidades de opciones son beneficiosas, porque la mayor parte del tiempo no necesitarán todas
de la configuración. Hacerlas opcionales ayuda a prevenir tener una “interfaz engorrosa”.

Malo:
claseDOMTraverser {
constructor(configuración) {
[Link]=configuraciones;
[Link]();
}

configuración() {
[Link]=[Link];
[Link]();
}

traverse() {
// ...
}
}

const$=nuevoDOMTraverser({
rootNode:[Link]("body"),

32
animationModule() {}// La mayoría de las veces, no necesitaremos animar al atravesar.
// ...
});
Bueno:
claseDOMTraverser {
constructor(configuración) {
[Link]=settings;
[Link]=[Link];
[Link]();
}

configuración() {
[Link]=[Link];
[Link]();
}

setupOptions() {
if ([Link]) {
// ...
}
}

traverse() {
// ...
}
}

const$=nuevoDOMTraverser({
rootNode:[Link]("body"),
options:{
animationModule() {}
}
});
volver arriba

Principio de Inversión de Dependencias (DIP)

Este principio establece dos cosas esenciales:


1. Los módulos de alto nivel no deberían depender de los módulos de bajo nivel. Ambos deberían
depender de abstracciones.
2. Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de
abstracciones.
Esto puede ser difícil de entender al principio, pero si has trabajado con AngularJS,

33
Has visto una implementación de este principio en forma de Inyección de Dependencias.
La inversión de dependencias (DI). Si bien no son conceptos idénticos, la DIP mantiene altos módulos de nivel

de conocer los detalles de sus módulos de bajo nivel y configurarlos. Puede


accomplish this through DI. A huge benefit of this is that it reduces the coupling
entre módulos. El acoplamiento es un patrón de desarrollo muy malo porque lo hace
tu código es difícil de refactorizar.

Como se mencionó anteriormente, JavaScript no tiene interfaces, por lo que las abstracciones que
depende de contratos implícitos. Es decir, los métodos y la prop-
propiedades que un objeto/clase expone a otro objeto/clase. En el ejemplo a continuación,
el contrato implícito es que cualquier módulo de Solicitud para un TrackingInventario
tiene unamétododeartículodepetición.

Malo:
claseInventoryRequester {
constructor() {
esto.REQ_METHODS=["HTTP"];
}

requestItem(item) {
// ...
}
}

claseInventarioSeguimiento {
constructor(elementos) {
[Link]=items;

MALO: Hemos creado una dependencia de una implementación de solicitud específica.


Solo deberíamos hacer que requestItems dependa de un método de solicitud: `request`
[Link]=nuevoSolicitante de Inventario();
}

requestItems() {
[Link](item=> {
[Link](item);
});
}
}

constinventoryTracker=nuevoInventoryTracker(["apples","bananas"]);
[Link]();
Bueno:
claseInventoryTracker {
constructor(elementos, solicitante) {

34
[Link]=items;
[Link]=requester;
}

requestItems() {
[Link](item=> {
[Link](item);
});
}
}

claseInventoryRequesterV1 {
constructor() {
esto.REQ_METHODS=["HTTP"];
}

solicitarElemento(elemento) {
// ...
}
}

claseInventoryRequesterV2 {
constructor() {
esto.REQ_METHODS=["WS"];
}

requestItem(item) {
// ...
}
}

Al construir nuestras dependencias externamente e inyectarlas, podemos fácilmente


// sustituir nuestro módulo de solicitud por uno nuevo y elegante que utiliza WebSockets.
constinventoryTracker=nuevoInventarioRastreador(
["apples","bananas"],
nuevoInventoryRequesterV2()
);
[Link]ículos();
volver arriba

Prueba
Las pruebas son más importantes que el envío. Si no tienes pruebas o son inadecuadas
cantidad, entonces cada vez que envíes código no estarás seguro de que no lo rompiste.
cualquier cosa. Decidir qué constituye una cantidad adecuada depende de tu equipo,

35
but having 100% coverage (all statements and branches) is how you achieve very
alta confianza y tranquilidad para el desarrollador. Esto significa que además de
tener un gran marco de pruebas, también necesitas usar unbuena herramienta de cobertura.
No hay excusa para no escribir pruebas. Haymucha buena prueba de marco JS
funcionaasí que encuentra uno que tu equipo prefiera. Cuando encuentres uno que funcione para
tu equipo, entonces intenta siempre escribir pruebas para cada nueva función/módulo que
introducir. Si tu método preferido es el Desarrollo Guiado por Pruebas (TDD), eso
es genial, pero el punto principal es asegurarse de que está alcanzando su cobertura
metas antes de lanzar cualquier función o refactorizar una existente.

Concepto único por prueba


Malo:
importar assert de "assert";

describir("MomentJS",()=> {
it("maneja los límites de fecha",()=> {
dejardate;

date=nuevoMomentJS("1/1/2015");
fecha.añadirDías(30);
[Link]("1/31/2015", fecha);

date=nuevoMomentJS("1/2/2016");
fecha.añadirDías(28);
[Link]("02/29/2016", fecha);

date=nuevoMomentJS("1/2/2015");
[Link](28);
[Link]("03/01/2015", fecha);
});
});
Bueno:
importar afirmación de "afirmación";

describe("MomentJS",()=> {
it("maneja meses de 30 días",()=> {
constantedate=nuevoMomentJS("1/1/2015");
[Link]ías(30);
[Link]("1/31/2015", fecha);
});

it("maneja año bisiesto",()=> {


constdate=nuevoMomentJS("2/1/2016");

36
[Link]ías(28);
[Link]("02/29/2016", date);
});

maneja el año no bisiesto=> {


constdate=nuevoMomentJS("2/1/2015");
[Link](28);
[Link]("03/01/2015", fecha);
});
});
back to top

Concurrencia
Usa Promesas, no callbacks
Las devoluciones de llamada no son limpias y causan excesivas cantidades de anidamiento. Con
ES2015/ES6, las Promesas son un tipo global incorporado. ¡Úsalas!

Malo:
importar { obtener } de "solicitud";
importar { escribirArchivo } de "fs";

obtener(
"[Link]
(requestErr,response,body)=> {
si(errorDeSolicitud) {
[Link](requestErr);
} sino{
writeFile("[Link]",body,writeErr=> {
si(escribirErr) {
[Link](writeErr);
} otro{
[Link]("Archivo escrito");
}
});
}
}
);
Bueno:
importar { obtener } de "request-promise";
importar { escribirArchivo } de "fs-extra";

get("[Link]
.entonces(cuerpo=> {

37
devolverescribirArchivo("[Link]",cuerpo);
})
.entonces(()=> {
[Link]("File written");
})
.catch(err=> {
[Link](err);
});
_volver arriba_

Async/Await son incluso más limpios que Promesas


Las promesas son una alternativa muy limpia a los callbacks, pero ES2017/ES8 trae async
y esperar que ofrezcan una solución aún más limpia. Todo lo que necesitas es una función que
está prefijado en anasynckeyword, y luego puedes escribir tu lógica impera-
de manera tiva sin una cadena de funciones. Usa esto si puedes aprovechar
¡Características de ES2017/ES8 hoy!

Malo:
importar { obtener } de "request-promise";
importar { writeFile } de "fs-extra";

get("[Link]
.entonces(cuerpo=> {
devolverescribirArchivo("[Link]",cuerpo);
})
.entonces(()=> {
[Link]("Archivo escrito");
})
.catch(err=> {
[Link](err);
});
Bueno:
importar { obtener } de "request-promise";
importar { escribirArchivo } de "fs-extra";

función asíncronagetCleanCodeArticle() {
intenta{
constantebody=esperarobtener(
[Link]
);
esperarescribirArchivo("artí[Link]",cuerpo);
[Link]("Archivo escrito");
} atrapar(err) {

38
[Link](err);
}
}

getCleanCodeArticle()
volver arriba

Manejo de errores
¡Los errores lanzados son algo bueno! Significan que el tiempo de ejecución ha identificado con éxito...
notificado cuando algo en tu programa ha salido mal y te está dejando
saber deteniendo la ejecución de la función en la pila actual, finalizando el proceso
(en Node), y notificándote en la consola con un rastro de pila.

No ignores los errores atrapados

No hacer nada con un error atrapado no te da la capacidad de arreglarlo nunca.


reacciona al error mencionado. Registrar el error en la consola ([Link]) no es mucho
mejor ya que a menudo puede perderse en un mar de cosas impresas en la consola. Si
si envuelves cualquier fragmento de código en un try/catch significa que crees que puede ocurrir un error
ahí y por lo tanto deberías tener un plan, o crear un camino de código, para cuando esto
ocurre.
Malo:
intentar{
functionThatMightThrow();
} atrapar(error) {
[Link](error);
}
Bueno:
intenta{
functionQuePodriaArrojar();
} atrapar(error) {
// Una opción (más ruidosa que [Link]):
[Link](error);
// Otra opción:
notifyUserOfError(error);
// Otra opción:
reportErrorToService(error);
// ¡O haz los tres!
}

No ignores las promesas rechazadas


Por la misma razón, no deberías ignorar los errores capturados de try/catch.

39
Malo:
obtenerDatos()
.entonces(data=> {
functionThatMightThrow(data);
})
.atrapar(error=> {
[Link](error);
});
Bueno:
obtenerDatos()
.entonces(datos=> {
functionThatMightThrow(data);
})
.catch(error=> {
// Una opción (más ruidosa que [Link]):
[Link](error);
// Otra opción:
notifyUserOfError(error);
// Otra opción:
reportErrorToService(error);
// ¡O haz las tres cosas!
});
↑ volver arriba

Formato
Formatting is subjective. Like many rules herein, there is no hard and fast rule
que debes seguir. El punto principal es NO DISCUTAS sobre el formato.
Haymontones de herramientaspara automatizar esto. ¡Usa uno! Es una pérdida de tiempo y
money for engineers to argue over formatting.
Para cosas que no caen bajo la esfera del formato automático (indenta-
tion, tabulaciones vs. espacios, comillas dobles vs. comillas simples, etc.) mira aquí para algunas pautas.

Usa una capitalización coherente


JavaScript no tiene tipo, por lo que el uso de mayúsculas te dice mucho sobre tus variables.
functions, etc. These rules are subjective, so your team can choose whatever
Ellos quieren. El punto es, no importa lo que elijan, solo sean consistentes.
Malo
constanteDAYS_IN_WEEK=7;
constantedaysInMonth=30;

40
constsongs=["Back In Black","Stairway to Heaven","Hey Jude"];
constanteArtists=["ACDC","Led Zeppelin","The Beatles"];

funciónborrarBaseDeDatos() {}
funciónrestaurar_base_de_datos() {}

claseanimal {}
claseAlpaca {}
Bueno:
constanteDAYS_IN_WEEK=7;
constDAYS_IN_MONTH=30;

constSONGS=["Back In Black","Stairway to Heaven","Hey Jude"];


constanteARTISTS=["ACDC","Led Zeppelin","The Beatles"];

function borrarBaseDeDatos() {}
funciónrestaurarBaseDeDatos() {}

claseAnimal {}
claseAlpaca {}
volver arriba

Los llamadores y los llamados de funciones deben estar cerca


Si una función llama a otra, mantén esas funciones verticalmente cerca en el código fuente
archivo. Idealmente, mantén el llamador justo encima del llamado. Tendemos a leer el código desde
de arriba hacia abajo, como un periódico. Debido a esto, haz que tu código lo lea así.
manera.
Malo:
clasePerformanceReview {
constructor(empleado) {
[Link]=employee;
}

buscarCompaneros() {
[Link]([Link],"compañeros";
}

lookupManager() {
[Link]([Link],"gerente");
}

getPeerReviews() {

41
constpeers=[Link]();
// ...
}

perfReview() {
[Link]();
[Link]();
[Link]ón();
}

obtenerRevisionDelGerente() {
constantemanager=[Link]();
}

obtenerAutoevaluación() {
// ...
}
}

constantereview=nuevoRevisiónDeDesempeño(empleado);
revisió[Link]ónDeRendimiento();
Bueno:
clasePerformanceReview {
constructor(empleado) {
[Link]=employee;
}

evaluaciónDeDesempeño() {
[Link]ñasDeCompañeros();
[Link]ónDelGerente();
[Link]ón();
}

obtenerRevisionesDeCompañeros() {
constpeers=[Link]();
// ...
}

lookupPeers() {
[Link]([Link],"compañeros");
}

obtenerRevisiónDelGerente() {
constmanager=[Link]();
}

42
lookupManager() {
[Link]([Link],"gerente");
}

getSelfReview() {
// ...
}
}

constantereview=nuevoPerformanceReview(employee);
reseñ[Link]ónDeRendimiento();
volver arriba

Comentarios
Solo comenta cosas que tengan complejidad en la lógica empresarial.

Los comentarios son una disculpa, no un requisito. Buen código, sobre todo documentos.
sí mismo.
Malo:
funciónhashIt(data) {
El hash
dejarhash=0;

Longitud de la cadena
constlongitud=[Link];

// Iterar a través de cada carácter en los datos


para(dejari=0;i<longitud;i++) {
// Obtener código de carácter.
constchar=[Link](i);
Hacer el hash
hash=(hash<<5)-hash+char;
// Convertir a entero de 32 bits
hash&=hash;
}
}
Bueno:
funciónhashIt(data) {
dejarhash=0;
constlength=[Link];

para(dejari=0;i<length;i++) {

43
constantechar=[Link](i);
hash=(hash<<5)-hash+char;

// Convertir a entero de 32 bits


hash&=hash;
}
}
volver al principio

No dejes código comentado en tu base de código


El control de versiones existe por una razón. Deja el código antiguo en tu historial.

Malo:
hacerCosas();
// hacerOtrasCosas();
// hacerAlgunCosaMas();
// doSoMuchStuff();
Bueno:
hacerCosas();
volver arriba

No tener comentarios de diario


¡Recuerda, utiliza control de versiones! No hay necesidad de código muerto, comentado
código, y especialmente comentarios en el diario. ¡Usa git log para obtener el historial!

Malo:
/**
* 2016-12-20: Se eliminaron los monads, no los entendía (RM)
2016-10-01: Mejorado utilizando monadas especiales (JP)
2016-02-03: Se eliminó la comprobación de tipo (LI)
* 2015-03-14: Se añadió combinar con verificación de tipo (JR)
*/
funcióncombinar(a,b) {
regresara+b;
}
Bueno:
funcióncombinar(a,b) {
devolvera+b;
}
volver arriba

44
Evitalosmarcadoresdeposición
Generalmente solo añaden ruido. Deja las funciones y los nombres de las variables junto con
la indentación y el formato adecuados dan la estructura visual a tu código.
Malo:
////////////////////////////////////////////////////////////////////////////////
// Instanciación del Modelo de Alcance
////////////////////////////////////////////////////////////////////////////////
$[Link]={
menu:"foo",
nav:"bar"
};

////////////////////////////////////////////////////////////////////////////////
// Action setup
////////////////////////////////////////////////////////////////////////////////
const actions=función() {
// ...
};
Bueno:
$[Link]={
menu:"foo",
nav:"bar"
};

constactions=función() {
// ...
};
↑ volver arriba

Traducción
Esto también está disponible en otros idiomas:

• Armenio:hanumanum/clean-code-javascript/

• BanglaInsomniacSabbir/código-limpio-javascript/

• Portugués brasileño:fesnt/código-limpio-javascript

• Chino simplificado
– alivebao/código-limpio-js

45
– beginor/código-limpio-javascript

• Chino tradicional:AllJointTW/clean-code-javascript

• Francés:eugene-augier/code-limpio-javascript-fr

• Alemán:marcbruederlin/clean-code-javascript

• Indonesia:andirkh/código-limpio-javascript/

• Italiano:frappacchio/código-limpio-javascript/

• Japonésmitsuruog/código-limpio-javascript/

• Coreano:qkraudghgh/clean-code-javascript-ko

• Pulir:greg-dev/codigo-limpio-javascript-pl

• Ruso
– BoryaMogila/clean-code-javascript-ru/
– maksugr/código-limpio-javascript

• Español:tureey/clean-code-javascript

• Spanish:andersontr15/código-limpio-javascript

• Serbiodoskovicmilos/código-limpio-javascript/

• Turco:bsonmez/código-limpio-javascript

• Ucraniano:mindfr1k/clean-code-javascript-ua

• Vietnamese:hienvd/código-limpio-javascript/
volver arriba

46

También podría gustarte