Quanta ridondanza / robustezza dovrebbe implementare un software complesso?

11

L'obiettivo di questa domanda: alcuni software eseguono "lavoro extra" per aumentare la possibilità di un risultato "alla fine positivo / soddisfacente", nonostante uno o più errori interni nel software, che richiede un tempo di esecuzione più lungo quando si verificano tali errori. Tutto ciò accade senza la consapevolezza dell'utente se l'esito ha avuto esito positivo.

Definizione di software complesso:

  • Contiene codice scritto da (fornito da) più di 10 sviluppatori nel corso della sua durata, e non scritto nello stesso intervallo di tempo
  • Dipende da più di 10 librerie esterne, ognuna con avvertimenti
  • Un'attività software tipica (per generare un risultato richiesto dall'utente) richiede 10 o più parametri di input, in cui la maggior parte di essi ha valori predefiniti ma è configurabile se l'utente ha bisogno di controllo.
  • Soprattutto, il software che presenta la complessità appropriata relativa all'attività da eseguire, ovvero non inutilmente complicato .

Modificato: Cosa è complesso? Per favore vedi C'è una grande differenza tra Complesso e Complicato . (collegamento diretto)

Definizione di ridondanza / robustezza all'interno di questa domanda :
(Aggiunto robustezza basata sui commenti)

  • Se un'attività software non è riuscita quando è stato utilizzato il set corrente di parametri, provare diversi parametri.
    • Ovviamente, è necessario sapere che quei parametri "diversi" utilizzano un percorso di codice diverso, che può avere un risultato diverso (si spera meglio).
    • A volte questi diversi percorsi di codice vengono scelti in base alle osservazioni delle librerie esterne.
  • Al termine, se l'attività effettiva eseguita è leggermente diversa dalle specifiche dell'utente, l'utente riceverà un rapporto che descrive la discrepanza.
  • Infine, come i 10 parametri configurabili, anche la ridondanza e il reporting sono configurabili.

Esempio di tale software:

  • Migrazione del database
    • Database aziendale
    • Database di controllo del codice sorgente, ecc.
  • Conversione batch tra un documento Word e un documento OpenOffice, PowerPoint e OpenOffice Draw, ecc.
  • Traduzione automatica di un intero sito web
  • Analisi automatica del pacchetto software, come Doxygen, ma dove l'analisi deve essere più affidabile (vale a dire non solo uno strumento di documentazione)
  • Comunicazione di rete, in cui i pacchetti potrebbero andare persi e si prevede un numero di tentativi

Questa domanda è stata originariamente ispirata da Come fare hai a che fare con codice intenzionalmente cattivo? , ma ora si concentra solo su una delle cause dell'abbassamento del software. Questa domanda non affronta altre cause del software gonfiato, come l'aggiunta di nuove funzionalità.

Probabilmente correlato:

posta rwong 17.11.2010 - 08:18
fonte

5 risposte

7

Questa è una domanda aziendale, non tecnica.

A volte sto codificando con i ricercatori o su un prototipo, quindi costruiremo qualcosa con una robustezza molto bassa. Se si rompe, lo aggiustiamo. Non ha senso investire nella magia extra se stiamo per buttare via il codice al più presto.

Ma se gli utenti del tuo sistema ne hanno bisogno per essere robusti, dovresti costruirlo in questo modo. E dovresti renderlo robusto nello specifico in cui tu e loro avete bisogno di massimizzare il successo a lungo termine, ignorando i tipi di ridondanza / solidità di cui non hanno bisogno.

In genere, inizio in modo approssimativo e quindi aggiungo robustezza nel tempo. Faccio spesso domande come questa parte del normale processo di pianificazione. Generalmente lavoro nello stile di programmazione Extreme, dove facciamo una lunga lista di funzionalità desiderate, e metto le caratteristiche di robustezza anche lì. Ad esempio, "Il sistema sopravvive al fallimento di ogni singola casella", si mescola con cose come "L'utente può aderire usando le credenziali di Facebook". Prima di tutto, prima costruisco.

    
risposta data 17.11.2010 - 19:13
fonte
5

Un software complesso tipicamente è ridondante come probabilmente sapete, ma ovviamente non perché è il modo migliore per farlo, ma perché gli sviluppatori tendono a "virare" sul codice esistente piuttosto che tentare di capire in modo molto dettagliato come funziona il software.

Tuttavia, se mi chiedessi quanta ridondanza dovrebbe essere accettabile, direi assolutamente nessuno. La ridondanza è uno dei tanti effetti collaterali della complessità, l'arcnemesi della semplicità. Probabilmente, la semplicità dovrebbe passare in secondo piano se il tempo è di maggiore importanza, anche se sottolineo che coloro che sostengono che il tempo è essenziale sono raramente quelli che effettivamente si occupano dello sviluppo del software. Di solito il tuo project manager ti spinge a finire il lavoro il prima possibile in modo da poter tornare ai problemi più urgenti, tuttavia è un tuo dovere come programmatore sapere quando il lavoro è finito. Penso che il lavoro non sia finito finché non lo hai integrato con successo nel programma come doveva essere. Forse il programma è complicato, ma almeno la tua modifica si adatta al modello, rendendola piuttosto facile da capire da un programmatore abituato a vedere un codice simile.

Tuttavia, è necessario dire che, nel fare ciò, potrebbe essere necessario produrre codice ridondante. Se il progetto è già altamente ridondante, potrebbe essere più semplice continuare il modello assumendo ovviamente che il tuo capo non abbia un paio di settimane da uccidere permettendoti di ristrutturare l'intero progetto.

Modifica: Alla luce della riformulazione della domanda, aggiungerò un po 'di robustezza. A mio parere, il controllo dei parametri dovrebbe essere fatto solo se A) si accetta un formato molto specifico come un valore di data come stringa o B) vari parametri potrebbero potenzialmente entrare in conflitto tra loro o si escludono a vicenda.

Con A), i requisiti in base ai quali i parametri corrispondono a un formato specifico sono in genere fondamentali per la necessità del metodo (ad esempio una conversione in una data di una stringa). Tecnicamente potrebbe ancora accadere nel tuo programma senza che sia necessario, ma ti incoraggio vivamente a eliminare queste possibilità e ad accettare solo i parametri che sai rappresentano il tipo di dati che stai cercando (accetta una data piuttosto che una stringa se il il punto non è convertire, per esempio Se la conversione deve essere eseguita, usa un metodo di utilità per convertire la stringa prima di passarla al metodo).

Come per B), i parametri mutuamente esclusivi rappresentano una cattiva struttura. Ci dovrebbero essere due classi, una che gestisce un caso e un altro che lo gestisce in un altro modo. Tutte le operazioni comuni possono essere eseguite in una singola classe base per evitare la ridondanza.

In situazioni in cui il numero di parametri di un metodo diventa 10+, comincio a considerare un file di proprietà che contiene tutti questi parametri che molto probabilmente non cambieranno spesso. Se cambiano, è possibile salvare il valore predefinito nel file delle proprietà e aggiungere un metodo "setPropertyName ()" che consente di sovrascrivere il valore predefinito in fase di esecuzione.

    
risposta data 17.11.2010 - 12:57
fonte
3

È una cosa dei requisiti.

Esiste un requisito per la robustezza?

"Quando il collegamento di comunicazione fallisce, i pacchetti errati vengono scartati" "Quando il collegamento riprende l'operazione, nessuna transazione viene elaborata due volte"

ci dovrebbero essere casi d'uso per il recupero degli errori (altrimenti come fai a sapere come accadrà?)

Lasciare ai programmatori di inventare la robustezza mentre vanno (se necessario) si traduce in sistemi "magici".

Tutti i sistemi magici diventano magici schifosi nel tempo. La correzione degli errori in background nasconde il verificarsi di errori, in modo che i guasti non vengano corretti, quindi il sistema si degraderà in uno stato di maggiore entropia; e corro come una schifezza, poiché corregge continuamente errori. Devi avere un limite per impedire al sistema di entrare in uno stato di degrado permanente.

    
risposta data 18.11.2010 - 01:56
fonte
2

Alcune operazioni probabilmente giustificano un approccio "try-again", specialmente se dipendono da risorse esterne come un database. Ad esempio, se un database non può essere collegato a una query non riesce, l'operazione può essere ripetuta un certo numero di volte prima di abbandonare e lanciare un errore a un livello superiore. Tuttavia, in qualche logica, provare la stessa cosa più volte è spesso un sintomo di codice errato e pensiero magico che nasconde problemi reali.

    
risposta data 17.11.2010 - 19:00
fonte
2

Il software dovrebbe essere indulgente nei confronti degli errori degli utenti e completamente intollerante nei confronti degli errori del programmatore.

Significa che il software dovrebbe essere molto robusto e consentire un recupero regolare per cose come errori di input dell'utente e errori di configurazione del sistema. Per lo meno un messaggio di errore amichevole che indica dove si è verificato l'errore (casella di input, file di configurazione, argomento della riga di comando, ecc ...) e quale vincolo è stato violato ("deve essere inferiore a X caratteri", "opzioni valide sono [X , Y, Z] ", ecc ...) Per maggiore robustezza, il software può suggerire un'alternativa, o usare un ragionevole valore predefinito (ma dovrebbe sempre indicare che non sta usando esattamente ciò che l'utente ha specificato).

Non riesco a pensare a molte situazioni in cui è necessario un nuovo tentativo automatico con diverse impostazioni predefinite, ma ce ne sono alcune (il tentativo automatico di stabilire un collegamento di comunicazione sembra ragionevole). Sono d'accordo con @William sul fatto che questo livello di "ridondanza" è una decisione aziendale.

D'altra parte, non ci dovrebbe essere robustezza di runtime contro l'errore del programmatore. Se ci sono pre-condizioni per i parametri di una funzione, dovrebbero essere controllati con asserzioni, non con i controlli di runtime. È un enorme problema per me vedere il bugover ridondante che controlla e riporta sullo stesso parametro tre o quattro livelli nello stack di chiamate:

 int A(int x)
 {
   if (x==0) return -1
   ...
 }
 int B(int x)
 {
   if (x==0) return -1
   err = A(x)
   if (err) return err;
   ...
 }
 // and so on and so on....

Questa è solo una complessità aggiuntiva non necessaria. Non dovresti passare il tempo a capire come una funzione debba gestire un errore introdotto abusando di un altro. Se questo è il tipo di "robustezza" a cui ti riferisci - non ne hai bisogno. Sostituiscilo con affermazioni e test di integrazione approfonditi.

    
risposta data 17.11.2010 - 22:38
fonte

Leggi altre domande sui tag