Tabla de Contenidos
Estilo y nombrado
Sección perteneciente al curso Clean Code aplicado para desarrollos limpios y rentables
Claridad con el menor esfuerzo
Si programamos para otras personas, tenemos que facilitar lo más posible el entendimiento de lo que hayamos escrito.
“Hay dos cosas difíciles en Informática: invalidar la caché y nombrar las cosas” – Phil Karlton
- Estilo y orden
- Tamaños y límites
- Definir con sustantivos: conceptos con los que tratamos
- Acciones con verbos: manipulación de los conceptos.
“El tiempo dedicado a la lectura es muy superior al de la escritura. Leemos código antiguo para escribir código nuevo. Facilitar la lectura facilita la escritura” – Robert C. Martin
Estilo y orden
“Cada línea de código debe parecer escrita por la misma persona, sin importar el número de participantes”.
Hay una serie de convenciones que hace que el código nos resulte agradable.
Características objetivas:
- Sencillez
- Armonía
- Repetición
Belleza horizontal:
- Sangría y llaves en bloques
- Tamaño de las líneas
Belleza vertical:
- Orden de las variables o propiedades
- Orden de las funciones o métodos
- revelador: públicos (al principio del fichero) → privados (al final)
- newsletter / periódico: público → privados (métodos que dan soporte al método público) → público → privados
Belleza interna:
- Separadores de listas e instrucciones
- Espacios en las expresiones:
- alrededor de los paréntesis
- alrededor de los operadores
- Delimitadores de cadenas
“Cuántas líneas en blanco seguidas realmente necesitas”
Tamaños y límites
Homogéneo, sin sobresaltos.
“No me gusta usar las barras de desplazamiento para leer tu código”.
Las reglas se basan en 3 principios casi psicológicos:
- Decisión: vamos a establecer reglas (reunión de equipo).
- Opción: vamos a fijar valores razonables.
- Sentido: vamos a incumplirlas… pero a sabiendas.
“Define unas reglas y haz que se cumplan señalando lo que es incorrecto”.
Límites:
- 80 - 120 caracteres por línea
- 1 - 2 líneas en blanco seguidas
- 100 - 200 líneas por fichero
Consistencia:
- Mejor ser consistente con pocas normas…
- … que cambiar de norma constantemente
Evita conflictos trasladando la decisión a otros:
- Tabs VS spaces
- Comillas simples o dobles
- Posición de llaves, paréntesis, operadores…
Herramientas de limpieza:
- Buscar según IDE y lenguaje
Enlaces de referencia:
Definiciones con sustantivos
Expresa claramente una intención. Da sentido mediante los nombres.
Aquello con lo que trabajamos inicialmente son las variables, donde guardamos la información, el estado de nuestra aplicación.
Objetivo:
- Claridad
- Mostrar la intención
- Explicar qué vamos a almacenar
Para variables / propiedades / constantes / clases:
- Emplear siempre palabras completas y descriptivas.
- Para que sean pronunciables y corregibles ortográficamente.
- Vocabulario de entidades y propiedades de negocio.
- Sin prefijos o sufijos técnicos.
- Lo siento Harry, pero mejor sin magia.
int wtf = 42; # Not a good name
Ejemplo práctico
Partimos del siguiente código TypeScript:
export class client { regOn: Date; // ❌ complete pronounceable clientName: string; // ❌ redundant intBalance: number; // ❌ no technical prefix status = 2; // ❌ no magic number numberOfSupliedRequests: number; // ❌ same vocabulary clientOrders: object[]; // ❌ redundant processOrders(): void { this.clientOrders.forEach(o => { console.log('Start processing'); console.log('processing things'); console.log('Ended with' + o); // ❌ avoid mental mapping }); } }
Arreglado:
const ACTIVE = 2; // ✔️ Bad nouns export class Client { registeredOn: Date; // ✔️ complete pronounceable name: string; // ✔️ redundant balance: number; // ✔️ no technical prefix status = ACTIVE; // ✔️ no magic number numberOfSuppliedOrders: number; // ✔️ same vocabulary well spelled orders: object[]; // ✔️ redundant processOrders(): void { this.orders.forEach(order => { console.log('Start processing'); console.log('processing things'); console.log('Ended with' + order); // ✔️ avoid mental mapping }); } }
Acciones con verbos
Creamos un idioma para nuestro negocio.
“Expresa la lógica con verbos”.
Como queremos hacer una narrativa que exprese la intención de lo que hemos programado, necesitamos verbos para actuar. En nuestro idioma de negocio (una tienda, un blog, un videojuego…)
Objetivo: claridad, mostrar la intención.
Explica lo que vas a hacer:
- Emplear siempre verbos que indiquen una acción.
- Para que se lea como una historia.
Cortos y concretos en variables que actúan como flags: is, has, can, must
Obligatorios en funciones / métodos:
- Vocabulario para relaciones y acciones.
- Define listas permitidas para acciones comunes (y reducir así la variedad de verbos):
get,set,read,write,select,insert. - Clarifica añadiendo sustantivos, adverbios o preposiciones.
Resumen:
- Piensa en mí (en el siguiente “lector” / programador, que también puedes ser tú)
- No me sorprendas.
- No me hagas pensar.
Ejemplo práctico
Partimos del siguiente código que “huele”:
// ❌ Bad verbs export class Client { pendingOrders: boolean; //❌ boolean verbs on flag variables lastOrderDate: Date; deferPayment: boolean; //❌ boolean verbs on flag variables // // Constructor // constructor() { this.pendingOrders = false; } // ❌ show intention pending(): object[] { return []; } // ❌ good names require no comment // Gets the orders by status getOrders(status: number): object[] { console.log('Getting by ', status); return []; } // ❌ return what is expected credit(): boolean { if (this.isVIP || this.deferPayment) return true; } // ❌ same verb for same action selectLastOrder(): object { return {}; } // ❌ return what is expected isActive(): string { if (this.pendingOrders || this.isVIP) { return 'ACTIVE'; } else { return 'INACTIVE'; } } // ❌ vertical declaration order isVIP: boolean; }
Lo mejoramos:
// ✔️ Bad verbs export class Client { hasPendingOrders: boolean; //✔️ boolean verbs on flag variables lastOrderDate: Date; canDeferPayment: boolean; //✔️ boolean verbs on flag variables // ✔️ vertical declaration order isVIP: boolean; // // Constructor // constructor() { this.hasPendingOrders = false; } // ✔️ show intention getPendingOrders(): object[] { return []; } //✔️ good names require no comment // Gets the orders by status getOrdersBy(status: number): object[] { console.log('Getting by ', status); return []; } // ✔️ return what is expected hasCredit(): boolean { if (this.isVIP || this.canDeferPayment) return true; } // ✔️ same verb for same action getLastOrder(): object { return {}; } // ✔️ return what is expected getActiveStatus(): string { if (this.hasPendingOrders || this.isVIP) { return 'ACTIVE'; } else { return 'INACTIVE'; } } }
