Domanda

ho avuto una discussione con uno dei miei colleghi su come difensiva il codice dovrebbe essere. Io sono tutto pro programmazione difensiva, ma si deve sapere dove fermarsi. Stiamo lavorando su un progetto che sarà gestito da altri, ma questo non significa che dobbiamo verificare la presenza di tutte le cose folli uno sviluppatore poteva fare. Naturalmente, si potrebbe fare, ma questo verrà aggiunto un molto grande in testa al codice.

Come si fa a sapere dove tracciare la linea?

È stato utile?

Soluzione

Non so che c'è davvero un modo per rispondere a questa. E 'solo una cosa che si impara dall'esperienza. Hai solo bisogno di porsi come comune un potenziale problema rischia di essere e fare una chiamata in giudizio. Si consideri inoltre che non si fa necessariamente sono per sempre il codice sulla difensiva. A volte è accettabile solo per notare eventuali problemi nella documentazione del codice.

In definitiva però, penso che questo è solo qualcosa che una persona deve seguire la loro intuizione. Non c'è modo giusto o sbagliato per farlo.

Altri suggerimenti

Tutto ciò che un utente entra direttamente o indirettamente, si dovrebbe sempre sanity-check. Oltre a ciò, alcuni assert è qui e non ci farà male, ma non si può davvero fare molto su programmatori folli editing e rompere il vostro codice, in ogni caso -!)

Io tendo a modificare la quantità di difesa ho messo nel mio codice in base alla lingua. Oggi sto lavorando principalmente in C ++ così i miei pensieri sono alla deriva in quella direzione.

Quando si lavora in C ++ non ci può essere sufficiente la programmazione sulla difensiva. Io tratto il mio codice come se sto a guardia segreti nucleari e di ogni altro programmatore è fuori per farli. Afferma, getta, tempo compilatore hack template errore, la convalida degli argomenti, eliminando i puntatori, in revisioni del codice di profondità e la paranoia generale sono tutti gioco equo. C ++ è un linguaggio meraviglioso male che io sia l'amore e gravemente diffidenza.

Io non sono un fan del termine "programmazione difensiva". A me suggerisce codice come questo:

void MakePayment( Account * a, const Payment * p ) {
    if ( a == 0 || p == 0 ) {
       return;
    }
    // payment logic here
}

Questo è sbagliato, sbagliato, sbagliato, ma devo aver visto centinaia di volte. La funzione dovrebbe mai dovuto essere chiamato con i puntatori nulli, in primo luogo, ed è del tutto sbagliato accettarli in silenzio.

L'approccio corretto qui è discutibile, ma una soluzione minima è di fallire rumorosamente, sia utilizzando un'asserzione o un'eccezione.

Modifica Non sono d'accordo con alcune altre risposte e commenti qui - non penso che tutte le funzioni dovrebbero controllare i loro parametri (per molte funzioni questo è semplicemente impossibile). Ritengo invece che tutte le funzioni dovrebbero documentare valori accettabili e precisa che altri valori si tradurrà in un comportamento indefinito. Questo è l'approccio adottato dalle librerie di maggior successo e ampiamente utilizzati mai scritti -. La C e C ++ librerie standard

E ora lasciate che i downvotes iniziano ...

Se si sta lavorando su API pubbliche di un componente, allora vale la pena di fare una buona quantità di convalida dei parametri. Questo mi ha portato ad avere l'abitudine di fare la convalida in tutto il mondo. Quello è un errore. Tutto ciò che il codice di validazione non viene mai testato e potenzialmente rende il sistema più complicato di quanto dovrebbe essere.

Ora preferisco confermare con test di unità. Convalida avviene sicuramente per dati provenienti da fonti esterne, ma non per le chiamate da sviluppatori non esterni.

Ho sempre Debug.Assert la mia ipotesi.

La mia ideologia personale:. L'atteggiamento difensivo di un programma dovrebbe essere proporzionale al massimo ingenuità / ignoranza della base di utenti potenziali

Essendo difensiva contro gli sviluppatori di consumare il vostro codice di API non è molto diverso dall'essere difensivo contro gli utenti regolari.

  • Controllare i parametri per assicurarsi che siano entro limiti appropriati e di tipi attesi
  • Verificare che il numero di chiamate API che potrebbe essere fatto sono entro le condizioni del servizio. Generalmente chiamato la limitazione di solito si applica solo ai servizi web e le funzioni di controllo della password.

Oltre a questo non c'è molto altro da fare se non assicurarsi che la vostra applicazione recupera bene in caso di un problema e che sempre danno ampie informazioni allo sviluppatore in modo da capire cosa sta succedendo.

programmazione difensiva è solo un modo di hounouring un contratto in un di progettazione per contratto i tipi di codifica.

Gli altri due sono

  • di programmazione totale e
  • programmazione nominale.

Naturalmente non dovreste difendersi contro ogni cosa folle uno sviluppatore potrebbe fare, ma poi si dovrebbe affermare in un contesto wich che farà ciò che è previsto di utilizzare precondizioni.

//precondition : par is so and so and so 
function doSth(par) 
{
debug.assert(par is so and so and so )
//dostuf with par 
return result
}

Credo che bisogna portare in questione se si sta creando test pure. Si dovrebbe essere sulla difensiva nel vostro codice, ma come sottolineato da JaredPar - Credo anche che dipende dalla lingua che si sta utilizzando. Se si tratta di codice non gestito, allora si dovrebbe essere estremamente difensivo. Se è riuscito, credo di avere un po 'di wiggleroom.

Se hai le prove, e qualche altro sviluppatore cerca di decimare il codice, i test avrà esito negativo . Ma poi di nuovo, dipende dalla copertura di test sul vostro codice (se c'è).

provo a scrivere il codice che è più di difesa, ma in calo ostili destra. Se qualcosa va storto e posso risolvere il problema, lo farò. in caso contrario, gettare o passare l'eccezione e rendere qualcuno elses problema. Tutto ciò che interagisce con un dispositivo fisico - file system, di connessione al database, la connessione di rete deve essere considerata unereliable e incline al fallimento. anticipando questi fallimenti e li cattura è fondamentale

Una volta che avete questa mentalità, la chiave è di essere coerente nel vostro approccio. cosa si aspetta a restituire codici di stato per comminicate problemi nella catena chiamata o ti piace eccezioni. modelli misti ti ucciderà o almeno guidare a bere. pesantemente. se si utilizza qualcuno api elses, quindi isolare queste cose in meccanismi che trappola / rapporto in termini che si utilizzano. utilizzare queste interfacce da imballaggio.

Se la discussione qui è come codificare difensiva contro future (possibilmente malevoli o incompetenti) manutentori, c'è un limite a quello che si può fare. contratti di far rispettare attraverso la copertura dei test e l'uso liberale di affermare la tua ipotesi è probabilmente la migliore che si può fare, e dovrebbe essere fatto in modo che idealmente non ingombrare il codice e rendere il lavoro più difficile per i futuri manutentori non male del codice. Afferma sono facili da leggere e capire e far capire quali sono i presupposti di un dato pezzo di codice è, quindi sono di solito una grande idea.

Codifica difensiva contro le azioni degli utenti è un altro problema del tutto, e l'approccio che uso è quello di pensare che l'utente è fuori per me. Ogni ingresso viene esaminata con la massima attenzione posso gestire, ed io fare ogni sforzo per avere il mio codice fail-safe - cercare di non persistere uno stato che non sia rigorosamente controllati, corretta dove è possibile, uscire con grazia se non è possibile, ecc Se basta pensare a tutte le cose Bozo che potrebbero essere perpetrati sul vostro codice da agenti esterni, che si ottiene nella mentalità giusta.

Codifica difensiva contro altri codici, come il tuo piattaforma o altri moduli, è esattamente lo stesso di utenti: sono fuori di farti. Il sistema operativo sta andando sempre scambiare il tuo thread in un momento inopportuno, le reti sono sempre intenzione di andare via al momento sbagliato, e, in generale, il male abbonda dietro ogni angolo. Non è necessario codificare contro ogni potenziale problema là fuori - il costo per la manutenzione potrebbe non valere la pena l'aumento della sicurezza - ma di sicuro non fa male a pensarci. E di solito non fa male a commentare in modo esplicito nel codice se c'è uno scenario pensato a riguardo, ma come irrilevante per qualche motivo.

I sistemi dovrebbero hanno ben disegnato i confini in cui il controllo sulla difensiva accade. Ci dovrebbe essere una decisione su dove viene convalidato l'input dell'utente interazione del motore (a ciò che di confine), e dove altri potenziali problemi difensivi richiedono il controllo (ad esempio, il terzo punto di integrazione del partito, pubblicamente API disponibili, le regole, o diverse unità codificati da differenti team di programmatori ). controllo più difensivo rispetto a quello viola DRY in molti casi, e aggiunge solo costi di manutenzione per molto poco benifit.

Detto questo, ci sono alcuni punti in cui non si può essere troppo paranoico. Potenziale di buffer overflow, corruzione dei dati e problemi simili dovrebbe essere molto rigoroso difendeva.

Recentemente ho avuto scenario, in cui i dati di input dell'utente è stato propagato attraverso l'interfaccia remota facciata, l'interfaccia facciata quindi locale, poi qualche altra classe, per arrivare infine al metodo in cui è stato effettivamente utilizzato. Mi è stato chiesto il mio io una domanda: Quando dovrebbe essere il valore convalidato ho aggiunto il codice di convalida solo alla classe finale, dove il valore è stato effettivamente utilizzato. Aggiunta di altri frammenti di codice di convalida delle classi che sul percorso di propagazione sarebbe troppo programmazione difensiva per me. Un'eccezione potrebbe essere la facciata a distanza, ma ho saltato troppo.

Buona domanda, ho Flip flop tra il fare controlli di integrità e non facendo loro. Il suo un 50/50

situazione, probabilmente sarei preso una via di mezzo in cui mi sarebbe solo "Bullet Proof" qualsiasi routine che sono:

(a) Chiamato da più di un posto nel progetto

(b) ha la logica che è destinata a cambiare

(c) Non è possibile utilizzare i valori di default

(d) la routine non può essere 'non riuscita' graziosamente

Darknight

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top