{"id":13553149,"url":"https://github.com/devictoribero/clean-code-javascript","last_synced_at":"2025-10-06T22:31:42.766Z","repository":{"id":41356876,"uuid":"168818168","full_name":"devictoribero/clean-code-javascript","owner":"devictoribero","description":":bathtub: Clean Code concepts adapted for JavaScript","archived":false,"fork":true,"pushed_at":"2024-03-02T17:25:06.000Z","size":534,"stargazers_count":2132,"open_issues_count":1,"forks_count":322,"subscribers_count":50,"default_branch":"master","last_synced_at":"2025-01-25T08:32:18.686Z","etag":null,"topics":["cleancode","development","frontend","goodpractices","javascript","js","solid"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"ryanmcdermott/clean-code-javascript","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devictoribero.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-02-02T10:00:19.000Z","updated_at":"2025-01-22T14:29:03.000Z","dependencies_parsed_at":"2023-01-23T10:45:10.439Z","dependency_job_id":null,"html_url":"https://github.com/devictoribero/clean-code-javascript","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/devictoribero/clean-code-javascript","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devictoribero%2Fclean-code-javascript","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devictoribero%2Fclean-code-javascript/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devictoribero%2Fclean-code-javascript/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devictoribero%2Fclean-code-javascript/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devictoribero","download_url":"https://codeload.github.com/devictoribero/clean-code-javascript/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devictoribero%2Fclean-code-javascript/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278690974,"owners_count":26029171,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-06T02:00:05.630Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cleancode","development","frontend","goodpractices","javascript","js","solid"],"created_at":"2024-08-01T12:02:18.482Z","updated_at":"2025-10-06T22:31:42.503Z","avatar_url":"https://github.com/devictoribero.png","language":"JavaScript","readme":"# ✨ Mejora como ingeniero de software\nSi quieres **mejorar como ingeniero de software** de seguro que te interesa **[mi nuevo canal de youtube](https://youtube.com/@devictoribero)!**\n\n# clean-code-javascript\n\nEste contenido no es original. está traducido de [aquí](https://github.com/ryanmcdermott/clean-code-javascript).\nTampoco significa que todo lo que esté en este repositorio lo comparta. De hecho,\nhay unas cosas en las que no estoy de acuerdo.\n\n## Contenido\n\n1. [Introducción](#introduction)\n2. [Variables](#variables)\n3. [Funciones](#functions)\n4. [Objetos y estructuras de datos](#objects-and-data-structures)\n5. [Clases](#classes)\n6. [SOLID](#solid)\n7. [Testing](#testing)\n8. [Concurrencia](#concurrency)\n9. [Manejo de errores](#error-handling)\n10. [Formato](#formatting)\n11. [Comentarios](#comments)\n12. [Traducciones](#translation)\n\n## Introducción\n\n![Humorous image of software quality estimation as a count of how many expletives\nyou shout when reading code](http://www.osnews.com/images/comics/wtfm.jpg)\n\nPrincipios de Ingeniería de Software por Robert C. Martin en el libro\n[_Código Limpio_](https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882),\nadaptado al Javascript. Esto no es una guía de estilos. Esto es una guía\npara crear código [legible, reutilizable y de fácil modificación](https://github.com/ryanmcdermott/3rs-of-software-architecture)\nen Javascript.\n\nNo se deben seguir estrictamente todos los principios e incluso aún menos,\ncomo tampoco, éstos van a ser dogmas internacionales ni verdades absolutas.\nLos conceptos explicados no son más una compilación de buenas prácticas que\nhan sido agrupadas a lo largo de muchos años de experiencia colectiva por\nlos autores de _Código Limpio_.\n\nNuestro oficio de ingeniería de software tiene poco más de 50 años y todavía\nestamos aprendiendo mucho. Quizás cuando la arquitectura del software sea tan\nantigua como la arquitectura tradicional en sí misma, tengamos reglas más\ndefinidas que seguir. Por ahora, dejemos que estas pautas sirvan de faro para\nevaluar la calidad del código JavaScript que tu equipo y tu producís.\n\nUna cosa más: Debes saber que estos principios, consejos o como quieras llamarlo,\nno te hará instantáneamente un mejor desarrollador de software y que trabajar con\nellos durante muchos años tampoco significa que no vayas a hacer más errores.\nCada trozo de código comienza como un primer borrador, igual que un jarrón precioso\nempieza con un trozo de arcilla feo y húmedo el cual vamos moldeando hasta conseguir el\nresultado final. Finalmente, limamos las imperfecciones cuando lo revisamos con\nnuestros compañeros a base de iteraciones. No te castigues por la posible mejora\nde los primeros borradores. En vez de eso, ¡Vence al código!\n\n## Variables\n\n### Utiliza nombres con sentido y de fácil pronunciación para las variables\n\n**🙅‍ Mal:**\n\n```javascript\nconst yyyymmdstr = moment().format(\"YYYY/MM/DD\");\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst fechaActual = moment().format(\"YYYY/MM/DD\");\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Utiliza el mismo tipo de vocabulario para el mismo tipo de variables\n\n**🙅‍ Mal:**\n\n```javascript\nconseguirInformacionUsuario();\nconseguirDatosCliente();\nconseguirRegistroCliente();\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconseguirUsuario();\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Utiliza nombres que puedan ser buscados\n\nLeeremos más código del que jamás escribiremos. Es importante que el código que\nescribamos sea legible y se puede buscar en él. Al no crear variables que sean\nsignificativas para entender nuestro código... Estamos entorpeciendo a sus lectores.\nHaz tus variables sean fáciles de entender y buscar. Herramientas como\n[buddy.js](https://github.com/danielstjules/buddy.js) y\n[ESLint](https://github.com/eslint/eslint/blob/660e0918933e6e7fede26bc675a0763a6b357c94/docs/rules/no-magic-numbers.md)\npueden ayudan a identificar constantes no nombradas.\n\n**🙅‍ Mal:**\n\n```javascript\n// Para que cojones sirve 86400000?\nsetTimeout(blastOff, 86400000);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\n// Declaralas como constantes nombradas\nconst MILISEGUNDOS_POR_DIA = 86400000;\n\nsetTimeout(blastOff, MILISEGUNDOS_POR_DIA);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Utiliza variables explicativas\n\n**🙅‍ Mal:**\n\n```javascript\nconst direccion = \"Calle Mallorca, Barcelona 95014\";\nconst expresionRegularCodigoPostalCiudad = /^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$/;\nguardarCP(\n  direccion.match(expresionRegularCodigoPostalCiudad)[1],\n  direccion.match(expresionRegularCodigoPostalCiudad)[2]\n);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst direccion = \"One Infinite Loop, Cupertino 95014\";\nconst expresionRegularCodigoPostalCiudad = /^[^,\\\\]+[,\\\\\\s]+(.+?)\\s*(\\d{5})?$/;\nconst [, ciudad, codigoPostal] =\n  direccion.match(expresionRegularCodigoPostalCiudad) || [];\nguardarCP(ciudad, codigoPostal);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita relaciones mentales\n\nExplícito es mejor que implícito.\n\n**🙅‍ Mal:**\n\n```javascript\nconst ciudades = [\"Barcelona\", \"Madrid\", \"Sitges\"];\nciudades.forEach(l =\u003e {\n  hacerAlgo();\n  hacerAlgoMas();\n  // ...\n  // ...\n  // ...\n  // Espera, para que era `l`?\n  dispatch(l);\n});\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst ciudades = [\"Barcelona\", \"Madrid\", \"Sitges\"];\nciudades.forEach(direccion =\u003e {\n  hacerAlgo();\n  hacerAlgoMas();\n  // ...\n  // ...\n  // ...\n  dispatch(direccion);\n});\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No añadas contexto innecesario\n\nSi tu nombre de clase/objeto ya dice algo, no lo repitas en tu nombre de variable\n\n**🙅‍ Mal:**\n\n```javascript\nconst Coche = {\n  marcaCoche: \"Honda\",\n  modeloCoche: \"Accord\",\n  colorCoche: \"Azul\"\n};\n\nfunction pintarCoche(coche) {\n  coche.colorCoche = \"Rojo\";\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst Coche = {\n  marca: \"Honda\",\n  modelo: \"Accord\",\n  color: \"Azul\"\n};\n\nfunction pintarCoche(coche) {\n  coche.color = \"Rojo\";\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Utiliza argumentos por defecto en vez de circuitos cortos o condicionales\n\nLos argumentos por defecto suelen ser más limpios que los cortocircuitos. Ten\nen cuenta que si los usas, solo se asignara ese valor por defectos cuando el\nvalor del parámetro sea `undefined`. Otros valores \"falsos\" como `''`, `\" \"`,\n`false`,`null`, `0` y `NaN`, no serán reemplazado por un valor predeterminado\npues se consideran valores como tal.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction crearMicroCerveceria(nombre) {\n  const nombreMicroCerveceria = nombre || \"Hipster Brew Co.\";\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction crearMicroCerveceria(nombre = \"Hipster Brew Co.\") {\n  // ...\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Funciones\n\n### Argumentos de una función (idealmente 2 o menos)\n\nLimitar la cantidad de parámetros de una función es increíblemente importante\nporque hacen que _las pruebas_ de tu función sean más sencillas. Tener más de tres\nlleva a una locura combinatoria donde tienes que probar toneladas de casos\ndiferentes con cada argumento por separado.\n\nEl caso ideal es usar uno o dos argumentos, tres... deben evitarse si es posible.\nCualquier número superior a eso, debería ser agrupado. Por lo general, si tienes\nmás de dos argumentos, tu función debe de estar haciendo demasiadas cosas. En los\ncasos donde no es así, la mayoría de las veces un objeto de nivel superior será\nsuficiente como un argumento _parámetro objeto_.\n\nYa que Javascript te permite crear objetos al vuelo sin tener que hacer mucho\ncódigo repetitivo en una clase, puedes usar un objeto en caso de estar necesitando\nmuchos parámetros.\n\nPara indicar que propiedades espera la función, puedes usar las funcionalidades\nde desestructuración que nos ofrece ES2015/ES6. Éstas tienen algunas ventajas:\n\n1. Cuando alguien mira la firma de la función, sabe inmediatamente que propiedades\n   están siendo usadas\n2. La desetructuración también clona los valores primitivos especificados del `objeto argumento`\n   pasado a la función. Esto puede servir de ayuda para prevenir efectos adversos.\n   _Nota: Los objetos y los arrays que son desestructurados del objeto parámetro NO son clonados._\n3. Las herramientas lintera o _linterns_ pueden avisarte de qué propiedades del\n   objeto parámetro no están en uso. _Cosa que es imposile sin desestructuración._\n\n**🙅‍ Mal:**\n\n```javascript\nfunction crearMenu(titulo, cuerpo, textoDelBoton, cancelable) {\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction crearMenu({ titulo, cuerpo, textoDelBoton, cancelable }) {\n  // ...\n}\n\ncrearMenu({\n  titulo: \"Foo\",\n  cuerpo: \"Bar\",\n  textoDelBoton: \"Baz\",\n  cancelable: true\n});\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Las funciones deberían hacer una cosa\n\nDe lejos, es la regla más importante en la ingeniería del software. Cuando\nlas funciones hacen más de una cosa, son difíciles de componer y _testear_\nentre otras cosas. Si isolamos las funciones por acciones, éstas pueden ser\nmodificadas y mantenidas con mayor facilidad y tu código será mucho más limpio.\nDe toda esta guía... si has de aprender algo, que sea esto. Ya estarás mmuy\npor delante de muchos desarrolladores de software.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction enviarCorreoAClientes(clientes) {\n  clientes.forEach(cliente =\u003e {\n    const historicoDelCliente = baseDatos.buscar(cliente);\n    if (historicoDelCliente.estaActivo()) {\n      enviarEmail(cliente);\n    }\n  });\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction enviarCorreoClientesActivos(clientes) {\n  clientes.filter(esClienteActive).forEach(enviarEmail);\n}\n\nfunction esClienteActivo(cliente) {\n  const historicoDelCliente = baseDatos.buscar(cliente);\n  return historicoDelCliente.estaActivo();\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Los nombres de las funciones deberían decir lo que hacen\n\n**🙅‍ Mal:**\n\n```javascript\nfunction añadirAFecha(fecha, mes) {\n  // ...\n}\n\nconst fecha = new Date();\n\n// Es difícil saber que se le está añadiendo a la fecha en este caso\nañadirAFecha(fecha, 1);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction añadirMesAFecha(mes, fecha) {\n  // ...\n}\n\nconst fecha = new Date();\nañadirMesAFecha(1, fecha);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Las funciones deberían ser únicamente de un nivel de abstracción\n\nCuando tienes más de un nivel de abstracción, tu función normalmente está\nhacicendo demasiado. Separarla en funciones más pequeñas te ayudará a poder\nreutilizar código y te facilitará el _testear_ éstas.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction analizarMejorAlternativaJavascript(codigo) {\n  const EXPRESIONES_REGULARES = [\n    // ...\n  ];\n\n  const declaraciones = codigo.split(\" \");\n  const tokens = [];\n  EXPRESIONES_REGULARES.forEach(EXPRESION_REGULAR =\u003e {\n    declaraciones.forEach(declaracion =\u003e {\n      // ...\n    });\n  });\n\n  const ast = [];\n  tokens.forEach(token =\u003e {\n    // lex...\n  });\n\n  ast.forEach(nodo =\u003e {\n    // parse...\n  });\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction analizarMejorAlternativaJavascript(codigo) {\n  const tokens = tokenize(codigo);\n  const ast = lexer(tokens);\n  ast.forEach(nodo =\u003e {\n    // parse...\n  });\n}\n\nfunction tokenize(codigo) {\n  const EXPRESIONES_REGULARES = [\n    // ...\n  ];\n\n  const declaraciones = codigo.split(\" \");\n  const tokens = [];\n  EXPRESIONES_REGULARES.forEach(EXPRESION_REGULAR =\u003e {\n    declaraciones.forEach(declaracion =\u003e {\n      tokens.push(/* ... */);\n    });\n  });\n\n  return tokens;\n}\n\nfunction lexer(tokens) {\n  const ast = [];\n  tokens.forEach(token =\u003e {\n    ast.push(/* ... */);\n  });\n\n  return ast;\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Elimina código duplicado\n\nHaz todo lo posible para evitar duplicación de código. Duplicar código es\nmalo porque significa que para editar un comportamiento... tendrás que modificarlko\nen más de un sitio. ¿Y no queremos trabajar de más, verdad?\n\nComo caso práctico: Imagina que tienes un restaurante. Llevas el registro del\ninventario: Todos tus tomates, cebollas, ajos, especies, etc... Si tuvieras más\nde una lista que tuvieras que actualizar cada vez que sirves un tomate o usas\nuna especie, sería más fácil de cometer errores, además de todo el tiempo perdido.\nSi solo tienes una, la posibilidad de cometer una error se reduce a ésta!\n\nA menudo tienes código duplicado porque tienes dos o más cosas ligeramente\ndiferentes, que tienen mucho en común, pero sus diferencias te obligan a tener\nese código de más. Borrar la duplicación de código significa crear una abstracción\nque pueda manejar este conjunto de cosas diferentes con una sola función/módulo/clase.\n\nHacer que la abstracción sea correcta es fundamental y a veces bastante complejo.\nEs por eso que debes seguir los Principios `SOLID` establecidos en la sección _Clases_.\nLas malas abstracciones pueden ser peores que el código duplicado. ¡Así que ten cuidado!\nDicho esto, si se puede hacer una buena abstracción, ¡Házla! Evita repetirte\nporque de lo contrario, como hemos comentado anteriormente, te verás editando\nen más de un lugar para modificar un comportamiento.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction mostrarListaDesarrolladores(desarrolladores) {\n  desarrolladores.forEach(desarrollador =\u003e {\n    const salarioEsperado = desarrollador.calcularSalarioEsperado();\n    const experiencia = desarrollador.conseguirExperiencia();\n    const enlaceGithub = desarrollador.conseguirEnlaceGithub();\n    const datos = {\n      salarioEsperado,\n      experiencia,\n      enlaceGithub\n    };\n\n    render(datos);\n  });\n}\n\nfunction mostrarListaJefes(jefes) {\n  jefes.forEach(jefe =\u003e {\n    const salarioEsperado = desarrollador.calcularSalarioEsperado();\n    const experiencia = desarrollador.conseguirExperiencia();\n    const experienciaLaboral = jefe.conseguirProyectosMBA();\n    const data = {\n      salarioEsperado,\n      experiencia,\n      experienciaLaboral\n    };\n\n    render(data);\n  });\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction mostrarListaEmpleados(empleados) {\n  empleados.forEach(empleado =\u003e {\n    const salarioEsperado = empleado.calcularSalarioEsperado();\n    const experiencia = empleado.conseguirExperiencia();\n\n    const datos = {\n      salarioEsperado,\n      experiencia\n    };\n\n    switch (empleado.tipo) {\n      case \"jefe\":\n        datos.portafolio = empleado.conseguirProyectosMBA();\n        break;\n      case \"desarrollador\":\n        datos.enlaceGithub = empleado.conseguirEnlaceGithub();\n        break;\n    }\n\n    render(datos);\n  });\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Asigna objetos por defecto con Object.assign\n\n**🙅‍ Mal:**\n\n```javascript\nconst configuracionMenu = {\n  titulo: null,\n  contenido: \"Bar\",\n  textoBoton: null,\n  cancelable: true\n};\n\nfunction crearMenu(config) {\n  config.titulo = config.titulo || \"Foo\";\n  config.contenido = config.contenido || \"Bar\";\n  config.textoBoton = config.textoBoton || \"Baz\";\n  config.cancelable =\n    config.cancelable !== undefined ? config.cancelable : true;\n}\n\ncrearMenu(configuracionMenu);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst configuracionMenu = {\n  titulo: \"Order\",\n  // El usuario no incluyó la clave 'contenido'\n  textoBoton: \"Send\",\n  cancelable: true\n};\n\nfunction crearMenu(configuracion) {\n  configuracion = Object.assign(\n    {\n      titulo: \"Foo\",\n      contenido: \"Bar\",\n      textoBoton: \"Baz\",\n      cancelable: true\n    },\n    configuracion\n  );\n\n  // configuracion ahora es igual a: {titulo: \"Order\", contenido: \"Bar\", textoBoton: \"Send\", cancelable: true}\n  // ...\n}\n\ncrearMenu(configuracionMenu);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No utilices banderas o flags\n\nLas banderas o _flags_ te indican de que esa función hace más de una cosa. Ya\nque como vamos repitiendo, nuestras funciones solo deberían hacer una cosa, separa\nesa lógica que es diferenciada por la bandera o _flag_ en una nueva función.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction crearFichero(nombre, temporal) {\n  if (temporal) {\n    fs.create(`./temporal/${nombre}`);\n  } else {\n    fs.create(nombre);\n  }\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction crearFichero(nombre) {\n  fs.create(nombre);\n}\n\nfunction crearFicheroTemporal(nombre) {\n  crearFichero(`./temporal/${nombre}`);\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita los efectos secundarios (parte 1)\n\nUna función produce un efecto adverso/colateral si hace otra cosa que recibir\nun parámetro de entrada y retornar otro valor o valores. Un efecto adverso puede\nser escribir un fichero, modificar una variable global o accidentalmente enviar\ntodo tu dinero a un desconocido.\n\nAhora bien, a veces necesitamos efectos adversos en nuestros programas. Como\nen el ejemplo anterior, quizás necesitas escribir en un fichero. Así pues, lo que\nqueremos es centralizar donde se hace esta acción. No queremos que esta lógica\nla tengamos que escribir en cada una de las funciones o clases que van a utilizarla.\nPara eso, la encapsularemos en un servicio que haga eso. Sólo eso.\n\nEl objetivo principal es evitar errores comunes como compartir el estado entre objetos\nsin ninguna estructura, usando tipos de datos mutables que pueden ser escritos por cualquier cosa\ny no centralizar donde se producen sus efectos secundarios. Si puedes hacer esto, serás\nmás feliz que la gran mayoría de otros programadores.\n\n**🙅‍ Mal:**\n\n```javascript\n// Variable Global referenciada por la siguiente función\n// Si tuvieramos otra función que usara ese nombre, podría ser un array y lo estaríamos rompiendo\n// If we had another function that used this name, now it'd be an array and it could break it.\nlet nombre = 'Ryan McDermott';\n\nfunction separarEnNombreYApellido() {\n  nombre = nombre.split(' ');\n}\n\nsepararEnNombreYApellido();\n\nconsole.log(nombre); // ['Ryan', 'McDermott'];\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction separarEnNombreYApellido(nombre) {\n  return nombre.split(' ');\n}\n\nconst nombre = 'Ryan McDermott';\nconst nuevoNombre = separarEnNombreYApellido(nombre);\n\nconsole.log(nombre); // 'Ryan McDermott';\nconsole.log(nuevoNombre); // ['Ryan', 'McDermott'];\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita los efectos secundarios (parte 2)\n\nEn JavaScript, los primitivos se pasan por valor y los objetos / arrays se pasan por\nreferencia. En el caso de objetos y arrays, si su función hace un cambio como por ejemplo,\nañadiendo un elemento al array que representa el carrito de la compra, entonces cualquier\notra función que use ese array `carrito` se verá afectada por esta modificación.\nEso puede ser genial, sin embargo, también puede ser malo. Imaginemos una mala situación:\n\nEl usuario hace clic en el botón \"Comprar\", que llama a una función de \"compra\" que\ngenera una petición de red y envía el array `carrito` al servidor. Dada una mala\nconexión de red, la función `comprar` tiene que seguir reintentando la solicitud.\nAhora, ¿Qué pasa si mientras tanto el usuario hace clic accidentalmente en el botón\n_\"Agregar al carrito\"_ en un elemento que realmente no quiere, antes de que comience\nla solicitud de red? Si esto sucede y la solicitud de red comienza, entonces esa\nfunción de compra enviará el artículo agregado accidentalmente porque tiene una\nreferencia al objeto dado que la función `añadirObjetoAlCarrito` modificó el `carrito`\nagregando un elemento que no deseado.\n\nUna buena solución para `añadirObjetoAlCarrito` podría ser clonar el `carrito`, editarlo,\ny retornar la copia. Esto nos asegura que ninguna otra función tiene referencia al\nobjeto con los campos modificados. Así pues, ninguna otra función se verá afectada\npor nuestros cambios.\n\nDos advertencias que mencionar para este enfoque:\n\n1. Puede haber casos en los que realmente desee modificar el objeto de entrada,\n   pero cuando adopte esta práctica de programación encontrará que esos casos son\n   bastante raros ¡La mayoría de las cosas se pueden refactorizar para que no tengan\n   efectos secundarios!\n\n2. Clonar objetos grandes puede ser muy costosa en términos de rendimiento.\n   Por suerte, en la práctica, esto no es un gran problema dado que hay\n   [buenas librerías](https://facebook.github.io/immutable-js/) que permiten este\n   tipo de enfoque de programación. Es rápido y no requiere tanta memoria como te\n   costaría a ti clonar manualmente los arrays y los objetos.\n\n**🙅‍ Mal:**\n\n```javascript\nconst añadirObjetoAlCarrito = (carrito, objeto) =\u003e {\n  carrito.push({ objeto, fecha: Date.now() });\n};\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst añadirObjetoAlCarrito = (carrito, objeto) =\u003e {\n  return [...carrito, { objeto, fecha: Date.now() }];\n};\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No escribas en variables globales\n\nLa contaminación global es una mala práctica en JavaScript porque podría chocar\ncon otra librería y usuarios usuarios de tu API no serían conscientes de ello hasta\nque tuviesen un error en producción. Pensemos en un ejemplo: ¿Qué pasaría si quisieras\nextender los arrays de Javascript para tener un método `diff` que pudiera enseñar la\ndiferencia entre dos arrays? Podrías escribir tu nueva función en el `Array.prototype`,\npero podría chocar con otra librería que intentó hacer lo mismo. ¿Qué pasa si esa otra\nlibrería estaba usando `diff` para encontrar la diferencia entre los elementos primero\ny último de una matriz? Tendríamos problemas... Por eso, sería mucho mejor usar las\nclases ES2015 / ES6 y simplemente extender el `Array` global.\n\n**🙅‍ Mal:**\n\n```javascript\nArray.prototype.diff = function diff(matrizDeComparación) {\n  const hash = new Set(matrizDeComparación);\n  return this.filter(elemento =\u003e !hash.has(elemento));\n};\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass SuperArray extends Array {\n  diff(matrizDeComparación) {\n    const hash = new Set(matrizDeComparación);\n    return this.filter(elemento =\u003e !hash.has(elemento));\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Da prioridad a la programación funcional en vez de la programación imperativa\n\nJavascript no es un lenguage funcional en la misma medida que lo es Haskell, pero\ntiene aspectos que lo favorecen. Los lenguages funcionales pueden ser más fáciles\ny limpios de _testear_. Favorece este estilo de programación siempre que puedas.\n\n**🙅‍ Mal:**\n\n```javascript\nconst datosSalidaProgramadores = [\n  {\n    nombre: \"Uncle Bobby\",\n    liniasDeCodigo: 500\n  },\n  {\n    nombre: \"Suzie Q\",\n    liniasDeCodigo: 1500\n  },\n  {\n    nombre: \"Jimmy Gosling\",\n    liniasDeCodigo: 150\n  },\n  {\n    nombre: \"Gracie Hopper\",\n    liniasDeCodigo: 1000\n  }\n];\n\nlet salidaFinal = 0;\n\nfor (let i = 0; i \u003c datosSalidaProgramadores.length; i++) {\n  salidaFinal += datosSalidaProgramadores[i].liniasDeCodigo;\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst datosSalidaProgramadores = [\n  {\n    nombre: \"Uncle Bobby\",\n    liniasDeCodigo: 500\n  },\n  {\n    nombre: \"Suzie Q\",\n    liniasDeCodigo: 1500\n  },\n  {\n    nombre: \"Jimmy Gosling\",\n    liniasDeCodigo: 150\n  },\n  {\n    nombre: \"Gracie Hopper\",\n    liniasDeCodigo: 1000\n  }\n];\n\nconst salidaFinal = datosSalidaProgramadores\n  .map(salida =\u003e salida.linesOfCode)\n  .reduce((totalLinias, linias) =\u003e totalLinias + linias);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Encapsula los condicionales\n\n**🙅‍ Mal:**\n\n```javascript\nif (fsm.state === \"cogiendoDatos\" \u0026\u0026 estaVacio(listaNodos)) {\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction deberiaMostrarSpinner(fsm, listaNodos) {\n  return fsm.state === \"cogiendoDatos\" \u0026\u0026 estaVacio(listaNodos);\n}\n\nif (deberiaMostrarSpinner(fsmInstance, listNodeInstance)) {\n  // ...\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita condicionales negativos\n\n**🙅‍ Mal:**\n\n```javascript\nfunction noEstaElNodoPresente(node) {\n  // ...\n}\n\nif (!noEstaElNodoPresente(node)) {\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction estaElNodoPresente(node) {\n  // ...\n}\n\nif (estaElNodoPresente(node)) {\n  // ...\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita condicionales\n\nEsto parece una tarea imposible. Al escuchar esto por primera vez, la mayoría de\nla gente dice _\"¿como voy a ser capaz de hacer cosas sin un `if`\"?_ La respuesta a eso,\nes que deberías usar polimorfismo para conserguir lo mismo en la gran mayoría de los\ncasos. La segunda pregunta que normalmente la gente hace es, _¿Bueno está bien pero\npara que voy a querer hacerlo?_ La respuesta es uno de los conceptos previos que\nhemos visto de _Código limpio_: Una función debería hacer únicamente una cosa.\nCuando tienes una función o clase que posee un `if`, le estás diciendo al usuario\nque tu función está haciendo más de una cosa. Recuerda, tan sólo una cosa.\n\n**🙅‍ Mal:**\n\n```javascript\nclass Avion {\n  // ...\n  obtenerAlturaDeVuelo() {\n    switch (this.tipo) {\n      case \"777\":\n        return this.cogerAlturaMaxima() - this.conseguirNumeroPasajeros();\n      case \"Air Force One\":\n        return this.cogerAlturaMaxima();\n      case \"Cessna\":\n        return this.cogerAlturaMaxima() - this.getFuelExpenditure();\n    }\n  }\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass Avion {\n  // ...\n}\n\nclass Boeing777 extends Avion {\n  // ...\n  obtenerAlturaDeVuelo() {\n    return this.cogerAlturaMaxima() - this.conseguirNumeroPasajeros();\n  }\n}\n\nclass AirForceOne extends Avion {\n  // ...\n  obtenerAlturaDeVuelo() {\n    return this.cogerAlturaMaxima();\n  }\n}\n\nclass Cessna extends Avion {\n  // ...\n  obtenerAlturaDeVuelo() {\n    return this.cogerAlturaMaxima() - this.getFuelExpenditure();\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita el control de tipos (parte 1)\n\nJavascript es un lenguaje no tipado. Esto significa que las funciones pueden recibir\ncualquier tipo como argumento. A veces, nos aprovechamos de eso... y es por eso, que\nse vuelve muy tentador el controlar los tipos de los argumentos de la función. Hay\nalgunas soluciones para evitar esto. La primera, son APIs consistentes. Por API se\nentiende de que manera nos comunicamos con ese módulo/función.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction viajarATexas(vehiculo) {\n  if (vehiculo instanceof Bicicleta) {\n    vehiculo.pedalear(this.ubicacionActual, new Localizacion(\"texas\"));\n  } else if (vehiculo instanceof Car) {\n    vehiculo.conducir(this.ubicacionActual, new Localizacion(\"texas\"));\n  }\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction viajarATexas(vehiculo) {\n  vehiculo.mover(this.ubicacionActual, new Localizacion(\"texas\"));\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita control de tipos (parte 2)\n\nSi estás trabajando con los tipos primitivos como son las `cadenas` o `enteros`,\ny no puedes usar polimorfismo pero aún ves la necesidad del control de tipos,\ndeberías considerar `Typescript`. Es una excelente alternativa al `Javascript`\nconvencional que nos aporta control de tipos de manera estática entre otras\nmuchas cosas. El problema de controlar manualmente el tipado en `Javascript` es\nque para hacerlo bien, necesitamos añadir mucho código a bajo nivel que afecta a\nla legibilidad del código. Mantén tu código `Javascript` limpio, escribe _tests_\ny intenta tener revisiones de código. Si no, intenta cubrir el máximo de cosas con\n`Typescript` que como ya hemos dicho, es una muy buena alternativa.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction combina(valor1, valor2) {\n  if (\n    (typeof valor1 === \"number\" \u0026\u0026 typeof valor2 === \"number\") ||\n    (typeof valor1 === \"string\" \u0026\u0026 typeof valor2 === \"string\")\n  ) {\n    return valor1 + valor2;\n  }\n\n  throw new Error(\"Debería ser una cadena o número\");\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction combina(valor1, valor2) {\n  return valor1 + valor2;\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No optimizes al máximo\n\nLos navegadores modernos hacen mucha optimización por detrás en tiempo de ejecución.\nMuchas veces, al interntar optimizar tu código... estás perdiendo el tiempo.\n[Esta es una buena documentación](https://github.com/petkaantonov/bluebird/wiki/Optimization-killers)\npara ver donde falta optimización. Pon el foco en éstas hasta que estén arregladas/hechas\nsi es que se pueden.\n\n**🙅‍ Mal:**\n\n```javascript\n// En los navegadores antiguos, cada iteración en la que `list.length` no esté cacheada\n// podría ser costosa por el recálculo de este valor. En los modernos, ya está optimizado\nfor (let i = 0, tamaño = lista.length; i \u003c tamaño; i++) {\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfor (let i = 0; i \u003c lista.length; i++) {\n  // ...\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Borra código inútil\n\nEl código inútil es tan malo como la duplicación. No hay razón alguna para\nmantenerlo en tu código. Si no está siendo usado por nadie, ¡Bórralo! Siempre\nestará disponible en sistema de versiones para el caso que lo necesites.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction antiguoModuloDePeticiones(url) {\n  // ...\n}\n\nfunction nuevoModuloDePeticiones(url) {\n  // ...\n}\n\nconst peticion = nuevoModuloDePeticiones;\ncalculadorDeInventario(\"manzanas\", peticion, \"www.inventory-awesome.io\");\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction nuevoModuloDePeticiones(url) {\n  // ...\n}\n\nconst peticion = nuevoModuloDePeticiones;\ncalculadorDeInventario(\"manzanas\", peticion, \"www.inventory-awesome.io\");\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Objectos y estructuras de datos\n\n### Utiliza setters y getters\n\nUsar `getters` y `setters` para acceder a la información del objeto está mejor\nque simplemente accediendo a esa propiedad del objeto. ¿Por qué?\n\n- Si quieres modificar una propiedad de un objeto, no tienes que ir mirando\n  si existe o no existe para seguir mirando a niveles más profundos del objeto.\n- Encapsula la representación interna (en caso de tener que comprobar cosas, mirar en varios sitios...)\n- Es sencillo añadir mensajes y manejos de error cuando hacemos `get` y `set`\n- Te permite poder hacer lazy load en caso de que los datos se recojan de una Base de Datos (bbdd)\n\n**🙅‍ Mal:**\n\n```javascript\nfunction crearCuentaBancaria() {\n  // ...\n\n  return {\n    balance: 0\n    // ...\n  };\n}\n\nconst cuenta = crearCuentaBancaria();\ncuenta.balance = 100;\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction crearCuentaBancaria() {\n  // Esta es privada\n  let balance = 0;\n\n  // Un \"getter\", hecho público a través del objeto que retornamos abajo\n  function cogerBalance() {\n    return balance;\n  }\n\n  // Un \"setter\", hecho público a través del objeto que retornamos abajo\n  function introducirBalance(cantidad) {\n    // ... validamos antes de hcaer un balance\n    balance = cantidad;\n  }\n\n  return {\n    // ...\n    cogerBalance,\n    introducirBalance\n  };\n}\n\nconst cuenta = crearCuentaBancaria();\ncuenta.introducirBalance(100);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Hacer que los objetos tengan atributos/métodos privados\n\nEsto se puede hacer mediante `clojures` _(de ES5 en adelante)_.\n\n**🙅‍ Mal:**\n\n```javascript\nconst Empleado = function(nombre) {\n  this.nombre = nombre;\n};\n\nEmpleado.prototype.cogerNombre = function cogerNombre() {\n  return this.nombre;\n};\n\nconst empleado = new Empleado(\"John Doe\");\nconsole.log(`Nombre del empleado: ${empleado.cogerNombre()}`); // Nombre del empleado: John Doe\ndelete empleado.nombre;\nconsole.log(`Nombre del empleado: ${empleado.cogerNombre()}`); // Nombre del empleado: undefined\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction crearEmpleado(name) {\n  return {\n    cogerNombre() {\n      return name;\n    }\n  };\n}\n\nconst empleado = crearEmpleado(\"John Doe\");\nconsole.log(`Nombre del empleado: ${empleado.cogerNombre()}`); // Nombre del empleado: John Doe\ndelete empleado.name;\nconsole.log(`Nombre del empleado: ${empleado.cogerNombre()}`); // Nombre del empleado: John Doe\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Clases\n\n### Prioriza las classes de ES2015/ES6 antes que las funciones planas de ES50\n\nEs muy complicado de conseguir que un código sea entendible y fácil de leer con\nherencia de clases, construcción y metodos típicos de clases con las clases de ES5.\nSi necesitas herencia (y de seguro, que no la necesitas) entonces, dale prioridad a\nlas clases ES2015/ES6. De todas las maneras, deberías preferir pequeñas funciones\nantes que ponerte a hacer clases. Solo cuando tengas un código largo o cuando veas\nnecesaria la implementación de clases, añádelas.\n\n**🙅‍ Mal:**\n\n```javascript\nconst Animal = function(edad) {\n  if (!(this instanceof Animal)) {\n    throw new Error(\"Inicializa Animal con `new`\");\n  }\n\n  this.edad = edad;\n};\n\nAnimal.prototype.mover = function mover() {};\n\nconst Mamifero = function(edad, furColor) {\n  if (!(this instanceof Mamifero)) {\n    throw new Error(\"Inicializa Mamifero con `new`\");\n  }\n\n  Animal.call(this, edad);\n  this.furColor = furColor;\n};\n\nMamifero.prototype = Object.create(Animal.prototype);\nMamifero.prototype.constructor = Mamifero;\nMamifero.prototype.aniversario = function aniversario() {};\n\nconst Humano = function(edad, furColor, idioma) {\n  if (!(this instanceof Humano)) {\n    throw new Error(\"Inicializa Humano con `new`\");\n  }\n\n  Mamifero.call(this, edad, furColor);\n  this.idioma = idioma;\n};\n\nHumano.prototype = Object.create(Mamifero.prototype);\nHumano.prototype.constructor = Humano;\nHumano.prototype.hablar = function hablar() {};\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass Animal {\n  constructor(edad) {\n    this.edad = edad;\n  }\n\n  mover() {\n    /* ... */\n  }\n}\n\nclass Mamifero extends Animal {\n  constructor(edad, furColor) {\n    super(edad);\n    this.furColor = furColor;\n  }\n\n  aniversario() {\n    /* ... */\n  }\n}\n\nclass Human extends Mamifero {\n  constructor(edad, furColor, idioma) {\n    super(edad, furColor);\n    this.idioma = idioma;\n  }\n\n  hablar() {\n    /* ... */\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Utiliza el anidación de funciones\n\nEste es un patrón útil en Javascript y verás que muchas librerías como jQuery\no Lodash lo usan. Permite que tu código sea expresivo y menos verboso.\nPor esa razón, utiliza las funciones anidadas y date cuenta de que tan limpio estará\ntu código. En las funciones de tu clase, sencillamente retorna `this` al final de\ncada una y con eso, tienes todo lo necesario pra poder anidar las llamadas a las\nfunciones.\n\n**🙅‍ Mal:**\n\n```javascript\nclass Coche {\n  constructor(marca, modelo, color) {\n    this.marca = marca;\n    this.modelo = modelo;\n    this.color = color;\n  }\n\n  introducirMarca(marca) {\n    this.marca = marca;\n  }\n\n  introducirModelo(modelo) {\n    this.modelo = modelo;\n  }\n\n  introducirColor(color) {\n    this.color = color;\n  }\n\n  guardar() {\n    console.log(this.marca, this.modelo, this.color);\n  }\n}\n\nconst coche = new Coche(\"Ford\", \"F-150\", \"rojo\");\ncoche.introducirColor(\"rosa\");\ncoche.guardar();\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass Coche {\n  constructor(marca, modelo, color) {\n    this.marca = marca;\n    this.modelo = modelo;\n    this.color = color;\n  }\n\n  introducirMarca(marca) {\n    this.marca = marca;\n    // NOTE: Retornamos this para poder anidas funciones\n    return this;\n  }\n\n  introducirModelo(modelo) {\n    this.modelo = modelo;\n    // NOTE: Retornamos this para poder anidas funciones\n    return this;\n  }\n\n  introducirColor(color) {\n    this.color = color;\n    // NOTE: Retornamos this para poder anidas funciones\n    return this;\n  }\n\n  guardar() {\n    console.log(this.marca, this.modelo, this.color);\n    // NOTE: Retornamos this para poder anidas funciones\n    return this;\n  }\n}\n\nconst coche = new Coche(\"Ford\", \"F-150\", \"rojo\")\n  .introducirColor(\"rosa\")\n  .guardar();\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Prioriza la composición en vez de la herecia\n\nComo se citó en [_Patrones de Diseño_](https://en.wikipedia.org/wiki/Design_Patterns)\npor \"the Gang of Four\", deberías priorizar la composición en vez de la herecia\nsiempre que puedas. Hay muy buenas razones para usar tanto la herecia como la\ncomposición. El problema principal es que nuestra mente siempre tiende a la herencia\ncomo primera opción, pero deberíamos de pensar qué tan bien nos encaja la composición\nen ese caso particular porque en muchas ocasiones es lo más acertado.\n\nTe estarás preguntando entonces, _¿Cuando debería yo usar la herencia?_ Todo depende.\nDepende del problema que tengas entre mano, pero ya hay ocasiones particulares donde\nla herencia tiene más sentido que la composición:\n\n1. Tu herencia representa una relación \"es un/a\" en vez de \"tiene un/a\"\n   (Humano-\u003eAnimal vs. Usuario-\u003eDetallesUsuario)\n2. Puedes reutilizar código desde las clases base (Los humanos pueden moverse como animales)\n3. Quieres hacer cambios generales a clases derivadas cambiando la clase base.\n   (Cambiar el consumo de calorías a todos los animales mientras se mueven)\n\n**🙅‍ Mal:**\n\n```javascript\nclass Empleado {\n  constructor(nombre, correoElectronico) {\n    this.nombre = nombre;\n    this.correoElectronico = correoElectronico;\n  }\n\n  // ...\n}\n\n// Bad because Employees \"have\" tax data. EmployeeTaxData is not a type of Empleado\nclass InformacionImpuestosEmpleado extends Empleado {\n  constructor(ssn, salario) {\n    super();\n    this.ssn = ssn;\n    this.salario = salario;\n  }\n\n  // ...\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass InformacionImpuestosEmpleado {\n  constructor(ssn, salario) {\n    this.ssn = ssn;\n    this.salario = salario;\n  }\n\n  // ...\n}\n\nclass Empleado {\n  constructor(nombre, correoElectronico) {\n    this.nombre = nombre;\n    this.correoElectronico = correoElectronico;\n  }\n\n  introducirInformacionImpuestos(ssn, salario) {\n    this.informacionImpuestos = new InformacionImpuestosEmpleado(ssn, salario);\n  }\n  // ...\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## **SOLID**\n\n### Principio de Responsabilidad Única (SRP)\n\nComo se cita en _Código Limpio_, \"No debería haber nunca más de un motivo para\nque una clase cambie\". Es muy tentador acribillar a una clase con un montón de\nfuncionalidad. El problema que tiene esto, es que tu clase no tendrá cohesión\ny tendrá bastantes motivos por los que cambiar. Es por eso que es importante\nreducir el número de veces que tendrás que modificar una clase. Y lo es, porque\nen caso de que tengamos una clase que haga más de una cosa y modifiquemos una\nde ellas, no podemos saber que efectos colaterales puede tener esta acción en las demás.\n\n**🙅‍ Mal:**\n\n```javascript\nclass OpcionesUsuario {\n  constructor(usuario) {\n    this.usuario = usuario;\n  }\n\n  changeSettings(opciones) {\n    if (this.verificarCredenciales()) {\n      // ...\n    }\n  }\n\n  verificarCredenciales() {\n    // ...\n  }\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass AutenticationUsuario {\n  constructor(usuario) {\n    this.usuario = usuario;\n  }\n\n  verificarCredenciales() {\n    // ...\n  }\n}\n\nclass UserSettings {\n  constructor(usuario) {\n    this.usuario = usuario;\n    this.autenticacion = new AutenticationUsuario(usuario);\n  }\n\n  changeSettings(settings) {\n    if (this.autenticacion.verificarCredenciales()) {\n      // ...\n    }\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Principio de abierto/cerrado (OCP)\n\nCitado por Bertrand Meyer: _\"Las entidades de software (clases, módulos, funciones, ...)\ndeberían estar abiertas a extensión pere cerradas a modificación.\"_ ¿Qué significa esto?\nBásicamente significa que los usuarios deberían de ser capaces de añadir funcionalidad\na la aplicación sin tener que tocar el código creado hasta ahora.\n\n**🙅‍ Mal:**\n\n```javascript\nclass AdaptadorAjax extends Adaptador {\n  constructor() {\n    super();\n    this.name = \"adaptadorAjax\";\n  }\n}\n\nclass AdaptadorNodos extends Adaptador {\n  constructor() {\n    super();\n    this.nombre = \"adaptadorNodos\";\n  }\n}\n\nclass  {\n  constructor(adapter) {\n    this.adapter = adapter;\n  }\n\n  fetch(url) {\n    if (this.adapter.nombre === \"adaptadorAjax\") {\n      return hacerLlamadaAjax(url).then(respuesta =\u003e {\n        // transformar la respuesta y devolverla\n      });\n    } else if (this.adapter.nombre === \"adaptadorHttpNodos\") {\n      return hacerLlamadaHttp(url).then(respuesta =\u003e {\n        // transformar la respuesta y devolverla\n      });\n    }\n  }\n}\n\nfunction hacerLlamadaAjax(url) {\n  // request and return promise\n}\n\nfunction hacerLlamadaHttp(url) {\n  // request and return promise\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass AdaptadorAjax extends Adapter {\n  constructor() {\n    super();\n    this.nombre = \"adaptadorAjax\";\n  }\n\n  pedir(url) {\n    // Pedir y devolver la promesa\n  }\n}\n\nclass AdaptadorNodos extends Adapter {\n  constructor() {\n    super();\n    this.nombre = \"adaptadorNodos\";\n  }\n\n  pedir(url) {\n    // Pedir y devolver la promesa\n  }\n}\n\nclass EjecutadorPeticionesHttp {\n  constructor(adaptador) {\n    this.adaptador = adaptador;\n  }\n\n  fetch(url) {\n    return this.adaptador.pedir(url).then(respuesta =\u003e {\n      // Transformar y devolver la respuesta\n    });\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Principio de sustitución de Liskov (LSP)\n\nEste es un término que asusta para lo sencillo que es. Estrictamente se define como\n\"Si S es un subtipo de T, entonces los objetos del tipo T deberían poderse substituir\npor objetos del tipo S\".\n\nUn ejemplo práctico vien a ser si tenemos una _clase padre_ y una _clase hija_,\nentonces ambas han de poderse substituir la una por la otra y viceversa sin recibir\nningún tipo de error o datos erróneos. Un caso práctico es el del cuadrado y el\nrectángulo. Geométricamente, un cuadrado es un rectángulo, pero si lo creamos\ncon una relación \"es un\" a través de herencia, empezamos a tener problemas...\n\n**🙅‍ Mal:**\n\n```javascript\nclass Rectangulo {\n  constructor() {\n    this.anchura = 0;\n    this.altura = 0;\n  }\n\n  introducirColor(color) {\n    // ...\n  }\n\n  render(area) {\n    // ...\n  }\n\n  introducirAnchura(anchura) {\n    this.anchura = anchura;\n  }\n\n  introducirAltura(altura) {\n    this.altura = altura;\n  }\n\n  conseguirArea() {\n    return this.anchura * this.altura;\n  }\n}\n\nclass Cuadrado extends Rectangulo {\n  introducirAnchura(anchura) {\n    this.anchura = anchura;\n    this.altura = anchura;\n  }\n\n  introducirAltura(altura) {\n    this.width = altura;\n    this.altura = altura;\n  }\n}\n\nfunction renderizaRectangulosLargos(rectangulos) {\n  rectangulos.forEach(rectangulo =\u003e {\n    rectangulo.introducirAnchura(4);\n    rectangulo.introducirAltura(5);\n    const area = rectangulo.conseguirArea(); // MAL: Para el cuadrado devuelve 25 y devería ser 20\n    rectangulo.render(area);\n  });\n}\n\nconst rectangulos = [new Rectangulo(), new Rectangulo(), new Cuadrado()];\nrenderizaRectangulosLargos(rectangulos);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass Forma {\n  introducirColor(color) {\n    // ...\n  }\n\n  render(area) {\n    // ...\n  }\n}\n\nclass Rectangulo extends Forma {\n  constructor(width, height) {\n    super();\n    this.anchura = anchura;\n    this.altura = altura;\n  }\n\n  conseguirArea() {\n    return this.anchura * this.altura;\n  }\n}\n\nclass Cuadrado extends Forma {\n  constructor(distancia) {\n    super();\n    this.distancia = distancia;\n  }\n\n  conseguirArea() {\n    return this.distancia * this.distancia;\n  }\n}\n\nfunction renderizaRectangulosLargos(shapes) {\n  shapes.forEach(shape =\u003e {\n    const area = shape.conseguirArea();\n    shape.render(area);\n  });\n}\n\nconst shapes = [new Rectangulo(4, 5), new Rectangulo(4, 5), new Cuadrado(5)];\nrenderizaRectangulosLargos(shapes);\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Principio de Segregacion de Interfaces (ISP)\n\nJavascript no dispone de interfaces así que no podemos aplicar el principio como\ntal. De todas maneras, es importante conceptualmente hablando aunque no tengamos\ntipados como tal, pues eso resulta haciendo un código mantenible igualmente.\n\n_ISP_ dice que \"los servicios no deberían estar forzados a depender de interfaces\nque realmente no usan\".\n\nUn buen ejemplo en javascript sería las típicas clases que requieren de un\nenormes objetos de configuración. No hacer que los servicios requieran de\ngrandes cantidades de opciones es beneficioso, porque la gran mayoría del tiempo,\nno necesitarán esa configuración. Hacerlos opcionales ayuda a no tener el problema\nde \"Interaz gorda\", en inglés conocido como \"fat interface\".\n\n**🙅‍ Mal:**\n\n```javascript\nclass DOMTraverser {\n  constructor(configuraciones) {\n    this.configuraciones = configuraciones;\n    this.setup();\n  }\n\n  preparar() {\n    this.nodoRaiz = this.configuraciones.nodoRaiz;\n    this.ModuloAnimacion.preparar();\n  }\n\n  atravesar() {\n    // ...\n  }\n}\n\nconst $ = new DOMTraverser({\n  nodoRaiz: document.getElementsByTagName(\"body\"),\n  moduloAnimacion() {} // Most of the time, we won't need to animate when traversing.\n  // ...\n});\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass DOMTraverser {\n  constructor(configuraciones) {\n    this.configuraciones = configuraciones;\n    this.opciones = configuraciones.opciones;\n    this.preparar();\n  }\n\n  preparar() {\n    this.nodoRaiz = this.configuraciones.nodoRaiz;\n    this.prepararOpciones();\n  }\n\n  prepararOpciones() {\n    if (this.opciones.moduloAnimacion) {\n      // ...\n    }\n  }\n\n  atravesar() {\n    // ...\n  }\n}\n\nconst $ = new DOMTraverser({\n  nodoRaiz: document.getElementsByTagName(\"body\"),\n  opciones: {\n    moduloAnimacion() {}\n  }\n});\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Principio de Inversión de Dependencias (DIP)\n\n_Por favor, no confundir con Inyección de Dependencias._ Mucha gente se piensa\nque la \"D\" de _SOLID_ es de Inyección de Dependencias _(Dependency Inection, DI)._\n\nEste principio nos dice dos cosas básicamente:\n\n1. Módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos\n   deberían depender de abstracciones.\n2. Las abstracciones no deberían depender de detalles si no que, los detalles\n   deberían depender de abstracciones.\n\nEsto puede ser algo complejo al principio, pero si has trabajado con AngularJS,\nhas visto de manera indirecta esto con la Inyección de Dependencias. Como\ncomentaba anteriormente, aunque no son lo mismo, van de la mano. La Inversión de\nDependencías es posible gracias a la Inyección de Dependencias. _DI_ hace posible\nque los módulos de alto nivel dependan de abstracciones y no de detalles.\n\nEl mayor de los beneficioses la reducción del acoplamiento entre módulos. Cuánto\nmayor acoplamiento, mayor dificultad en refactorización.\n\nComo hemos comentado antes, `Javascript` no tiene interfaces así que los contratos\nson un poco... así asá. Están en nuestro cabeza y eso debemos tenerlo en cuenta.\nMucha gente usa javascript docs, anotaciones en comentarios justo encima de los\nmódulos y algunas cosas más. Vamos a ver un ejemplo con `RastreadorDeInventario`.\n\n**🙅‍ Mal:**\n\n```javascript\nclass SolicitadorDeInventario {\n  constructor() {\n    this.REQ_METHODS = [\"HTTP\"];\n  }\n\n  pedirArticulo(articulo) {\n    // ...\n  }\n}\n\nclass RastreadorDeInventario {\n  constructor(articulos) {\n    this.articulos = articulos;\n\n    // MAL: Hemos creado una dependencia de una concreción que va atada a una implementación\n    // Deberíamos tener pedirArticulos  dependiendo únicamente de un método: 'solicitud'\n    this.solicitador = new SolicitadorDeInventario();\n  }\n\n  pedirArticulos() {\n    this.articulos.forEach(articulo =\u003e {\n      this.solicitador.pedirArticulo(articulo);\n    });\n  }\n}\n\nconst rastreadorDeInventario = new RastreadorDeInventario([\n  \"manzanas\",\n  \"platanos\"\n]);\nrastreadorDeInventario.pedirArticulos();\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass RastreadorDeInventario {\n  constructor(articulos, solicitador) {\n    this.articulos = articulos;\n    this.solicitador = solicitador;\n  }\n\n  pedirArticulos() {\n    this.articulos.forEach(articulo =\u003e {\n      this.solicitador.pedirArticulo(articulo);\n    });\n  }\n}\n\nclass SolicitadorDeInventarioV1 {\n  constructor() {\n    this.REQ_METHODS = [\"HTTP\"];\n  }\n\n  pedirArticulo(articulo) {\n    // ...\n  }\n}\n\nclass SolicitadorDeInventarioV2 {\n  constructor() {\n    this.REQ_METHODS = [\"WS\"];\n  }\n\n  pedirArticulo(articulo) {\n    // ...\n  }\n}\n\n// By constructing our dependencies externally and injecting them, we can easily\n// substitute our request module for a fancy new one that uses WebSockets.\n\n// Construyendo nuestras dependencias desde fuera e inyectandolas, podríamos\n// substituir nuestro Módulo solicitador por uno con websockets o lo que sea\nconst rastreadorDeInventario = new RastreadorDeInventario(\n  [\"manzanas\", \"platanos\"],\n  new SolicitadorDeInventarioV2()\n);\nrastreadorDeInventario.pedirArticulos();\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## **Testing**\n\nEl testing es más importante que la entrega. Si no tienes test o tienes muchos\nque no soy de gran ayuda, cada vez que quieras entregar valor no estarás seguro\nde ue eso funciona debidamente y que nada falla. Puedes decidir con el equipo\ncuál es el porcentaje al que queréis ceñiros pero, la única manera de tener\nconfianza total de que nada falla, es teniendo 100% de covertura de test. Para\nesto, ncesitarás tener una gran herramienta para poder testear pero también\nuna que te calcule adecuadamente [el porcentaje cubierto](http://gotwarlost.github.io/istanbul/).\n\nNo hay excusas para no escribir tests. Hay\n[un montón de frameworks de JS](http://jstherightway.org/#testing-tools) entre\nlos que podréis tu y tu equipo decidir. Una vez hayáis elegido el framework,\npara cada nueva funcionalidad que se quiera añadir a la plataforma, escribir tests.\nSi prefieres hacer _Test-Driven Development_ me parece bien, pero la ide principal de\nlos test es dar confianza suficiente al programador para que pueda seguir entregando valor.\n\n### Sólo un concepto por test\n\n**🙅‍ Mal:**\n\n```javascript\nimport assert from \"assert\";\n\ndescribe(\"MakeMomentJSGreatAgain\", () =\u003e {\n  it(\"maneja límites de las fechas\", () =\u003e {\n    let fecha;\n\n    fecha = new MakeMomentJSGreatAgain(\"1/1/2015\");\n    fecha.addDays(30);\n    assert.equal(\"1/31/2015\", fecha);\n\n    fecha = new MakeMomentJSGreatAgain(\"2/1/2016\");\n    fecha.addDays(28);\n    assert.equal(\"02/29/2016\", fecha);\n\n    fecha = new MakeMomentJSGreatAgain(\"2/1/2015\");\n    fecha.addDays(28);\n    assert.equal(\"03/01/2015\", fecha);\n  });\n});\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nimport assert from \"assert\";\n\ndescribe(\"MakeMomentJSGreatAgain\", () =\u003e {\n  it(\"Maneja los meses con 30 días\", () =\u003e {\n    const fecha = new MakeMomentJSGreatAgain(\"1/1/2015\");\n    fecha.addDays(30);\n    assert.equal(\"1/31/2015\", fecha);\n  });\n\n  it(\"Maneja los años bisiestos\", () =\u003e {\n    const fecha = new MakeMomentJSGreatAgain(\"2/1/2016\");\n    fecha.addDays(28);\n    assert.equal(\"02/29/2016\", fecha);\n  });\n\n  it(\"Maneja los años NO bisiestos\", () =\u003e {\n    const fecha = new MakeMomentJSGreatAgain(\"2/1/2015\");\n    fecha.addDays(28);\n    assert.equal(\"03/01/2015\", fecha);\n  });\n});\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Concurrencia\n\n### Usa Promesas, no callbacks\n\n_Los callbacks son funciones que se pasan como parámetros a otras funciones\npara ser ejecutaras una vez esta función termina. Por ejemplo: Dada las funciones\nA y B, se dice que B es el callback de A si la función B es pasada como parámetro\na la función A y esta, se ejecuta este callback una vez ha terminado_\n\nLos `callbacks` no son limpios ni en cuanto a legibilidad ni en cuanto a formato\nde texto _(dado que provocan niveles de identación)_. Con ES2015/ES6 las promesas\nson un tipo global. ¡Úsalas!\n\n**🙅‍ Mal:**\n\n```javascript\nimport { get } from \"request\";\nimport { writeFile } from \"fs\";\n\nget(\n  \"https://en.wikipedia.org/wiki/Robert_Cecil_Martin\",\n  (requestErr, respuesta) =\u003e {\n    if (requestErr) {\n      console.error(requestErr);\n    } else {\n      writeFile(\"article.html\", respuesta.body, writeErr =\u003e {\n        if (writeErr) {\n          console.error(writeErr);\n        } else {\n          console.log(\"File written\");\n        }\n      });\n    }\n  }\n);\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nimport { get } from \"request\";\nimport { writeFile } from \"fs\";\n\nget(\"https://en.wikipedia.org/wiki/Robert_Cecil_Martin\")\n  .then(respuesta =\u003e {\n    return writeFile(\"article.html\", respuesta);\n  })\n  .then(() =\u003e {\n    console.log(\"File written\");\n  })\n  .catch(err =\u003e {\n    console.error(err);\n  });\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Async/Await is incluso más limpio que las Promesas\n\nLas promesas son una elección más limpia que los callbacks pero ES2017/ES8\ntrae la funcionalidad de `async/await` que es incluos más limpio que las promesas.\nTodo lo que tienes que hacer es añadir el prefijo `async` a una función y entonces\nya podemos usar esa función de manera imperative sin ningún `.then()`. La\npalabra `await` la usarás para hacer que ese código asincrono se comporte de\n\"manera síncrona\".\n\n**🙅‍ Mal:**\n\n```javascript\nimport { get } from \"request-promise\";\nimport { writeFile } from \"fs-promise\";\n\nget(\"https://en.wikipedia.org/wiki/Robert_Cecil_Martin\")\n  .then(respuesrta =\u003e {\n    return writeFile(\"article.html\", respuesrta);\n  })\n  .then(() =\u003e {\n    console.log(\"File written\");\n  })\n  .catch(err =\u003e {\n    console.error(err);\n  });\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nimport { get } from \"request-promise\";\nimport { writeFile } from \"fs-promise\";\n\nasync function conseguirArticulosDeCodigoLimpio() {\n  try {\n    const respuesrta = await get(\n      \"https://en.wikipedia.org/wiki/Robert_Cecil_Martin\"\n    );\n    await writeFile(\"article.html\", respuesrta);\n    console.log(\"File written\");\n  } catch (err) {\n    console.error(err);\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Manejo de errores\n\n¡Lanzar errores está bien! Significa que en tiempo de ejecución se ha detectado\nque algo no estaba funcionando como debía y se ha parado la ejecución del trozo\nde código. Además se notifica siempre en la consola del navegador.\n\n### No ignores los errores capturados\n\nNo hacer nada con los errores capturados no te da la opción de anticiparte\no arreglar dicho error. El printar el error por la consola del navegador\nno es una solución, pues la gran mayoría de veces nadie es consciente de eso\ny el error pasas desapercibido. Envuelve tu código con `try/catch` y es ahí\ndonde tendrás que elaborar tu plan de reacción a posibles errores\n\n**🙅‍ Mal:**\n\n```javascript\ntry {\n  functionQueDeberiaLanzarError();\n} catch (error) {\n  console.log(error);\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\ntry {\n  functionQueDeberiaLanzarError();\n} catch (error) {\n  // Una option (algo más molesta que el convencional console.log)\n  console.error(error);\n  // Otra opción:\n  notificarAlUsuarioDelError(error);\n  // Otra opción:\n  reportarElArrorAUnServicio(error);\n  // O hazlas todas!\n}\n```\n\n### No ignores las promesas rechazadas\n\nNo ignores las promesas que han sido rechadas por la misma razón que no deberías\nignorar errores capturados en el `try/catch`.\n\n**🙅‍ Mal:**\n\n```javascript\ncogerDatos()\n  .then(datos =\u003e {\n    functionQueDeberiaLanzarError(datos);\n  })\n  .catch(error =\u003e {\n    console.log(error);\n  });\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\ncogerDatos()\n  .then(datos =\u003e {\n    functionQueDeberiaLanzarError(datos);\n  })\n  .catch(error =\u003e {\n    // Una option (algo más molesta que el convencional console.log)\n    console.error(error);\n    // Otra opción:\n    notificarAlUsuarioDelError(error);\n    // Otra opción:\n    reportarElArrorAUnServicio(error);\n    // O hazlas todas!\n  });\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Formato\n\nEl formato del código es algo subjetivo. Como otras reglas aquí, no hay una regla\nque deberías seguir o una fórmula secreta. Lo que si que está claro es que no\ndeberíamos discutir ni crear conflictos con nuestros compañeros de trabajo acerca\nde estas reglas. Hay unas cuantas [herrmientas](http://standardjs.com/rules.html)\nque automatizan todas las reglas de formato de texto. ¡Ahorrarse tiempo en estas\nformateando el texto es un pasada!\n\n### Usa consistenemente la capitalización\n\nComo ya hemos dicho, `javascript` es un lenguage no tipado así pues, la\ncapitalización de las variables importa, y mucho. Estas son reglas totalmente\nsubjetivas así que como equipo, podéis elegir lo que más os guste/convenga.\nLa cuestión es que independientemente de lo que decidáis, seáis consistentes.\n\n**🙅‍ Mal:**\n\n```javascript\nconst DIAS_POR_SEMANA = 7;\nconst diasPorMes = 30;\n\nconst canciones = [\"Back In Black\", \"Stairway to Heaven\", \"Hey Jude\"];\nconst Artistas = [\"ACDC\", \"Led Zeppelin\", \"The Beatles\"];\n\nfunction borrarBaseDeDatos() {}\nfunction restablecer_baseDeDatos() {}\n\nclass animal {}\nclass Alpaca {}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nconst DIAS_POR_SEMANA = 7;\nconst DIAS_POR_MES = 30;\n\nconst CANCIONES = [\"Back In Black\", \"Stairway to Heaven\", \"Hey Jude\"];\nconst ARTISTAS = [\"ACDC\", \"Led Zeppelin\", \"The Beatles\"];\n\nfunction borrarBaseDeDatos() {}\nfunction restablecerBaseDeDatos() {}\n\nclass Animal {}\nclass Alpaca {}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Funciones que llaman y funciones que son llamadas, deberían estar cerca\n\nSi una función llama a otra, haz que esta función que va a ser llamada esté\nlo más cerca posible de la función que la llama. Idealmente, situa siempre\nla función que va a ser llamada justo después de la función que la ejecuta.\n¿El motivo? Pues normalmente acostumbramos a leer de arriba abajo y tampoco\nqueremos tener que hacer _scroll_ hasta abajo del todo del ficheor para volver\na subir.\n\n**🙅‍ Mal:**\n\n```javascript\nclass RevisionDeRendimiento {\n  constructor(empleado) {\n    this.empleado = empleado;\n  }\n\n  conseguirCompañeros() {\n    return db.buscar(this.empleado, \"compañeros\");\n  }\n\n  conseguirJefe() {\n    return db.buscar(this.empleado, \"jefe\");\n  }\n\n  conseguirOpinionDeLosCompañeros() {\n    const compañeros = this.conseguirCompañeros();\n    // ...\n  }\n\n  executarRevision() {\n    this.conseguirOpinionDeLosCompañeros();\n    this.conseguirOpinionDelJefe();\n    this.conseguirAutoRevision();\n  }\n\n  conseguirOpinionDelJefe() {\n    const jefe = this.conseguirJefe();\n  }\n\n  conseguirAutoRevision() {\n    // ...\n  }\n}\n\nconst review = new RevisionDeRendimiento(empleado);\nreview.executarRevision();\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nclass RevisionDeRendimiento {\n  constructor(empleado) {\n    this.empleado = empleado;\n  }\n\n  executarRevision() {\n    this.conseguirOpinionDeLosCompañeros();\n    this.conseguirOpinionDelJefe();\n    this.conseguirAutoRevision();\n  }\n\n  conseguirOpinionDeLosCompañeros() {\n    const compañeros = this.conseguirCompañeros();\n    // ...\n  }\n\n  conseguirCompañeros() {\n    return db.buscar(this.empleado, \"compañeros\");\n  }\n\n  conseguirOpinionDelJefe() {\n    const jefe = this.conseguirJefe();\n  }\n\n  conseguirJefe() {\n    return db.buscar(this.empleado, \"jefe\");\n  }\n\n  conseguirAutoRevision() {\n    // ...\n  }\n}\n\nconst review = new RevisionDeRendimiento(empleado);\nreview.executarRevision();\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Comentarios\n\n### Comenta únicamente la lógica de negocio que es compleja\n\nLos comentarios son una disculpa, no un requerimiento. Supuesatmente se dice\nque un buen código debería comentarse por si mismo. Un código perfecto no\nestá optimizado para la máquina sinó que lo está para la manteniblidad de éste\npor un compañero o futuro compañero. Para esto, ha de ser lo más semántico posible.\nEl código ha de estar escrito para que niños pequeños lo entiendan.\n\n**🙅‍ Mal:**\n\n```javascript\nfunction hashIt(datos) {\n  // El hash\n  let hash = 0;\n\n  // Tamaño del string\n  const tamaño = datos.length;\n\n  // Iteramos a través de cada carácter de los datos\n  for (let i = 0; i \u003c tamaño; i++) {\n    // Coger código del caracter\n    const char = datos.charCodeAt(i);\n    // Crear el hash\n    hash = (hash \u003c\u003c 5) - hash + char;\n    // Convertir a un entero de 32 bits\n    hash \u0026= hash;\n  }\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction hashIt(datos) {\n  let hash = 0;\n  const tamaño = datos.length;\n\n  for (let i = 0; i \u003c tamaño; i++) {\n    const caracter = datos.charCodeAt(i);\n    hash = (hash \u003c\u003c 5) - hash + caracter;\n\n    // Convertir a un entero de 32 bits\n    hash \u0026= hash;\n  }\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No dejes código comentado en tu repositorio\n\nEl control de versiones existe para algo. Si tu motivo o excusa por el que comentar\nun código es porque en breves o algun día lo vas a necesitas, eso no me sirve. Ese\ncódigo que acabas de borrar consta en alguna de tus versiones de tu código fuente.\nLo que deberías hacer entonces quizás, es usar `git tags`, poner el código de la\ntarea en el nombre del commit, etc... Hay muchos truquitos para hacer eso!\n\n**🙅‍ Mal:**\n\n```javascript\nhacerCosas();\n// hacerOtrasCosas();\n// hacerCosasAunMasRaras();\n// estoHaceMaravillas();\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nhacerCosas();\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### No hagas un diario de comentarios\n\nRecuerda ¡Usa el control de versioens! No hay motivo alguno para tener código\nmuerto, código comentado y aún menos, un diadrio o resumen de modificaciones en\ntus comentarios. Si quieres ver las modificaciones, usa `git log`, la herramiento\n`blame` o incluso el `history`.\n\n**🙅‍ Mal:**\n\n```javascript\n/**\n * 2016-12-20: `monads` borrados, no hay quien los entienda\n * 2016-10-01: Código mejorado con 'monads'\n * 2016-02-03: Borrado tipado\n * 2015-03-14: Añadido tipado\n */\nfunction combinar(a, b) {\n  return a + b;\n}\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\nfunction combinar(a, b) {\n  return a + b;\n}\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n### Evita los marcadores de secciones\n\nNormalmente acostumbran a ser molestos. Deja que las variables y las funciones\nhagan su función con sus identaciones naturales y de esta manera, formateen el\ncódigo correctamente\n.\n\n**🙅‍ Mal:**\n\n```javascript\n////////////////////////////////////////////////////////////////////////////////\n// Instanciación del Modelo Scope\n////////////////////////////////////////////////////////////////////////////////\n$scope.modelo = {\n  menu: \"foo\",\n  nav: \"bar\"\n};\n\n////////////////////////////////////////////////////////////////////////////////\n// Preparación de la acción\n////////////////////////////////////////////////////////////////////////////////\nconst acciones = function() {\n  // ...\n};\n```\n\n**👨‍🏫 Bien:**\n\n```javascript\n$scope.modelo = {\n  menu: \"foo\",\n  nav: \"bar\"\n};\n\nconst acciones = function() {\n  // ...\n};\n```\n\n**[⬆ Volver arriba](#contenido)**\n\n## Traducciones\n\nTambién esta disponible en otros idiomas\n\n- ![br](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Brazil.png) **Brazilian Portuguese**: [fesnt/clean-code-javascript](https://github.com/fesnt/clean-code-javascript)\n- ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Uruguay.png) **Spanish (Uruguay)**: [andersontr15/clean-code-javascript](https://github.com/andersontr15/clean-code-javascript-es)\n- ![es](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Spain.png) **Spanish (Spain)**: [tureey/clean-code-javascript](https://github.com/tureey/clean-code-javascript)\n- ![cn](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/China.png) **Chinese**:\n  - [alivebao/clean-code-js](https://github.com/alivebao/clean-code-js)\n  - [beginor/clean-code-javascript](https://github.com/beginor/clean-code-javascript)\n- ![de](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Germany.png) **German**: [marcbruederlin/clean-code-javascript](https://github.com/marcbruederlin/clean-code-javascript)\n- ![kr](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/South-Korea.png) **Korean**: [qkraudghgh/clean-code-javascript-ko](https://github.com/qkraudghgh/clean-code-javascript-ko)\n- ![pl](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Poland.png) **Polish**: [greg-dev/clean-code-javascript-pl](https://github.com/greg-dev/clean-code-javascript-pl)\n- ![ru](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Russia.png) **Russian**:\n  - [BoryaMogila/clean-code-javascript-ru/](https://github.com/BoryaMogila/clean-code-javascript-ru/)\n  - [maksugr/clean-code-javascript](https://github.com/maksugr/clean-code-javascript)\n- ![vi](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Vietnam.png) **Vietnamese**: [hienvd/clean-code-javascript/](https://github.com/hienvd/clean-code-javascript/)\n- ![ja](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Japan.png) **Japanese**: [mitsuruog/clean-code-javascript/](https://github.com/mitsuruog/clean-code-javascript/)\n- ![id](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Indonesia.png) **Indonesia**:\n  [andirkh/clean-code-javascript/](https://github.com/andirkh/clean-code-javascript/)\n- ![it](https://raw.githubusercontent.com/gosquared/flags/master/flags/flags/shiny/24/Italy.png) **Italian**:\n  [frappacchio/clean-code-javascript/](https://github.com/frappacchio/clean-code-javascript/)\n\n**[⬆ Volver arriba](#contenido)**\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevictoribero%2Fclean-code-javascript","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevictoribero%2Fclean-code-javascript","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevictoribero%2Fclean-code-javascript/lists"}