work - dynamic assert




Quando le affermazioni dovrebbero rimanere nel codice di produzione? (12)

A condizione che vengano gestiti come qualsiasi altro errore, non vedo alcun problema. Tieni presente che le asserzioni fallite in C, come in altre lingue, non fanno altro che uscire dal programma, e questo di solito non è sufficiente per i sistemi di produzione.

Ci sono alcune eccezioni: PHP, ad esempio, consente di creare un gestore personalizzato per errori di asserzione in modo che sia possibile visualizzare errori personalizzati, effettuare la registrazione dettagliata, ecc. Anziché semplicemente uscire.

C'è una discussion in corso su comp.lang.c ++. Moderata sul fatto che le asserzioni, che in C ++ esistono solo nelle build di debug per impostazione predefinita, dovrebbero essere mantenute nel codice di produzione o meno.

Ovviamente, ogni progetto è unico, quindi la mia domanda qui non è tanto se le asserzioni debbano essere mantenute, ma in quali casi questo è raccomandabile / non è una buona idea.

Per asserzione, intendo:

  • Un controllo run-time che verifica una condizione che, se falsa, rivela un bug nel software.
  • Un meccanismo con il quale il programma viene fermato (forse dopo un lavoro di pulizia davvero minimo).

Non sto necessariamente parlando di C o C ++.

La mia opinione è che se sei il programmatore, ma non possiedi i dati (che è il caso della maggior parte delle applicazioni desktop commerciali), dovresti tenerli attivi, perché un'assenza fallita mostra un bug, e non dovresti andare con un bug, con il rischio di corrompere i dati dell'utente. Questo ti costringe a testare con forza prima di spedire, e rende gli insetti più visibili, quindi più facili da individuare e correggere.

Qual è la tua opinione / esperienza?

Saluti,

Carl

Vedi domanda correlata here

Risposte e aggiornamenti

Hey Graham,

Un'affermazione è un errore, pura e semplice e, pertanto, dovrebbe essere gestita come tale. Poiché un errore deve essere gestito in modalità di rilascio, non hai davvero bisogno di asserzioni.

Ecco perché preferisco la parola "bug" quando parlo di asserzioni. Rende le cose molto più chiare. Per me, la parola "errore" è troppo vaga. Un file mancante è un errore, non un bug, e il programma dovrebbe occuparsene. Cercando di dereferenziare un puntatore nullo è un bug, e il programma dovrebbe riconoscere che qualcosa odora di formaggio scadente.

Quindi, si dovrebbe testare il puntatore con un'asserzione, ma la presenza del file con il normale codice di gestione degli errori.

Leggero fuori tema, ma un punto importante nella discussione.

Come testa a testa, se le tue affermazioni irrompono nel debugger quando falliscono, perché no? Ma ci sono molte ragioni per cui un file non può esistere completamente fuori dal controllo del tuo codice: diritti di lettura / scrittura, disco pieno, dispositivo USB scollegato, ecc. Dal momento che non hai il controllo su di esso, sento che le asserzioni sono non è il modo giusto per affrontarlo.

Carl

Tommaso,

Sì, ho il codice completo e devo dire che non sono assolutamente d'accordo con quel particolare consiglio.

Supponiamo che l'allocatore di memoria personalizzato avviti e azzeri un blocco di memoria ancora utilizzato da qualche altro oggetto. Mi capita di azzerare un puntatore che questo oggetto dereferences regolarmente, e uno degli invarianti è che questo puntatore non è mai nullo, e hai un paio di asserzioni per assicurarsi che rimanga in quel modo. Cosa fai se il puntatore improvvisamente è nullo. Sei solo se () intorno ad esso, sperando che funzioni?

Ricorda, stiamo parlando del codice del prodotto qui, quindi non c'è violazione del debugger e controllo dello stato locale. Questo è un vero bug sulla macchina dell'utente.

Carl


A meno che la profilazione non dimostri che le asserzioni stanno causando problemi di prestazioni, dico che dovrebbero rimanere anche nella versione di produzione.

Tuttavia, penso che questo richieda anche che tu gestisca i fallimenti di asserzione con un po 'di grazia. Ad esempio, dovrebbero generare un tipo generale di dialogo con l'opzione di (automaticamente) riportare il problema agli sviluppatori e non solo chiudere o arrestare il programma. Inoltre, dovresti fare attenzione a non usare asserzioni per condizioni che tu concedi effettivamente, ma che probabilmente non ti piacciono o non considerano indesiderate. Tali condizioni dovrebbero essere gestite da altre parti del codice.


Il nostro software per server di database contiene sia asserzioni di produzione che di debug. Le asserzioni di debug sono proprio queste: vengono rimosse nel codice di produzione. Le asserzioni di produzione si verificano solo se (a) esiste una condizione che non dovrebbe mai esistere e (b) non è possibile recuperare in modo affidabile da questa condizione. Un'asserzione di produzione indica che è stato riscontrato un errore nel software o che si è verificata una qualche forma di danneggiamento dei dati.

Poiché si tratta di un sistema di database e stiamo memorizzando dati potenzialmente importanti per l'azienda, facciamo tutto il possibile per evitare dati corrotti. Se esiste una condizione che potrebbe causare l'archiviazione di dati errati, si asserisce immediatamente, si ripristinano tutte le transazioni e si arresta il server.

Detto questo, cerchiamo anche di evitare asserzioni di produzione in routine critiche per le prestazioni.


Il più delle volte, quando uso assertion in java (la parola chiave assert) aggiungo automaticamente alcuni codici di produzione dopo. Secondo il caso, può trattarsi di un messaggio di registrazione, un'eccezione ... o nulla.

Secondo me, tutte le tue affermazioni sono critiche nei rilasci degli sviluppatori, non nei termini di produzione. Alcuni devono essere conservati, altri devono essere scartati.


Lasciare le asserzioni attivate nel codice di produzione, a meno che tu non abbia misurato che il programma gira molto più velocemente con loro disattivati.

se non vale la pena misurare per dimostrare che è più efficiente, allora non vale la pena sacrificare la chiarezza per una scommessa sulle prestazioni. "- Steve McConnell 1993

http://c2.com/cgi/wiki?ShipWithAssertionsOn


Le asserzioni non dovrebbero mai rimanere nel codice di produzione. Se una particolare affermazione sembra possa essere utile nel codice di produzione, allora non dovrebbe essere un'affermazione; dovrebbe essere un controllo dell'errore di run time, cioè qualcosa di codificato come questo: if( condition != expected ) throw exception .

Il termine 'asserzione' ha finito per significare "un controllo solo in fase di sviluppo che non verrà eseguito sul campo".

Se inizi a pensare che le asserzioni possano arrivare in campo, allora inevitabilmente inizierai anche a fare altri pensieri pericolosi, come chiedersi se valga davvero la pena asserire. Non c'è affermazione che non valga la pena di fare. Non dovresti mai chiederti "dovrei affermarlo o no?" Dovresti solo chiedertelo "C'è qualcosa che ho dimenticato di affermare?"


Non li tengo mai in codice critico delle prestazioni.


Se stai anche pensando di lasciare delle affermazioni in produzione, probabilmente stai pensando a loro di sbagliato. Il punto centrale delle affermazioni è che puoi disattivarle in produzione, perché non fanno parte della tua soluzione. Sono uno strumento di sviluppo, utilizzato per verificare che le ipotesi siano corrette. Ma nel momento in cui entri in produzione, dovresti già avere fiducia nelle tue ipotesi.

Detto questo, c'è un caso in cui girerò le asserzioni in produzione: se incontriamo un bug riproducibile in produzione che stiamo avendo difficoltà a riprodurre in un ambiente di test, potrebbe essere utile riprodurre il bug con le asserzioni attivate in produzione, per vedere se forniscono informazioni utili.

Una domanda più interessante è questa: nella tua fase di test, quando disattivi le asserzioni?


Trovo che sia meglio gestire tutti gli errori che rientrano nello scope e utilizzare asserzioni per le assunzioni che stiamo affermando sono vere.

cioè, se il tuo programma sta aprendo / leggendo / chiudendo un file, quindi non essere in grado di aprire il file è in ambito - è una possibilità reale, che sarebbe negligente da ignorare, in altre parole. Quindi, questo dovrebbe avere il codice di controllo degli errori ad esso associato.

Tuttavia, diciamo che il tuo fopen () è documentato come sempre restituendo un handle di file aperto valido. Si apre il file e lo si passa alla funzione readfile ().

Quella funzione readfile, in questo contesto, e probabilmente in base alle sue specifiche di progettazione, può quasi presupporre che otterrà un file valido ptr. Quindi, sarebbe inutile aggiungere un codice di gestione degli errori per il caso negativo, in un programma così semplice. Tuttavia, dovrebbe almeno documentare l'ipotesi, in qualche modo, assicurare in qualche modo che questo sia effettivamente il caso, prima di continuare la sua esecuzione. Non dovrebbe in realtà assumere che sarà sempre valido, nel caso in cui sia chiamato in modo errato, o sia copiato / incollato in qualche altro programma, per esempio.

Quindi, readfile () {assert (fptr! = NULL); ..} è appropriato in questo caso, mentre la gestione degli errori in piena regola non lo è (ignorando il fatto che in realtà la lettura del file richiederebbe comunque un sistema di gestione degli errori).

E sì, quelle affermazioni dovrebbero rimanere nel codice di produzione, a meno che non sia assolutamente necessario disabilitarle. Anche allora, dovresti probabilmente disabilitarli solo all'interno di sezioni critiche per le prestazioni.


Un'affermazione è un errore, pura e semplice e, pertanto, dovrebbe essere gestita come tale.

Poiché un errore deve essere gestito in modalità di rilascio, non hai davvero bisogno di asserzioni.

Il vantaggio principale che vedo per le asserzioni è una interruzione condizionale: sono molto più facili da configurare rispetto alla perforazione attraverso le finestre di VC per impostare qualcosa che richiede 1 riga di codice.


Vedo affermazioni come test di unità in linea. Utile per un rapido test durante lo sviluppo, ma alla fine queste affermazioni dovrebbero essere rielaborate per essere testate esternamente nei test unitari.


Le asserzioni sono commenti che non diventano obsoleti. Documentano quali stati teorici sono previsti e quali stati non dovrebbero verificarsi. Se il codice viene modificato in modo che gli stati consentano il cambiamento, lo sviluppatore viene presto informato e deve aggiornare l'asserzione.