Aikido

Cómo detectar y corregir lógica contradictoria en tu código

Error lógico

Regla
Detectar contradictorio o imposible lógica
Código que comprueba las después de que 
ya violado violadas, o asume que
que son imposibles dado el flujo flujo.

Idiomas admitidos: 45+

Introducción

La lógica contradictoria aparece cuando el código verifica condiciones que ya se sabe que son verdaderas o falsas basándose en el flujo de control anterior. Esto ocurre después de una refactorización, cuando la validación se reordena, o cuando los desarrolladores añaden comprobaciones defensivas sin comprender qué garantías ya existen. Una función que comprueba if (user !== null) después de llamar user.email tiene lógica contradictoria, la comprobación de nulos llega demasiado tarde. Estas imposibilidades lógicas indican problemas más profundos con la organización del código o una comprensión deficiente de lo que garantiza cada ruta de código.

Por qué es importante

Implicaciones de seguridad: Una validación falsa crea una peligrosa ilusión de seguridad. Cuando las comprobaciones de seguridad aparecen después de que los datos ya han sido utilizados, los atacantes pueden explotar la ventana antes de que se produzca la validación. El código que valida los permisos de usuario después de ejecutar operaciones privilegiadas no proporciona protección real, solo comentarios engañosos sobre seguridad.

Mantenibilidad del código: La lógica contradictoria sugiere que el código no coincide con el modelo mental del desarrollador. Alguien pensó que una condición necesitaba ser verificada pero la colocó mal, o el código fue refactorizado sin actualizar las comprobaciones relacionadas. Los futuros mantenedores no pueden confiar en que la validación exista donde se necesita, lo que les obliga a rastrear funciones completas para entender las garantías reales.

Indicadores de errores: Las condiciones imposibles rara vez existen de forma aislada. Señalan problemas más profundos como la falta de manejo de errores, suposiciones incorrectas sobre los contratos de funciones o refactorizaciones fallidas. Una comprobación que nunca puede ejecutarse a menudo significa que falta otra comprobación en algún otro lugar que debería haber evitado este estado.

Ejemplos de código

❌ No conforme:

function processOrder(order) {
    if (!order) {
        return { error: 'Order required' };
    }

    const total = order.items.reduce(
        (sum, item) => sum + item.price,
        0
    );

    if (order.items && order.items.length > 0) {
        applyDiscount(order);
    }

    if (total < 0) {
        throw new Error('Invalid total');
    }

    return { total, status: 'processed' };
}

Por qué es incorrecto: El código llama a order.items.reduce() que se bloquea si los elementos son null o no definido, luego comprueba si los elementos existen después. El total < 0 La comprobación también es contradictoria porque la función reduce siempre devuelve valores no negativos al sumar precios.

✅ Conforme:

function processOrder(order) {
    if (!order || !order.items || order.items.length === 0) {
        return { error: 'Valid order with items required' };
    }

    const hasInvalidPrice = order.items.some(
        item => typeof item.price !== 'number' || item.price < 0
    );

    if (hasInvalidPrice) {
        throw new Error('Invalid item prices');
    }

    const total = order.items.reduce(
        (sum, item) => sum + item.price,
        0
    );

    if (order.items.length >= 5) {
        applyBulkDiscount(order);
    }

    return { total, status: 'processed' };
}

Por qué esto es importante: Toda la validación ocurre antes de usar los datos, las comprobaciones se realizan en orden lógico y las condiciones reflejan los requisitos reales. La función valida las entradas de antemano, luego procesa los datos válidos sin comprobaciones redundantes o contradictorias.

Conclusión

Coloca la validación antes de usar los datos, no después. Revisa las condiciones que parecen defensivas pero que aparecen después de que los datos ya han sido accedidos o modificados. Al refactorizar, actualiza o elimina la validación relacionada para mantener la coherencia lógica en toda la función.

Preguntas frecuentes

¿Tiene preguntas?

¿Cómo distingo la programación defensiva de la lógica contradictoria?

La programación defensiva valida las entradas en los límites de las funciones antes de su uso. La lógica contradictoria valida después del uso o comprueba condiciones ya garantizadas por código anterior. El momento y la necesidad importan. Si el usuario ya fue desreferenciado con user.email, entonces comprobar si (user) después es contradictorio, no defensivo.

¿Qué hay del type narrowing en TypeScript?

El análisis de flujo de control de TypeScript rastrea lo que es posible en cada punto. Si TypeScript permite una comprobación, la condición podría ser alcanzable. Pero JavaScript en tiempo de ejecución no impone estos tipos, por lo que aún pueden existir comprobaciones de tiempo de ejecución contradictorias a pesar de la seguridad de tipos. Concéntrate en el flujo de control en tiempo de ejecución, no solo en los tipos estáticos.

¿Puede una lógica contradictoria causar vulnerabilidades de seguridad?

Sí, cuando las comprobaciones de seguridad se realizan después de que se ejecutan operaciones privilegiadas. Comprobar permisos después de escrituras en la base de datos, validar la entrada después de la ejecución de una consulta SQL o verificar la autenticación después de exponer datos sensibles, todo ello crea vulnerabilidades de tipo 'tiempo de comprobación, tiempo de uso'. La validación debe preceder a la acción para que la seguridad sea efectiva.

¿Qué pasa con el código de manejo de errores que parece imposible?

Los manejadores de errores para excepciones que no pueden ocurrir, dada una validación previa, podrían indicar una programación excesivamente defensiva o un manejo de errores obsoleto de antes de que se añadiera la validación. Revise si cada ruta de error es realmente alcanzable. Si es imposible, elimínela para simplificar el código y evitar confundir a futuros mantenedores.

¿Cómo encuentro lógica contradictoria en el código existente?

Busca comprobaciones de validación después del acceso a datos, condiciones que siempre son verdaderas o falsas dadas ramas anteriores, y manejo de errores para estados ya prevenidos. Las herramientas de cobertura de código ayudan a identificar ramas inalcanzables. La revisión manual de los patrones de validación revela comprobaciones que ocurren demasiado tarde o prueban condiciones imposibles.

Asegúrate ahora.

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

No se requiere tarjeta de crédito | Resultados del escaneo en 32 segundos.