Domanda Perché dovrei usare asserti?


Non ho mai avuto l'idea di affermazioni - perché dovresti mai usarle?

Voglio dire, diciamo che fossi un pilota di formula e tutti gli asseriti erano cose come cintura di sicurezza, casco, ecc.

I test (nel debug) erano tutti a posto, ma ora vogliamo fare le corse (rilascio)! Dovremmo eliminare tutta la sicurezza, perché non c'erano problemi durante il test?

Non li rimanderò mai e poi mai. Penso che la maggior parte dei ragazzi affermi che la rimozione di qualcosa di simile agli asseriti non ha mai profilato il loro codice o che gli asseriti sono stati sfollati in modo assoluto. Non ho mai visto alcun vantaggio in termini di prestazioni, in particolare per quanto riguarda la regola 80/20.

Quindi, mi manca il punto in qualche modo, o qualcuno potrebbe dirmi, perché dovrei usare asserzioni? A proposito, sto usando i test unitari.


44
2017-07-04 03:13


origine


risposte:


Innanzitutto, la differenza di prestazioni può essere enorme In un progetto, il nostro asserito ha letteralmente causato un rallentamento di 3 volte. Ma ci hanno aiutato a scoprire alcuni bug davvero fastidiosi.

Qual è esattamente il punto.

I suggerimenti sono lì per aiutarti a cogliere bug. E perché vengono rimossi nelle build di rilascio, possiamo permetterci di inserirne molti senza preoccuparci delle prestazioni. Se non sei lì per agire in realtà su asserzioni fallite, diventano inutili, quindi potremmo anche rimuoverle.

Anche prendere l'errore e lanciare un'eccezione non è davvero una soluzione. La logica del programma è imperfetta e, anche se gestiamo l'eccezione, il programma è ancora rotto.

Ciò che fondamentalmente si riduce è "Perché preoccuparsi di prendere errori che non si riescono a gestire?"

Alcuni errori devono essere rilevati durante lo sviluppo. Se superano i test e nella build di rilascio utilizzata da un cliente, il programma è solo rotto e nessuna correzione degli errori di runtime la risolverà.

Non ho mai avuto l'idea di affermazioni - perché dovresti mai usarle?

Voglio dire, diciamo che fossi un pilota di formula e tutti gli asseriti erano cose come cintura di sicurezza, casco, ecc.

Sì, questo è un buon esempio di quando non usare un assert. Queste sono cose che potrebbero effettivamente andare storte in fase di esecuzione e che devono essere controllate. Il tuo pilota di Formula 1 potrebbe dimenticare alcune precauzioni di sicurezza, e se lo fa, vogliamo fermare il tutto prima che qualcuno si faccia male.

Ma per quanto riguarda il controllo per vedere che il motore è installato? Dobbiamo controllarlo durante la gara?

Ovviamente no. Se entriamo in gara senza un motore, siamo fregati, e anche se rileviamo l'errore, è troppo tardi per fare qualcosa al riguardo.

Invece, questo è un errore che deve essere catturato durante lo sviluppo o per niente. Se i progettisti dimenticano di mettere un motore nella loro auto, hanno bisogno di rilevare questo errore durante lo sviluppo. Questa è un'affermazione. È rilevante per gli sviluppatori durante lo sviluppo, ma in seguito l'errore non deve esistere e, se lo fa, non c'è nulla che possiamo fare.

Questa è fondamentalmente la differenza. Un'eccezione è lì per aiutare l'utente, gestendo gli errori che possono essere gestiti.

Un assert è lì per aiutare tu, avvisandoti di errori che non devono mai verificarsi in primo luogo, che devono essere risolti prima del prodotto puòessere spedito Errori che non dipendono dall'input dell'utente, ma dal tuo codice che fa ciò che dovrebbe fare.

La radice quadrata di quattro deve mai valutare a tre. L'errore è semplicemente impossibile. Se si verifica, la logica del programma è appena interrotta. Non importa quanta manipolazione degli errori lo avvolgiamo, è qualcosa che deve essere catturato durante lo sviluppo o non lo è affatto. Se abbiamo usato la gestione delle eccezioni per verificare questo errore e gestirlo, cosa farà l'eccezione? Dite all'utente "il programma è fondamentalmente rotto. Non usarlo mai"?

Un'e-mail dallo sviluppatore avrebbe potuto raggiungere questo obiettivo. Perché preoccuparsi di costruirlo nel codice del programma? Questo è un esempio di un problema che semplicemente non deve verificarsi. Se lo fa, dobbiamo tornare indietro e sistemare il programma. Non sono possibili altre forme di gestione degli errori.

Ma alcuni errori, come non essere in grado di aprire un file per la lettura, lo sono possibile. Anche se potrebbe essere una brutta cosa se dovesse succedere, dobbiamo accettarlo può accadere. Quindi dobbiamo gestirlo se lo fa.

Gli asserti sono per cogliere gli errori che non possono assolutamente accadere.


37
2017-08-07 17:02



Andrew Koenig era solito avere un buona discussione filosofica sull'uso di eccezioni e affermazioni nel codice di spedizione. Alla fine, stai evitando di fare cose selvagge quando il programma si trova in uno stato irreparabilmente rotto.

Credo, quindi, che quando a   il programma scopre qualcosa che è   irrefutabilmente sbagliato con il suo interno   stato, è meglio terminare a   una volta, piuttosto che dare il suo chiamante   l'opportunità di fingere questo   niente è sbagliato.

Se ti va, penso che le eccezioni   dovrebbe essere riservato per le situazioni in   che è possibile fare qualcosa   sensato dopo aver catturato l'eccezione.   Quando scopri una condizione che tu   il pensiero era impossibile, è difficile   di 'molto su cosa potrebbe accadere   dopo.


33
2017-07-04 03:21



Da Codice completo 2: "Utilizzare la gestione degli errori per le condizioni che si prevede di verificarsi, utilizzare le asserzioni per condizioni che non dovrebbero mai verificarsi."

Un esempio comunemente citato sta verificando zero nel denominatore prima di una divisione.

Ci si aspetta che elimini le asserzioni dal codice di produzione. Sono lì durante lo sviluppo per aiutarti a cogliere gli errori.

I test unitari non sostituiscono le asserzioni.


17
2017-07-04 03:20



Perché rendono più facile il debug.

La parte del debug che richiede molto tempo è tracciare un problema dal sintomo che si nota per la prima volta all'errore nel codice. Le affermazioni ben scritte renderanno il sintomo che si nota molto più vicino al problema del codice reale.

Un esempio molto semplice potrebbe essere un bug in cui si indicizza la fine di un array e si verifica un danneggiamento della memoria che causa un arresto anomalo. Può essere necessario molto tempo per risalire dall'arresto all'operazione dell'indice non valido. Tuttavia, se hai un'asserzione accanto a quell'indice che controlla il tuo indice, allora il tuo programma fallirà proprio accanto all'errore, così sarai in grado di trovare rapidamente il problema.


7
2017-07-04 04:29



Dal tuo post, sembra che tu non sia in disaccordo con l'idea di usare asserzioni, ma piuttosto l'idea di avere asserzioni nel debug e non averle attive nella produzione.

La ragione di ciò è che quando si esegue il debug, si potrebbe volere che il processo abbia esito negativo in modo catastrofico, ovvero lanciare un'eccezione e uscire, in modo che l'errore possa essere risolto. In produzione, ciò potrebbe influenzare l'intero sistema e la condizione di errore potrebbe verificarsi solo per pochissimi casi. Quindi, in produzione si vorrebbe probabilmente registrare l'errore, ma mantenere il processo in esecuzione.

L'utilizzo delle asserzioni consente di modificare il comportamento tra debug e release.

Sono d'accordo con te sul fatto che le affermazioni non dovrebbero essere semplicemente messe a tacere nel codice di produzione: molti errori non sono esposti negli ambienti di test ed è importante sapere quando le asserzioni falliscono nella produzione.


2
2017-07-04 03:30



Ti permettono di testare le tue ipotesi. Ad esempio, supponiamo che tu volessi calcolare la velocità. Probabilmente vorrai affermare che il tuo calcolo è inferiore alla velocità della luce.

Le asserzioni sono per lo sviluppo, per assicurarti di non rovinarti.


2
2017-07-04 03:18



È un argomento controverso. Molte persone, come me, preferiscono effettivamente lasciarle in codice di produzione. Se il tuo programma andrà comunque nelle erbacce, potresti avere l'affermazione in là in modo che il tuo cliente possa almeno fornirti il ​​numero di riga e il nome del file (o qualsiasi altra informazione o azione che configuri l'asserzione da fare). Se hai lasciato l'asserzione, tutto il cliente potrebbe segnalarti "è andato in crash".

Ciò significa che probabilmente non dovresti eseguire operazioni costose nei tuoi assert test, o almeno nel profilo per vedere se causeranno problemi di prestazioni.


2
2017-07-04 04:29



Le asserzioni sono inestimabili mentre penso al refactoring. Se si desidera sostituire alogrihm1 () con algoritm2 (), è possibile averli entrambi e affermare che i risultati sono uguali. È quindi possibile gradualmente eliminare gradualmente l'algoritmo1 ()

Anche gli asserti sono utili per alcune modifiche che potresti apportare rapidamente, ma non sono troppo sicure nel contesto dello stato del sistema. Impostare le asserzioni per le ipotesi che assumi, ti aiuterà rapidamente a segnalare il problema, se esiste.

È discutibile se le asserzioni debbano essere rimosse tramite l'uso di macro o simili nel rilascio, ma questo è ciò che è stato fatto nei progetti su cui ho lavorato finora.


2
2017-07-04 05:36



Nel codice completo è una sezione che dice qualcosa di simile. Ogni volta che scrivi uno se non altro ti manchi qualcosa.

È come questo codice

int i = 1
i = i++ 

Il programmatore comune non penserà mai a cosa succede se io sono negativo nel codice successivo. C'è una leggera possibilità che il tuo codice produca un overflow e linguaggi come java salteranno da max int a min int e otterrai un numero negativo molto grande. Questi sono tutti i casi che normalmente dici. Uh questo non accadrà mai. Ma cosa sta facendo il tuo programma se succede? Quindi, se sai che c'è qualcosa che pensi non accadrà mai per testarlo o contro di esso e metti un asserito falso nella clausola else che non accadrà mai, invece di non programmare la dichiarazione else. In questo modo il tuo programma dovrebbe bloccarsi completamente nel momento in cui non sei più sicuro di quello che sta facendo. Nel codice di produzione dovrebbe esserci qualcosa di diverso dall'arresto anomalo di qualcosa come informare l'utente, il manutentore e poi uscire.

Un altro uso delle asserzioni è la progettazione basata sul contratto. Tu specifichi un contratto con la tua interfaccia e, in base alla tua posizione nel programma, asserisci il tuo input, ma molto più importa che stai affermando il tuo output due.

Sono d'accordo con te che le asserzioni disabilitate nel codice di produzione rendono le asserzioni piuttosto inutili. E le asserzioni predefinite disattivate in caso di java vm sono un rischio secondo me.


1
2017-07-04 03:34



Gli avvertimenti dovrebbero essere utilizzati solo per verificare le condizioni durante lo sviluppo che non sono necessarie durante il rilascio.

Ecco un esempio molto semplice di come l'asserzione può essere usata nello sviluppo.

A(char* p)
{
    if(p == NULL)
        throw exception;

    B(p);
    C(p);

}

B(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

C(char* p)
{
    assert(p != NULL);
    D(p);
    do stuff;
}

D(char* p)
{
    assert(p != NULL);
    do stuff;
}

Invece di chiamare "if (p == NULL) genera un'eccezione"; 5 volte, basta chiamarlo una volta così sai già che non è NULL quando inserisci B (), C () e D (). Altrimenti, un'affermazione uscirà nella fase di sviluppo perché "hai cambiato il codice!" non a causa di un "input dell'utente".

Questo può far funzionare il codice molto più velocemente nella versione di rilascio perché tutto ciò che devi fare è invocare gcc con "-DNDEBUG" in modo che tutte le asserzioni non vengano compilate e tutti i "controlli non necessari" vengano rimossi nell'eseguibile.


1
2017-07-13 00:36