Aikido

Evitar asignaciones en condicionales: prevención de errores ocultos

Legibilidad

Regla
No coloque tareas dentro de condicionales. 
Mezclar asignación y condición lógica hace que código propenso a errores
y más difícil de de entender. Separe tareas de lógica lógicas. 

Idiomas compatibles lenguajes:** JavaScript, TypeScript, Python, PHP

Introducción

Los operadores de asignación dentro de sentencias condicionales son una fuente común de errores que los compiladores y los linters suelen pasar por alto. El error clásico es utilizar = (asignación) en lugar de == o === (comparación) en una sentencia if, pero el problema es más profundo. Incluso las asignaciones intencionadas en condicionales crean código difícil de leer, revisar y depurar. Cuando la asignación y la evaluación se producen en la misma línea, los lectores deben analizar mentalmente qué operación tiene prioridad y qué valor se está comprobando realmente.

Por qué es importante

Por qué es importante

Introducción de errores: Un error tipográfico que cambia === a = no causará un error de sintaxis, sólo cambia silenciosamente el comportamiento. La condición evalúa el valor asignado (verdadero/falso), no el resultado de la comparación.

Legibilidad del código: Los lectores esperan que las condicionales comprueben los valores, no que los modifiquen. Cuando ambas cosas ocurren simultáneamente, los responsables del mantenimiento deben saber qué variables se modifican y cuándo.

Ejemplos de códigos

❌ No conforme:

function processUser(userData) {
    if (user = userData.user) {
        console.log(`Processing user: ${user.name}`);
        return user.id;
    }
    return null;
}

function validateInput(value) {
    if (result = value.match(/^\d{3}-\d{2}-\d{4}$/)) {
        return result[0];
    }
    return false;
}

Por qué está mal: Las asignaciones dentro de los condicionales hacen que no esté claro si esto es intencionado o un error tipográfico. El primer ejemplo podría ser un error donde === era la intención, y el segundo mezcla la concordancia regex con la asignación, haciendo que el flujo de código sea difícil de seguir.

✅ Conforme:

function processUser(userData) {
    const user = userData.user;
    if (user) {
        console.log(`Processing user: ${user.name}`);
        return user.id;
    }
    return null;
}

function validateInput(value) {
    const result = value.match(/^\d{3}-\d{2}-\d{4}$/);
    if (result) {
        return result[0];
    }
    return false;
}

Por qué es importante: Separar la asignación del condicional aclara la intención. Los lectores ven inmediatamente que usuario se extrae primero y luego se comprueba. El resultado de la coincidencia regex se captura y luego se evalúa. Sin ambigüedad, sin sobrecarga cognitiva y sin errores tipográficos como = vs === se hacen evidentes.

Conclusión

Mantener las asignaciones separadas de las condicionales es una regla sencilla que evita toda una clase de errores. La sobrecarga cognitiva de analizar operaciones combinadas supera cualquier beneficio percibido de brevedad. Un código claro y explícito en el que la asignación y la evaluación son operaciones distintas mejora la legibilidad, reduce los errores y hace que la revisión del código sea más eficaz.

Preguntas frecuentes

¿Tiene alguna pregunta?

¿Qué ocurre con los casos en los que la asignación en condicionales es idiomática, como la lectura de archivos?

Incluso en lenguajes donde while (line = file.readline()) es común, las mejores prácticas modernas favorecen la separación explícita. En JavaScript, utilice protocolos iteradores: for (const línea de archivoLíneas). En Python 3.8+, el operador morsa := hace explícita la intención cuando la asignación en condicionales es realmente necesaria, pero incluso entonces, considere si declaraciones separadas serían más claras.

¿Existen implicaciones de rendimiento al separar la asignación de las condicionales?

No. Los motores JavaScript modernos optimizan ambos patrones de forma idéntica. La separación añade una declaración de variable, que tiene un coste cero en tiempo de ejecución tras la compilación. Cualquier diferencia de rendimiento percibida es insignificante comparada con la prevención de errores y los beneficios de legibilidad. Escriba primero código claro y optimice sólo cuando el perfil identifique cuellos de botella reales.

¿Cómo manejo patrones como if ((match = regex.exec(str)) !== null)?

Divídalo en dos sentencias: const match = regex.exec(str); if (match !== null). O mejor, use alternativas modernas: const match = str.match(regex); if (match). La comprobación explícita de null resulta redundante porque match() devuelve null en caso de fallo, lo cual es falso. La claridad mejora y la intención se hace obvia.

¿Qué ocurre con las asignaciones que se utilizan intencionadamente por su valor de retorno?

Intencionado no significa buena práctica. El código que se basa en valores de retorno de asignación en condicionales crea riesgos de mantenimiento. Los futuros editores podrían "arreglar" lo que parece una errata. Si es absolutamente necesario utilizar este patrón, añada un comentario explicando por qué, pero reconsidere si el código podría reestructurarse de forma más clara.

¿Se aplica esta regla a los operadores ternarios?

Sí. Evite const x = (y = getValue()) ? y : defaultValue. Esto es aún más difícil de leer que en las sentencias if. Use: const y = getValue(); const x = y ? y : defaultValue. O mejor, use coalescencia nula: const x = getValue() ?? defaultValue. Los operadores modernos existen específicamente para evitar estos patrones incómodos.

¿Cómo gestionan este patrón los linters y las herramientas de análisis estático?

La mayoría de los linters modernos marcan la asignación en condicionales por defecto o mediante configuración. Normalmente requieren paréntesis adicionales if ((x = y)) para señalar la asignación intencionada, pero esto es un olor a código. Es mejor desactivar la excepción del linter y arreglar el código correctamente. Las herramientas de análisis estático pueden detectar estos patrones durante CI/CD, evitando que lleguen a producción.

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.