Convención de nombres de variables
design patterns
Las convenciones de nombres son importantes al escribir código, especialmente en lenguajes como JavaScript. Buenas convenciones de nombres pueden mejorar significativamente la legibilidad del código y facilitar el trabajo en equipo.
Los nombres de las variables deben necesariamente estar en inglés y deben ser pronunciables. A continuación mostramos un mal ejemplo:
// mal, debemos evitar estos nombres
const n = 53;
const tx = 0.15;
const coms = 1;
const mmddyyyy = new Date('April 24, 2000 00:00:00');
Hay que tratar de no ahorrar caracteres al nombrar estas variables. Lo que buscamos es que cada uno de estos nombres sea muy expresivo.
// mejor
const numberOfUnits = 53;
const tax = 0.15;
const comissions = 1;
const birthDate = new Date('April 24, 2000 00:00:00');
Falta de información técnica
// mal
class AbstractUser { };
class UserMixin { };
class UserImplementation { };
interface UserInterface { };
// mejor
class User { };
interface User { };
Nombres según el tipo de dato
Arrays
Para los arrays, sabemos que son una lista iterable o que sus elementos tienen algo en común.
// mal
const fruit = ['apple', 'orange', 'strewberry']
// regular
const fruitList = ['apple', 'orange', 'strewberry']
// bien
const fruits = ['apple', 'orange', 'strewberry']
// mejor
const fruitNames = ['apple', 'orange', 'strewberry']
Booleanos
Generalmente tienen dos valores (con la excepción de undefined, null), aunque esto no siempre es así y depende del lenguaje.
Para este caso se recomienda el uso de prefijos (is, has, can).
// mal
const open = true;
const write = true;
const active = true;
const fruit = false;
const notEmpty = false;
const noValues = false;
// mejor
const isOpen = true;
const canWrite = true;
const isActive = true;
const hasFruit = false;
const isEmpty = false;
const hasValues = false;
Números
Se pueden usar varias palabras, prefijos como min, max, o la palabra “of”/“total”.
// mal
const fruits = 3;
const cars = 10;
// mejor
const maxFruits = 5;
const minFruits = 1;
const totalFruits = 1;
const totalOfCars = 10;
Funciones
Tienen varias características. Deben representar acciones, generalmente nombradas con el verbo que representa la acción seguido de un sustantivo. Deben ser descriptivas y concisas. Tienen que expresar qué hacen y abstenerse de revelar la implementación.
// mal
createUserIfNotExists();
updateUserIfNotEmpty();
sendEmailIfFieldsValid();
// mejor
createUser();
updateUser();
sendEmail();
Clases
Las clases deben tener nombres de sustantivos o frases nominales, evitando nombres genéricos porque pueden hacer que las clases terminen haciendo más trabajo del que deberían.
- El nombre es lo más importante de la clase
- No deben ser demasiado genéricos
- Usar UpperCamelCase
// mal
class Manager {};
class User {};
class Data {};
class Info {};
3 preguntas para determinar/saber si es un buen nombre de clase:
- ¿Qué hace exactamente la clase?
- ¿Cómo realiza exactamente esta clase determinada tarea?
- ¿Hay algo específico sobre su ubicación?
Si algo no tiene sentido, debería eliminarse o refactorizarse.
Consejo: más palabras !== mejor nombre
// mal
class SpecialViewingCaseMonsterManagerEvents {};
Más sobre funciones
“Sabemos que estamos desarrollando código limpio cuando cada función hace exactamente lo que su nombre dice.” -Ward Cunningham
function sendEmail (toWhom: string): boolean {
// Verificar la dirección de email
// Construir el cuerpo o mensaje
// Enviar el email
// Si todo sale bien
return true;
}
Mirá el ejemplo de arriba. (Dejemos de lado internamente cómo está construida la función) la función indica claramente que quiero enviar un email a ese destinatario, y devuelve un valor booleano.
Acá podemos ver su definición, en la que tenemos que verificar un email, una pequeña porción de código bastante básica. Si no, devolvemos directamente false, y si todo está bien, entonces se construye el cuerpo, el mensaje u otras cosas, pero esto sigue siendo subjetivo.
Entonces esta función, lo que literalmente está haciendo es eso.
Verificar el correo, construir el cuerpo del mensaje que queremos enviar.
Enviar el correo y, si todo sale bien, devolver un true.
Pero veamos este otro ejercicio en el que tenemos un email así, sendEmail no recibe ningún argumento y devuelve un valor booleano.
Ok, entonces pensaría que eso no significa que la función esté mal.
Eso no es así, no es el problema.
Porque podría ser que tengas el email guardado en otro lugar, o que esté en un scope un poco más alto desde donde se puede tomar, o quizás en alguna variable de entorno.
function sendEmail (): boolean {
// Verificar que el usuario existe
// Verificar la contraseña
// Crear un nuevo email en la base de datos
// Si todo sale bien
return true;
}
Acá estamos viendo que dice “verificar si el usuario existe”. Esto no tiene mucho sentido en esta función. No esperaría ver esto acá.
La siguiente acción es “verificar contraseña”. ¿La contraseña de qué? Puede ser que estemos verificando la contraseña del email de la persona, es decir, del correo que vamos a usar para enviar el mail. Podría ser eso, pero después viene “crear una casilla de correo en la base de datos” y eso no tiene mucho sentido.
La función se llama sendEmail.
No está enviando ningún email, está funcionando como si hiciera un login o alguna otra cosa.
Entonces esto es lo que queremos decir cuando afirmamos que los nombres de las funciones tienen que hacer exactamente lo que su nombre dice. Eso es todo.
Parámetros y argumentos
Cuando estamos definiendo una función, estas variables se llaman parámetros.
function sendEmail (toWhom: string): boolean {
// Verificar la dirección de email
if (!toWhom.includes("@")) return false;
return true;
}
Por otro lado, cuando invocamos esta función, se llaman argumentos.
sendEmail('castromaciel@email.com')
Ahora, ¿por qué destacamos esto?
Bueno, porque no hay límite en la cantidad de parámetros que podemos definir.
El problema es que se recomienda limitarlo a tres. La verdad es que no es un problema en sí, pero cuando hay más de tres, las funciones se ven bastante pesadas de leer cuando tienen muchos parámetros.
Como podés ver acá:
// mal
function sendEmail(toWhom: string, from: string, body: string, subject: string, apiKey: string): boolean {
}
Todo esto que está alineado acá arriba es exactamente lo mismo que tengo acá abajo:
// mal
function sendEmail(
toWhom : string,
from : string,
body : string,
subject: string,
apiKey : string
): boolean {
}
Solo que acá está ordenado con una tabulación distinta, pero es básicamente lo mismo. Y estas líneas son literalmente iguales, solo que con mejores tabs.
Otro problema es que, cuando trabajamos con argumentos posicionales, si queremos enviar solamente la apiKey, necesariamente tenemos que enviar también los demás parámetros.
Entonces, una mejor forma de trabajar esto es enviar 3 o 1 parámetro. ¿Por qué solo un parámetro? Porque podemos hacer esto:
// mejor
interface SendEmailOptions {
apiKey : string
body : string,
from : string,
subject: string,
toWhom : string,
}
function sendEmail({
apiKey, body, from, subject, toWhom
}: SendEmailOptions): boolean {
}
Eso ayuda mucho a que sea más fácil de leer, más fácil de mantener y a que tengamos clara la relación entre cada uno de estos campos.
Hay otra recomendación también, que es que sus propiedades estén ordenadas alfabéticamente.
Otras recomendaciones
- La simplicidad es esencial.
- Las funciones deben tener un tamaño reducido.
- Funciones de una sola línea, sin generar complejidad.
- Basado en el libro Clean Code, menos de 20 líneas.
- Evitar el uso de else.
- Priorizar el uso del condicional ternario (en la medida de lo posible)
¡Mal ejemplo!
const getDeduction = ({
isAffiliate = false, isPremium = true, hasChristmasDeduction = false, amountToPay = 100
}): number => {
let result;
if (isAffiliate) {
result = amountToPay / 0.1;
} else {
if (isPremium) {
result = amountToPay / 0.2;
} else {
if (hasChristmasDeduction) {
result = amountToPay / 0.25;
} else {
result = amountToPay;
}
}
}
return result;
}
Mejor
const getDeduction = ({
isAffiliate = false, isPremium = true, hasChristmasDeduction = false, amountToPay = 100
}): number => {
if (isAffiliate) return amountToPay / 0.1;
if (isPremium) return amountToPay / 0.2;
return hasChristmasDeduction ? 0.25 : amountToPay
}