Regola
Rileva logica contraddittoria o impossibile
Codice che verifica condizioni dopo che
sono già state violate, o presuppone
stati che sono impossibili in base al flusso di controllo.
Linguaggi supportati: 45+Introduzione
La logica contraddittoria compare quando il codice verifica condizioni che si sa già essere vere o false in base al precedente flusso di controllo. Ciò accade dopo un refactoring in cui la validazione è stata riordinata, o quando gli sviluppatori aggiungono controlli difensivi senza comprendere quali garanzie esistano già. Una funzione che verifica if (user !== null) dopo aver chiamato user.email presenta una logica contraddittoria: il controllo sui valori null arriva troppo tardi. Queste impossibilità logiche indicano problemi più profondi nell'organizzazione del codice o una scarsa comprensione di ciò che ogni percorso di codice garantisce.
Perché è importante
Implicazioni di sicurezza: Una falsa validazione crea una pericolosa illusione di sicurezza. Quando i controlli di sicurezza compaiono dopo che i dati sono già stati utilizzati, gli attacchi possono sfruttare la finestra temporale precedente alla validazione. Il codice che verifica i permessi degli utenti dopo aver eseguito operazioni privilegiate non offre alcuna protezione reale, ma solo commenti fuorvianti sulla sicurezza.
Manutenibilità del codice: La logica contraddittoria suggerisce che il codice non corrisponda al modello mentale dello sviluppatore. Qualcuno ha pensato che una condizione andasse verificata ma l'ha posizionata male, oppure il codice è stato sottoposto a refactoring senza aggiornare i controlli correlati. I futuri manutentori non possono dare per scontato che la validazione esista dove necessario, il che li costringe ad analizzare intere funzioni per comprendere le garanzie effettive.
Indicatori di bug: Le condizioni impossibili raramente esistono isolatamente. Segnalano problemi più profondi, come la gestione mancante degli errori, ipotesi errate sui contratti delle funzioni o un refactoring non riuscito. Un controllo che non può mai essere eseguito spesso significa che manca un controllo diverso altrove, il quale avrebbe dovuto impedire questo stato.
Esempi di codice
❌ Non 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' };
}
Perché è errato: Il codice chiama order.items.reduce() il che genera un errore se items è null oppure undefined, e successivamente verifica se items esiste. Il controllo total < 0 è inoltre contraddittorio perché reduce restituisce sempre valori non negativi quando somma dei prezzi.
✅ 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' };
}
Perché è importante: Tutta la validazione avviene prima di utilizzare i dati, i controlli avvengono in ordine logico e le condizioni riflettono i requisiti reali. La funzione valida gli input in anticipo, quindi elabora i dati validi senza controlli ridondanti o contraddittori.
Conclusione
Posiziona la validazione prima di utilizzare i dati, non dopo. Rivedi le condizioni che sembrano difensive ma compaiono dopo che i dati sono già stati letti o modificati. Durante il refactoring, aggiorna o rimuovi la validazione correlata per mantenere la coerenza logica in tutta la funzione.

