Aikido

Cómo mantener las funciones concisas: escribir código mantenible

Legibilidad

Regla

Mantenga funciones concisas.
Las funciones largas funciones son difíciles de entender, prueba, y mantener.

Idiomas compatibles: 45+

Introducción

Las funciones que abarcan cientos de líneas mezclan múltiples responsabilidades, lo que dificulta la comprensión de lo que hace la función sin leer cada línea. Las funciones largas suelen manejar múltiples aspectos, como la validación, la lógica de negocio, la transformación de datos y la gestión de errores, todo en el mismo sitio. Esto viola el principio de responsabilidad única y crea código difícil de probar, depurar y modificar sin romper el comportamiento existente.

Por qué es importante

Mantenimiento del código: Las funciones largas obligan a los desarrolladores a tener más contexto en la cabeza para entender el comportamiento. Si se modifica una parte, se corre el riesgo de romper otra, ya que toda la lógica está entrelazada. Las correcciones de errores son arriesgadas, ya que es difícil predecir los efectos secundarios no deseados.

Complejidad de las pruebas: Probar una función de 200 líneas significa cubrir todas las posibles rutas de código en una prueba, lo que requiere una configuración compleja y numerosos casos de prueba. Las funciones más pequeñas pueden probarse de forma independiente con pruebas unitarias específicas, lo que agiliza las suites de pruebas y las hace más fiables.

Ejemplos de códigos

❌ No conforme:

async function processOrder(orderData) {
    if (!orderData.items?.length) throw new Error('Items required');
    if (!orderData.customer?.email) throw new Error('Email required');
    const subtotal = orderData.items.reduce((sum, item) => 
        sum + (item.price * item.quantity), 0);
    const tax = subtotal * 0.08;
    const total = subtotal + tax + (subtotal > 50 ? 0 : 9.99);
    const order = await db.orders.create({
        customerId: orderData.customer.id,
        total: total
    });
    await emailService.send(orderData.customer.email, `Order #${order.id}`);
    await inventory.reserve(orderData.items);
    return order;
}

Por qué está mal: Esta función maneja la validación, el cálculo, las operaciones de base de datos, el correo electrónico y el inventario. Las pruebas requieren simular todas las dependencias. Cualquier cambio en la lógica fiscal o la validación requiere modificar toda esta función.

✅ Conforme:

function validateOrder(orderData) {
    if (!orderData.items?.length) throw new Error('Items required');
    if (!orderData.customer?.email) throw new Error('Email required');
}

function calculateTotal(items) {
    const subtotal = items.reduce((sum, item) => 
        sum + (item.price * item.quantity), 0);
    return subtotal + (subtotal * 0.08) + (subtotal > 50 ? 0 : 9.99);
}

async function createOrder(customerId, total) {
    return await db.orders.create({ customerId, total });
}

async function processOrder(orderData) {
    validateOrder(orderData);
    const total = calculateTotal(orderData.items);
    const order = await createOrder(orderData.customer.id, total);
    
    // Non-critical operations in background
    emailService.send(orderData.customer.email, `Order #${order.id}`).catch(console.error);
    
    return order;
}

Por qué es importante: Cada función tiene una responsabilidad clara. validarPedido() y calcularTotal() pueden probarse independientemente sin mocks. crearOrden() aísla la lógica de la base de datos. Las operaciones de correo electrónico e inventario no bloquean la creación de pedidos, y los fallos se gestionan por separado.

Conclusión

Haga evolucionar las API mediante cambios aditivos: añada nuevos campos, nuevos puntos finales o parámetros opcionales. Cuando los cambios de última hora sean inevitables, utilice el control de versiones de la API para ejecutar simultáneamente versiones antiguas y nuevas. Deje obsoletos los campos antiguos con plazos claros y guías de migración antes de eliminarlos.

Preguntas frecuentes

¿Tiene alguna pregunta?

¿Cómo se desglosan las funciones largas?

Identificar las distintas responsabilidades dentro de la función. Extraer la validación en funciones separadas. Extraer los cálculos en funciones puras. Trasladar las operaciones de E/S (base de datos, llamadas a la API) a sus propias funciones. Cada función extraída debe tener un propósito claro y único con un nombre descriptivo.

¿Las funciones pequeñas no añaden sobrecarga y perjudican el rendimiento?

Los compiladores e intérpretes modernos incorporan pequeñas funciones, eliminando la sobrecarga de llamadas. El impacto en el rendimiento es insignificante en comparación con las ventajas de mantenimiento. Perfile antes de optimizar. El código legible es más fácil de optimizar después, cuando se identifican los cuellos de botella reales.

¿Qué ocurre con las funciones con muchos pasos secuenciales?

Los pasos secuenciales sugieren un flujo de trabajo que puede dividirse en funciones más pequeñas. Cree funciones de ayuda para cada paso y llámelas en secuencia desde una función coordinadora. Esto hace que el flujo de trabajo sea legible y que cada paso se pueda probar de forma independiente.

¿Cómo se gestionan las funciones que necesitan muchos parámetros después de la extracción?

Pasar objetos que contengan parámetros relacionados en lugar de largas listas de parámetros. O considere si las funciones extraídas deben ser métodos de una clase que contenga estado compartido. Si una función necesita más de 6 parámetros, puede indicar una mala abstracción o que faltan estructuras de datos.

¿Debo extraer funciones aunque sólo se llamen una vez?

Sí, si la extracción mejora la legibilidad. Una función extraída bien nombrada documenta lo que hace un bloque de código mejor que los comentarios. La extracción puntual es valiosa cuando aclara la lógica compleja o reduce los niveles de anidamiento en la función padre.

Asegúrese gratis

Proteja el código, la nube y el tiempo de ejecución en un sistema central.
Encuentre y corrija vulnerabilidades de forma rápida y automática.

No requiere tarjeta de crédito | Escanea resultados en 32segs.