Clase 8 - Patrones de código limpio
🧼 Clean Code en JavaScript
📛 Nombres de variables y funciones
❌ Ejemplo muy malo
// SCREAMING_SNAKE_CASE// PascalCase// camelCase// kebab-case// snake_caseconst SelectedUser = 'Juan';const fnu = true;const array = ['Juan', 'Pedro', 'Luis'];const obj = { name: 'Juan', role: 'Admin' };
d.user(obj);✅ Buena práctica aplicada
const selectedUser = 'Juan';const foundUser = false;const users = ['Juan', 'Pedro', 'Luis'];const userData = { name: 'Juan', role: 'Admin' };
database.showUserData(userData);✅ Se usan nombres significativos, en minúscula camelCase y con funciones descriptivas.
🧴 Evitar jergas y abreviaturas poco claras
❌ Ejemplo muy malo
user.enterToTheSystem(); // Jerga innecesariasave(x); // Abreviación ambiguaallUsers = users.filter((user) => user.role == 'Admin'); // Falta claridad✅ Buena práctica aplicada
user.login();save(userData);filteredAdminUsers = users.filter((user) => user.role === 'Admin');✅ Funciones con nombres claros y directos, sin jerga técnica ambigua.
🧱 Evitar información redundante
❌ Ejemplo muy malo
const petWithOwner = new Pet('Haru', 'Santiago');
const person = { personName: 'Juan', personLastName: 'Pérez', personAge: 53, personCountry: 'Argentina',};✅ Buena práctica aplicada
const pet = new Pet('Haru', 'Santiago');
const person = { name: 'Juan', lastName: 'Pérez', age: 53, country: 'Argentina',};✅ Se eliminan prefijos innecesarios. El contexto ya es claro por la estructura de datos.
📉 Mantener bajo el número de argumentos
❌ Ejemplo muy malo
const getBooksPublished = (author, genre, startDate, endDate) => { // ...};✅ Buena práctica aplicada
const getBooksPublished = ({ author, genre, startDate, endDate }) => { // ...};✅ Mejora la legibilidad y el orden usando un solo parámetro como objeto.
⚡ Short Circuit Evaluation
El uso de operadores lógicos && y || para evaluar condiciones y ejecutar código de forma concisa.
❌ Ejemplo muy malo
// Código verboso con bloques if innecesariosfunction logUserData(user) { if (user) { console.log(user); }}
function getElementStyle(element) { if (element.style) { return element.style; } else { return {}; }}✅ Buena práctica aplicada
// Short circuit con &&function logUserData(user) { user && console.log(user);}
// Short circuit con ||function getElementStyle(element) { return element.style || {};}✅ Código más conciso y directo sin bloques condicionales excesivos.
⚙️ Nullish Coalescing Operator
El operador de fusión nula ?? es un operador lógico que devuelve su operando del lado derecho cuando su operando del lado izquierdo es null o undefined, y de lo contrario devuelve su operando del lado izquierdo.
❌ Ejemplo muy malo
// Puede causar comportamientos inesperados con valores "falsy" pero válidosfunction greet(name) { const userName = name || 'Guest'; // '' se convierte en 'Guest' return `Hello, ${userName}!`;}
const count = data.count || 10; // 0 se convierte en 10✅ Buena práctica aplicada
function greet(name) { const userName = name ?? 'Guest'; // Solo si name es null o undefined return `Hello, ${userName}!`;}
const count = data.count ?? 10; // Mantiene 0 como un valor válido✅ Respeta valores falsy válidos como
'',0ofalse.
🔗 Optional Chaining
El operador de encadenamiento opcional ?. permite leer el valor de una propiedad ubicada dentro de una cadena de objetos conectados sin tener que validar expresamente cada referencia en la cadena.
❌ Ejemplo muy malo
// Anidamiento excesivo y propenso a erroresfunction getUserCity(user) { if (user && user.address && user.address.city) { return user.address.city; } return 'Ciudad desconocida';}✅ Buena práctica aplicada
function getUserCity(user) { return user?.address?.city ?? 'Ciudad desconocida';}
// Ejemplo con métodosconst result = someObject?.someMethod?.();✅ Código más conciso y seguro, evitando errores de “Cannot read property of undefined”.
🔄 Evitar uso de switch
Los switch suelen generar código repetitivo y difícil de mantener. Es preferible utilizar objetos o maps.
❌ Ejemplo muy malo
function getDiscount(memberType) { switch (memberType) { case 'basic': return 5; case 'standard': return 10; case 'premium': return 15; case 'super-premium': return 25; default: return 0; }}✅ Buena práctica aplicada
// Usando un objetoconst discountRates = { basic: 5, standard: 10, premium: 15,};
function getDiscount(memberType) { return discountRates[memberType] || 0;}
// O con un Map para casos más complejosconst actionHandlers = new Map([ ['ADD', (x, y) => x + y], ['MULTIPLY', (x, y) => x * y],]);
function performAction(actionType, x, y) { const handler = actionHandlers.get(actionType) || ((x, y) => 0); return handler(x, y);}✅ Mayor escalabilidad, fácil de mantener y extender con nuevos casos.
🔀 Operador Ternario
El operador condicional (ternario) proporciona una forma concisa de escribir expresiones condicionales.
❌ Ejemplo muy malo
// Uso excesivo de if-else para asignaciones simpleslet result;if (isActive) { result = 'Active';} else { result = 'Inactive';}
// Ternarios anidados ilegiblesconst message = isLoggedIn ? isAdmin ? 'Welcome admin!' : isPremium ? 'Welcome premium user!' : 'Welcome user!' : 'Please log in';✅ Buena práctica aplicada
// Ternario simple para asignacionesconst result = isActive ? 'Active' : 'Inactive';
// Evitar ternarios anidados, mejor usar funciones o if-else cuando la lógica es complejafunction getWelcomeMessage(user) { if (!user.isLoggedIn) return 'Please log in'; if (user.isAdmin) return 'Welcome admin!'; return user.isPremium ? 'Welcome premium user!' : 'Welcome user!';}✅ Mejora la legibilidad en expresiones condicionales simples, evitando abusar del operador en casos complejos.
📐 Formatear el código
Mantener un formato consistente es esencial para la legibilidad y mantenimiento del código.
❌ Ejemplo muy malo
// Formato inconsistentefunction calculate(a, b) { const result = a + b; return result;}const users = [ { name: 'Juan', age: 30 }, { name: 'Ana', age: 25 },];if (condition) { doSomething();} else { doSomethingElse();}✅ Buena práctica aplicada
// Formato consistente con Prettier/ESLintfunction calculate(a, b) { const result = a + b; return result;}
const users = [ { name: 'Juan', age: 30 }, { name: 'Ana', age: 25 },];
if (condition) { doSomething();} else { doSomethingElse();}✅ Herramientas recomendadas:
- Prettier: Formateador automático.
- Linters: Análisis estático de código. Algunos ejemplos son ESLint o Biome.
- EditorConfig: Mantener consistencia entre editores.
🧪 Otros principios importantes
DRY (Don’t Repeat Yourself)
Evitá repetir lógica. Extraé funciones comunes.
❌ Ejemplo muy malo
function validateEmail(email) { const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return regex.test(email);}
function validateForm() { const name = document.getElementById('name').value; const email = document.getElementById('email').value;
if (!name) { showError('Nombre requerido'); return false; }
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!regex.test(email)) { showError('Email inválido'); return false; }
return true;}✅ Buena práctica aplicada
function validateEmail(email) { const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return regex.test(email);}
function validateRequired(value) { return value.trim() !== '';}
function validateForm() { const name = document.getElementById('name').value; const email = document.getElementById('email').value;
if (!validateRequired(name)) { showError('Nombre requerido'); return false; }
if (!validateEmail(email)) { showError('Email inválido'); return false; }
return true;}SRP (Single Responsibility Principle)
Cada función hace una sola cosa y la hace bien.
❌ Ejemplo muy malo
function saveUser(userData) { // Validación if (!userData.name || !userData.email) { throw new Error('Faltan datos obligatorios'); }
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(userData.email)) { throw new Error('Email inválido'); }
// Formateo userData.name = userData.name.trim(); userData.createdAt = new Date();
// API call const response = fetch('/api/users', { method: 'POST', body: JSON.stringify(userData), });
// Manejo de UI if (response.ok) { showSuccessMessage('Usuario guardado'); clearForm(); } else { showErrorMessage('Error al guardar'); }}✅ Buena práctica aplicada
function validateUserData(userData) { if (!userData.name || !userData.email) { throw new Error('Faltan datos obligatorios'); }
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; if (!emailRegex.test(userData.email)) { throw new Error('Email inválido'); }
return true;}
function formatUserData(userData) { return { ...userData, name: userData.name.trim(), createdAt: new Date(), };}
async function saveUserToAPI(userData) { return fetch('/api/users', { method: 'POST', body: JSON.stringify(userData), });}
function updateUI(success) { if (success) { showSuccessMessage('Usuario guardado'); clearForm(); } else { showErrorMessage('Error al guardar'); }}
// Función orquestadoraasync function handleSaveUser(userData) { try { validateUserData(userData); const formattedData = formatUserData(userData); const response = await saveUserToAPI(formattedData); updateUI(response.ok); } catch (error) { showErrorMessage(error.message); }}KISS (Keep It Simple, Stupid)
Si algo se puede resolver de forma simple, no lo compliques.
❌ Ejemplo muy malo
// Sobrecomplejo para filtrar números paresfunction extractEvenNumbers(numbers) { const result = []; for (let i = 0; i < numbers.length; i++) { const current = numbers[i]; if (current % 2 === 0) { let alreadyIncluded = false; for (let j = 0; j < result.length; j++) { if (result[j] === current) { alreadyIncluded = true; break; } } if (!alreadyIncluded) { result.push(current); } } } return result;}✅ Buena práctica aplicada
// Solución simple y directafunction extractEvenNumbers(numbers) { return [...new Set(numbers)].filter((num) => num % 2 === 0);}💡 Tips extra
- Valida datos de entrada.
- Nombra booleanos con
isX,hasY,canZ. - Usa constantes para valores mágicos.
- Implementa manejo adecuado de errores con try/catch.
📚 Lecturas y recursos
Ejercicios
Refactorización
Analiza y resuelve el código presente en el siguiente GIST.
Diccionario - Map
Realiza la implementación de una calculadora básica con JavaScript. Para ello crea las funciones de sumar, restar, multiplicar y dividir. Utiliza un diccionario o un map para organizar el código y respeta las prácticas vistas en esta clase.