Pautas para escribir código JavaScript limpio

Si le importa el código en sí, y cómo está escrito, y no solo está ocupado creando programas de trabajo, esto significa que quiere que su código esté limpio. Un desarrollador profesional escribe código no solo para computadoras, sino también para sí mismo que ha cumplido este código en el futuro, y para otros programadores. El código que escribes no desaparece para siempre en las entrañas de la computadora. Vive, cambia y si está mal escrito, puede molestar mucho a alguien que tendrá que editarlo después de que lo escribes. Es posible que seas este "alguien".



En base a estas ideas, el código limpio se puede definir como un código escrito de tal manera que se explique por sí mismo. Este código puede ser fácilmente entendido por las personas, será fácil modificarlo o ampliarlo.

Código y preguntas de WTF


La esencia de las preguntas de WTF, como "¿WTF es eso?", Se reduce a la extrema sorpresa y resentimiento. En ruso, estos sentimientos se pueden expresar con la pregunta "¿Qué demonios?". "Maldición", dependiendo de la situación, puede dar paso a algo completamente no imprimible. ¿Cuántas veces ha tenido que agregar el código de alguien y hacer preguntas similares?

Cuando se hacen preguntas de WTF sobre el código de otra persona, los programadores se preguntan qué es (¿WTF es eso?), ¿Qué trató de hacer el autor del código (WTF hizo aquí?), ¿Por qué esta o esa construcción está presente en el código (WTF es esto para?)

Aquí está la imagen según la cual el único indicador confiable de la calidad del código es el número de preguntas WTF por minuto.


A la izquierda hay buen código. A la derecha es malo

En serio, para ayudarlo a sintonizar para pensar en un código limpio, citemos a Robert Martin, conocido como Tío Bob: "Incluso un código de programa incorrecto puede funcionar. Sin embargo, si el código no es "limpio", siempre interferirá con el desarrollo del proyecto ".

Ahora veamos algunas pautas prácticas para escribir código limpio. Usaremos JavaScript aquí, pero estas recomendaciones se pueden aplicar al desarrollo en otros idiomas.

1. estrictos controles de igualdad


Intenta usar === lugar de == .

 //     == -       .     ,   ,   ,   -    . 0 == false // true 0 === false // false 2 == "2" // true 2 === "2" // false //  const value = "500"; if (value === 500) { console.log(value); //     } if (value === "500") { console.log(value); //    } 

2. Variables


Nombra las variables para que sus nombres revelen su esencia, su papel en el programa. Con este enfoque, será conveniente buscarlos en el código, y cualquiera que vea este código puede comprender más fácilmente el significado de las acciones que realizan.
Malo:

 let daysSLV = 10; let y = new Date().getFullYear(); let ok; if (user.age > 30) { ok = true; } 

Bueno

 const MAX_AGE = 30; let daysSinceLastVisit = 10; let currentYear = new Date().getFullYear(); ... const isUserOlderThanAllowed = user.age > MAX_AGE; 

No es necesario agregar palabras adicionales a los nombres de las variables que no son necesarias.

Malo:

 let nameValue; let theProduct; 

Bueno

 let name; let product; 

No debe obligar a alguien que lee el código a tener que recordar el entorno en el que se declara la variable.

Malo:

 const users = ["John", "Marco", "Peter"]; users.forEach(u => { doSomething(); doSomethingElse(); // ... // ... // ... // ... //    ,    WTF- "   `u`?" register(u); }); 

Bueno

 const users = ["John", "Marco", "Peter"]; users.forEach(user => { doSomething(); doSomethingElse(); // ... // ... // ... // ... register(user); }); 

No es necesario que proporcione nombres de variables con información redundante sobre el contexto en el que se utilizan.

Malo:

 const user = { userName: "John", userSurname: "Doe", userAge: "28" }; ... user.userName; 

Bueno

 const user = { name: "John", surname: "Doe", age: "28" }; ... user.name; 

3. Funciones


Use nombres descriptivos largos para las funciones. Dado que una función es una descripción de una determinada acción, su nombre debe ser un verbo o una frase que describa completamente la esencia de la función. Los nombres de los argumentos deben seleccionarse para que describan adecuadamente los datos que representan. Los nombres de las funciones deben decirle al lector de código qué hacen exactamente estas funciones.

Malo:

 function notif(user) { //  } 

Bueno

 function notifyUser(emailAddress) { //  } 

Evite usar largas listas de argumentos. Idealmente, las funciones deberían tener dos o menos argumentos. Cuantos menos argumentos tenga una función, más fácil será probarla.

Malo:

 function getUsers(fields, fromDate, toDate) { //  } 

Bueno

 function getUsers({ fields, fromDate, toDate }) { //  } getUsers({ fields: ['name', 'surname', 'email'], fromDate: '2019-01-01', toDate: '2019-01-18' }) 

Use los argumentos predeterminados, dándoles preferencia sobre las construcciones condicionales.

Malo:

 function createShape(type) { const shapeType = type || "cube"; // ... } 

Bueno

 function createShape(type = "cube") { // ... } 

Una función debería resolver un problema. Esfuércese por asegurarse de que una función no realice muchas acciones.

Malo:

 function notifyUsers(users) { users.forEach(user => {   const userRecord = database.lookup(user);   if (userRecord.isVerified()) {     notify(user);   } }); } 

Bueno

 function notifyVerifiedUsers(users) { users.filter(isUserVerified).forEach(notify); } function isUserVerified(user) { const userRecord = database.lookup(user); return userRecord.isVerified(); } 

Use Object.assign para establecer las propiedades de los objetos de forma predeterminada.

Malo:

 const shapeConfig = { type: "cube", width: 200, height: null }; function createShape(config) { config.type = config.type || "cube"; config.width = config.width || 250; config.height = config. height || 250; } createShape(shapeConfig); 

Bueno

 const shapeConfig = { type: "cube", width: 200 //   'height'   }; function createShape(config) { config = Object.assign(   {     type: "cube",     width: 250,     height: 250   },   config ); ... } createShape(shapeConfig); 

No use banderas como parámetros. Su uso significa que la función realiza más acciones de las que debería haber realizado.

Malo:

 function createFile(name, isPublic) { if (isPublic) {   fs.create(`./public/${name}`); } else {   fs.create(name); } } 

Bueno

 function createFile(name) { fs.create(name); } function createPublicFile(name) { createFile(`./public/${name}`); } 

No contaminar el alcance global. Si necesita expandir un objeto existente, use clases ES y mecanismos de herencia en lugar de crear funciones en la cadena prototipo de objetos estándar.

Malo:

 Array.prototype.myFunc = function myFunc() { //  }; 

Bueno

 class SuperArray extends Array { myFunc() {   //  } } 

4. Construcciones condicionales.


Intente no nombrar las variables booleanas para que haya negación en sus nombres. Lo mismo ocurre con las funciones que devuelven valores booleanos. El uso de tales entidades en construcciones condicionales dificulta la lectura del código.

Malo:

 function isUserNotBlocked(user) { //  } if (!isUserNotBlocked(user)) { //  } 

Bueno

 function isUserBlocked(user) { //  } if (isUserBlocked(user)) { //  } 

Use la forma corta para construcciones condicionales. Quizás esta recomendación pueda parecer trivial, pero vale la pena mencionarla. Use este enfoque solo para variables lógicas, y si está seguro de que el valor de la variable no será undefined o null .

Malo:

 if (isValid === true) { // - ... } if (isValid === false) { // - ... } 

Bueno

 if (isValid) { // - ... } if (!isValid) { // - ... } 

Evite construcciones lógicas siempre que sea posible. Utilice el polimorfismo y la herencia en su lugar.

Malo:

 class Car { // ... getMaximumSpeed() {   switch (this.type) {     case "Ford":       return this.someFactor() + this.anotherFactor();     case "Mazda":       return this.someFactor();     case "McLaren":       return this.someFactor() - this.anotherFactor();   } } } 

Bueno

 class Car { // ... } class Ford extends Car { // ... getMaximumSpeed() {   return this.someFactor() + this.anotherFactor(); } } class Mazda extends Car { // ... getMaximumSpeed() {   return this.someFactor(); } } class McLaren extends Car { // ... getMaximumSpeed() {   return this.someFactor() - this.anotherFactor(); } } 

5. clases de ES


Las clases aparecieron en JavaScript hace relativamente poco. Se les puede llamar azúcar sintáctico. Lo que sucede cuando se usan clases se basa en prototipos de objetos, como antes. Pero el código que usa las clases se ve diferente. En general, si es posible, se deberían preferir las clases ES a las funciones de constructor regulares.

Malo:

 const Person = function(name) { if (!(this instanceof Person)) {   throw new Error("Instantiate Person with `new` keyword"); } this.name = name; }; Person.prototype.sayHello = function sayHello() { /**/ }; const Student = function(name, school) { if (!(this instanceof Student)) {   throw new Error("Instantiate Student with `new` keyword"); } Person.call(this, name); this.school = school; }; Student.prototype = Object.create(Person.prototype); Student.prototype.constructor = Student; Student.prototype.printSchoolName = function printSchoolName() { /**/ }; 

Bueno

 class Person { constructor(name) {   this.name = name; } sayHello() {   /* ... */ } } class Student extends Person { constructor(name, school) {   super(name);   this.school = school; } printSchoolName() {   /* ... */ } } 

Organice métodos para que puedan encadenarse. Muchas bibliotecas usan este patrón, como jQuery y Lodash. Como resultado, su código será más compacto que sin usar este patrón. El punto es que al final de cada función de la clase necesitas devolver this . Esto le permitirá combinar llamadas de tales funciones en cadenas.

Malo:

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname; } setAge(age) {   this.age = age; } save() {   console.log(this.name, this.surname, this.age); } } const person = new Person("John"); person.setSurname("Doe"); person.setAge(29); person.save(); 

Bueno

 class Person { constructor(name) {   this.name = name; } setSurname(surname) {   this.surname = surname;   //  this           return this; } setAge(age) {   this.age = age;   //  this           return this; } save() {   console.log(this.name, this.surname, this.age);   //  this           return this; } } const person = new Person("John")   .setSurname("Doe")   .setAge(29)   .save(); 

6. ¿Qué es mejor no hacer?


Cualquiera que quiera que su código esté limpio debe intentar no repetirlo. El punto es evitar situaciones en las que tenga que escribir el mismo código. Además, no necesita dejar funciones no utilizadas y fragmentos de programas que nunca se ejecutan en la base del código.

El código duplicado puede aparecer por varias razones. Por ejemplo, un proyecto puede tener un par de funciones ligeramente diferentes. La naturaleza de estas diferencias o falta de tiempo obliga al programador, por ejemplo, a crear dos funciones independientes que contienen un código casi idéntico. En tal situación, deshacerse del código duplicado es abstraer las diferencias y trabajar con ellas en un nivel superior.

Ahora hablemos del código no utilizado. Este es un código que está presente en la base de código pero no hace absolutamente nada. Esto sucede, por ejemplo, cuando en una determinada etapa de desarrollo se decide que ya no tiene sentido un cierto fragmento del programa. Para deshacerse de dichos fragmentos de código, debe revisar cuidadosamente la base del código y eliminarlos. Es más fácil deshacerse de dicho código en el momento en que se decide que ya no es necesario. Más tarde, puede olvidarse de para qué se utilizó. Esto complicará enormemente la pelea con él.

Si pospone la lucha contra el código innecesario, el programa se parecerá a lo que se muestra en la siguiente figura.


A veces mi código se parece a este balcón. No sé qué tarea está resolviendo, pero me da miedo deshacerme de él.

Resumen


Aquí hemos discutido solo una pequeña parte de las acciones que se pueden tomar para mejorar el código. El autor de este material cree que los principios discutidos aquí a menudo se olvidan. Los programadores intentan seguirlos, pero, por varias razones, no siempre tienen éxito en esto. Quizás, al comienzo del proyecto, todos recuerdan la importancia del código limpio, como resultado, el programa es ordenado. Luego, a medida que se acercan los plazos, a menudo se olvidan de la pureza del código, prestando atención solo a lo que está marcado como TODO o REFACTOR. En esos momentos, el cliente del proyecto insistirá en que el proyecto se complete a tiempo, y no en que su código esté limpio.

Muy a menudo, publicamos materiales sobre el problema de escribir código JavaScript de alta calidad. Si está interesado en este tema, aquí hay algunos enlaces.


Esperamos que lo que aprendió al leer este artículo y lo que puede encontrar en otras publicaciones lo ayude en su búsqueda para escribir código JavaScript limpio.

Estimados lectores! ¿Alguna vez ha hecho preguntas a WTF mientras leía el código de otra persona?



Source: https://habr.com/ru/post/454520/


All Articles