Cosa definisce un codice robusto?

40

Il mio professore continua a riferirsi a questo esempio di Java quando parla di codice "robusto":

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Afferma che "codice robusto" significa che il tuo programma tiene conto di tutte le possibilità e che non esiste un errore - tutte le situazioni sono gestite dal codice e risultano in uno stato valido, da qui il "else".

Sono dubbioso, comunque. Se la variabile è un booleano, qual è il punto di controllo di un terzo stato quando un terzo stato è logicamente impossibile?

"Non avere nulla come un errore" sembra ridicolo; anche le applicazioni di Google mostrano gli errori direttamente all'utente invece di inghiottirli silenziosamente o in qualche modo considerarli come uno stato valido. Ed è bello - mi piace sapere quando qualcosa va storto. E sembra proprio l'affermazione di dire che un'applicazione non avrebbe mai avuto errori.

Quindi qual'è la effettiva definizione di "codice robusto"?

    
posta Lotus Notes 27.08.2011 - 00:17
fonte

10 risposte

33

what is the point of checking a third state when a third state is logically impossible?

Che dire di un Boolean? che consente uno stato NULL che non è né vero né falso. Ora, cosa dovrebbe fare il software? Alcuni software devono essere altamente resistenti agli urti come i pacemaker. Hai mai visto qualcuno aggiungere una colonna a un database che era Boolean e inizializzare i dati correnti inizialmente a NULL ? So di averlo visto.

Ecco alcuni link che descrivono cosa significa essere robusti in termini di software:

Se pensi che ci sia una definizione universalmente condivisa di "robusto" qui, buona fortuna. Ci possono essere alcuni sinonimi come a prova di bomba o a prova di idiota. Il Duct Tape Programmer sarebbe un esempio di qualcuno che di solito scrive codice robusto almeno nella mia comprensione dei termini.

    
risposta data 27.08.2011 - 00:33
fonte
11

Per motivi di discussione, un Bool può avere 2 stati, Vero o Falso. Qualsiasi altra cosa è non conforme alle specifiche di programmazione langugae. Se la tua catena di strumenti non è conforme alle sue specifiche, tieni un hosed indipendentemente da ciò che fai. Se uno sviluppatore ha creato un tipo di Bool con più di 2 stati, è l'ultima cosa che avrebbe mai fatto sul mio codice base.

Opzione A.

if (var == true) {
    ...
} else if (var == false) {
    ...
} else {
    ...
}

Opzione B

if (var == true) {
    ...
} else {
    ...
}

Asserisco che l'opzione B è più solida .....

Qualsiasi twit può dirti di gestire errori imprevisti. Di solito sono banalmente facili da rilevare una volta che li si pensa. L'esempio che il tuo professore ha dato non è qualcosa che potrebbe accadere, quindi è un esempio molto povero.

A è impossibile da testare senza cablaggi test complicati. Se non riesci a crearlo, come lo testerai? Se non hai testato il codice, come sai che funziona? Se non sai che funziona, allora non stai scrivendo un software robusto. Penso che lo chiamino ancora Catch22 (Grande film, guardalo qualche volta).

L'opzione B è banale da testare.

Problema successivo, chiedi al tuo professore questa domanda "Che cosa vuoi che faccia io a riguardo se un booleano non è né vero né falso?" Ciò dovrebbe portare ad una discussione molto interessante .....

La maggior parte dei casi, un core dump è approriate, nel peggiore dei casi infastidisce l'utente o costa un sacco di soldi. Cosa succede se, ad esempio, il modulo è il sistema di calcolo del rientro in tempo reale dello Space Shuttle? Qualsiasi risposta, non importa quanto imprecisa, non può essere peggio di abortire, che ucciderà gli utenti. Quindi, cosa fare, se sai che la risposta potrebbe essere sbagliata, vai per il 50/50, o abortisci e vai al 100% di fallimento. Se fossi un membro dell'equipaggio, prenderei il 50/50.

L'opzione A mi uccide L'opzione B mi dà una possibilità di sopravvivenza.

Ma aspetta - è una simulazione del rientro dello space shuttle - e poi? Annuncia perché tu lo sappia. Sembra una buona idea? - NOT - perché è necessario testare il codice che si prevede di spedire.

L'opzione A è migliore per la simulazione, ma non può essere implementata. È inutile L'opzione B è il codice distribuito in modo che la simulazione funzioni come i sistemi live.

Diciamo che questa era una preoccupazione valida. La soluzione migliore sarebbe isolare la gestione degli errori dalla logica dell'applicazione.

if (var != true || var != false) {
    errorReport("Hell just froze over, var must be true or false")
}
......
if (var == true){
 .... 
} else {
 .... 
}

Futher reading - Macchina Xray Therac-25, guasto di Ariane 5 Rocket e altri (Link ha molti link non funzionanti ma sufficienti informazioni che Google ti aiuterà)

    
risposta data 27.08.2011 - 10:34
fonte
9

In realtà il tuo codice non è più robusto ma MENO robusto. L'ultimo else è semplicemente un codice morto che non puoi testare.

Nei software critici come i veicoli spaziali, il codice morto e il codice più in generale non testato è vietato: se un raggio cosmico produce un singolo evento sconvolto che a sua volta rende attivo il tuo codice morto, tutto è possibile. Se SEU attiva una porzione di codice robusto, il comportamento (inaspettato) rimane sotto controllo.

    
risposta data 27.08.2011 - 14:11
fonte
7

Penso che il professore potrebbe confondere "errore" e "bug". Il codice robusto dovrebbe certamente avere pochi / nessun bug. Un codice robusto può, e in un ambiente ostile, deve avere una buona gestione degli errori (che si tratti di gestione delle eccezioni o test di stato di ritorno rigoroso).

Sono d'accordo sul fatto che l'esempio di codice del professore sia sciocco, ma non così sciocco come il mio.

// Assign 3 to x
var x = 3;
x = 3;   // again, just for sure
while (x < 3 or x > 3) { x = 3; }  // being robust
if (x != 3) { ... }  // this got to be an error!
    
risposta data 27.08.2011 - 03:00
fonte
5

Non esiste una definizione concordata di Codice robusto , poiché molte cose nella programmazione sono più o meno soggettive ...

L'esempio fornito dal tuo professore dipende dalla lingua:

  • In Haskell, un Boolean può essere True o False , non esiste una terza opzione
  • In C ++, un bool può essere true , false , o (sfortunatamente) provengono da un cast dubbia che lo ha messo in un caso sconosciuto ... Questo dovrebbe non accadere , ma può, come risultato di un errore precedente.

Tuttavia, ciò che consiglia il tuo professore oscura il codice introducendo una logica estranea per eventi dovrebbe-non-accadere nel mezzo del programma principale, quindi ti indicherò, invece, verso Programmazione difensiva .

Nel caso dell'università, potresti addirittura aumentarlo adottando una strategia Design by Contract:

  • Stabilisci invarianti per le classi (ad esempio, size è il numero di elementi nell'elenco data )
  • Stabilisci pre-condizioni e post-condizioni per ogni funzione (ad esempio, questa funzione può essere invocata solo se a è inferiore a 10 )
  • Prova ciascuno di quelli nei punti di ingresso e di uscita di ciascuna delle tue funzioni

Esempio:

class List:
  def __init__(self, items):
    self.__size = len(items)
    self.__data = items

  def __invariant(self):
    assert self.__size == len(self.__data)

  def size(self):
    self.__invariant()

    return self.__size

  def at(self, index):
    """index should be in [0,size)"""
    self.__invariant()
    assert index >= 0 and index < self.__size

    return self.__data[index]

  def pushback(self, item):
    """the subsequent list is one item longer
       the item can be retrieved by self.at(self.size()-1)"""
    self.__invariant()

    self.__data.append(item)
    self.__size += 1

    self.__invariant()
    assert self.at(self.size()-1) == item
    
risposta data 27.08.2011 - 14:28
fonte
2

L'approccio del tuo professore è totalmente fuorviante.

Una funzione, o solo un po 'di codice, dovrebbe avere una specifica che dice quello che fa, che dovrebbe coprire ogni possibile input. E il codice dovrebbe essere scritto in modo tale che il suo comportamento sia garantito per corrispondere alle specifiche. Nell'esempio, scriverei le specifiche abbastanza semplici in questo modo:

Spec: If var is false then the function does "this", otherwise it does "that". 

Quindi scrivi la funzione:

if (var == false) dothis; else dothat; 

e il codice soddisfa le specifiche. Quindi il tuo professore dice: Cosa succede se var == 42? Guarda le specifiche: dice che la funzione dovrebbe fare "quello". Guarda il codice: la funzione fa "quello". La funzione soddisfa le specifiche.

Laddove il codice del tuo professore rende le cose totalmente inefficaci è il fatto che con il suo approccio, quando var non è né vero né falso, eseguirà codice che non è mai stato chiamato prima e che è completamente non testato, con risultati assolutamente imprevedibili.

    
risposta data 16.05.2015 - 21:45
fonte
1

Sono d'accordo con l'affermazione di @ gnasher729: L'approccio del tuo professore è totalmente fuorviante.

Robusto significa che è resistente a rotture / guasti perché fa alcune ipotesi ed è disaccoppiato: è autonomo, auto-definitivo e portatile. Include anche l'adattabilità alle mutevoli esigenze. In una parola, il tuo codice è duraturo .

Questo in genere si traduce in brevi funzioni che ottengono i dati dai parametri trasmessi dal chiamante e l'uso di interfacce pubbliche per i consumatori - metodi astratti, wrapper, indirezione, interfacce COM in stile, ecc. piuttosto che funzioni contenenti codice di implementazione concreto .

    
risposta data 18.09.2011 - 22:35
fonte
0

Il codice robusto è semplicemente il codice che gestisce bene i guasti. Niente di più, niente di meno.

Di errori, ci sono molti tipi: codice errato, codice incompleto, valori imprevisti, stati imprevisti, eccezioni, esaurimento delle risorse, .... Un codice robusto gestisce bene questi elementi.

    
risposta data 27.08.2011 - 15:27
fonte
0

Prenderò in considerazione il codice che hai fornito come esempio di programmazione difensiva (almeno come uso il termine). Parte della programmazione difensiva è fare delle scelte che minimizzano le ipotesi fatte sul comportamento del resto del sistema. Ad esempio, quale di questi è meglio:

for (int i = 0; i != sequence.length(); ++i) {
    // do something with sequence[i]
}

o

for (int i = 0; i < sequence.length(); ++i) {
    // do something with sequence[i]
}

(Nel caso in cui hai difficoltà a vedere la differenza, controlla il test del ciclo: il primo utilizza != , il secondo utilizza < ).

Ora, nella maggior parte dei casi, i due anelli si comporteranno esattamente nello stesso modo. Tuttavia, il primo (confrontando con != ) presuppone che i verrà incrementato una sola volta per iterazione. Se salta il valore sequence.length() , il ciclo potrebbe continuare oltre i limiti della sequenza e causare un errore.

Si può quindi argomentare che la seconda implementazione è più robusta: non dipende da ipotesi sul fatto che le modifiche del corpo del loop i (nota: in realtà continua a supporre che i non sia mai negativo).

Per motivare il motivo per cui potresti non voler fare quella ipotesi, immagina che il ciclo stia eseguendo una scansione di una stringa, eseguendo qualche elaborazione di testo. Scrivi il ciclo e tutto va bene. Ora i tuoi requisiti cambiano e tu decidi che devi supportare i caratteri di escape nella stringa di testo, così cambi il corpo del loop in modo tale che se rileva un carattere di escape (ad esempio, barra inversa), incrementa i per saltare il carattere immediatamente successivo al fuga. Ora il primo loop ha un bug perché se l'ultimo carattere del testo è backslash, il corpo del loop incrementerà i e il ciclo continuerà oltre la fine della sequenza.

    
risposta data 27.08.2011 - 20:58
fonte
-1

Personalmente descrivo un codice come "robusto" che ha questo uno, attributi importanti:

  1. Se mia madre si siede di fronte ad essa e lavora con lui, non può rompere il sistema

Ora, per interruzione, intendo che il sistema diventa instabile o causa un'eccezione UNHANDLED . Sai, a volte per un concetto semplice, puoi fare una definizione e una spiegazione complesse. Ma preferirei definizioni semplici. Gli utenti sono abbastanza bravi a trovare applicazioni robuste. Se l'utente della tua applicazione ti invia molte richieste su bug, sulla perdita di stato, su flussi di lavoro non intuitivi, ecc., Allora c'è qualcosa di sbagliato nella tua programmazione.

    
risposta data 27.08.2011 - 12:54
fonte

Leggi altre domande sui tag