Sii liberale in ciò che accetti ... o no?


45

[Dichiarazione di non responsabilità: questa domanda è soggettiva, ma preferirei ricevere risposte sostenute da fatti e / o riflessioni]

Penso che tutti conoscano il principio di robustezza , di solito riassunto dalla Legge di Postel:

Sii prudente in ciò che invii; sii liberale in ciò che accetti.

Concordo sul fatto che per la progettazione di un protocollo di comunicazione diffuso ciò potrebbe avere senso (con l'obiettivo di consentire una facile estensione), tuttavia ho sempre pensato che la sua applicazione a HTML / CSS fosse un fallimento totale, ogni browser implementava il proprio tweak silenzioso rilevamento / comportamento, rendendo quasi impossibile ottenere un rendering coerente su più browser.

Noto però che lì il RFC del protocollo TCP considera accettabile "Silent Failure" se non diversamente specificato ... il che è un comportamento interessante, per non dire altro.

Ci sono altri esempi dell'applicazione di questo principio in tutto il commercio di software che compaiono regolarmente perché hanno morsi sviluppatori, dalla cima della mia testa:

  • Inserimento di punti e virgola Javascript
  • C (silenzioso) conversioni integrate (che non sarebbe così male se non si tronca ...)

e ci sono strumenti per aiutare ad attuare comportamenti "intelligenti":

Tuttavia, trovo che questo approccio, sebbene possa essere utile quando si ha a che fare con utenti non tecnici o per aiutare gli utenti nel processo di recupero degli errori, presenta alcuni svantaggi quando applicato alla progettazione dell'interfaccia libreria / classi:

  • è in qualche modo soggettivo se l'algoritmo indovina "giusto", e quindi potrebbe andare contro il principio del minimo stupore
  • rende l'implementazione più difficile, quindi maggiori possibilità di introdurre bug (violazione di YAGNI ?)
  • rende il comportamento più suscettibile al cambiamento, poiché qualsiasi modifica della routine "indovina" può rompere i vecchi programmi, quasi escludendo le possibilità di refactoring ... dall'inizio!

E questo è ciò che mi ha portato alla seguente domanda:

Quando si progetta un'interfaccia (libreria, classe, messaggio), ti inclini verso il principio di robustezza o no?

Io stesso tendo ad essere piuttosto severo, usando un'ampia convalida dell'input sulle mie interfacce, e mi chiedevo se forse ero troppo severo.


Mi chiedo qual è la differenza tra HTML e dati generali? Il principio di robustezza riguarda la comunicazione. Uno scrive - uno legge. Perché la comunicazione di rete è diversa da quella visiva o API? Ho un esempio di API in cui il principio di essere liberale in ciò che accettiamo semplifica la vita degli utenti che sono programmatori , riduce la dimensione del codice e, quindi, migliora le prestazioni + elimina i bug. Guarda stackoverflow.com/questions/18576849
Val

@Val: in realtà, il tuo esempio non corrisponde. "Essere liberali in ciò che accetti" non è solo una questione di base / derivata, va oltre e accetta (e interpreta) input leggermente errati.
Matthieu M.,

In che modo mostrare un caso non mostra quel caso?
Val

Risposte:


34

Direi robustezza quando non introduce ambiguità .

Ad esempio: quando si analizza un elenco separato da virgole, se c'è o meno uno spazio prima / dopo la virgola non cambia il significato semantico.

Quando analizza una guida di stringa, dovrebbe accettare qualsiasi numero dei formati comuni (con o senza trattini, con o senza parentesi graffe circostanti).

La maggior parte dei linguaggi di programmazione sono robusti con l'utilizzo di spazi bianchi. Soprattutto ovunque che non influisca sul significato del codice. Anche in Python dove gli spazi bianchi sono rilevanti, è ancora flessibile quando sei all'interno di un elenco o di una dichiarazione del dizionario.

Sono assolutamente d'accordo sul fatto che se qualcosa può essere interpretato in diversi modi o se non è chiaro al 100% cosa si intendesse, troppa robustezza può finire per essere un dolore, ma c'è molto spazio per la robustezza senza essere ambigua.


1
Sono d'accordo, la solidità quando non costa molto vale la pena.
Matthieu M.,

2
Anche l'elenco separato da virgole causa problemi, tipo di: il motore javascript di chrome e firefox sembra accettare {"key": "value",}come valido, IE no. Mi sono spesso imbattuto in questo particolare problema fino a quando non ho migliorato il mio processo di compilazione con JSlint.
keppla,

2
@keppla è un problema di implementazione piuttosto che di progettazione. Non sono sicuro che ciò sia legale dalle specifiche javascript e IE non stia seguendo, o se questa sia una "bella caratteristica" che FF e Chrome hanno aggiunto, ma in Python è specificato per essere valido e implementato come tale. Se è specificato come valido e non funziona, si tratta di un'implementazione errata. Se non viene specificato, non è necessario fare affidamento su di esso (anche se per praticità, se non funziona in un browser principale, potrebbe non essere considerato nelle specifiche se non si controlla l'utente)
Davy8

7
@ Davy8: la virgola finale sembra essere illegale ( stackoverflow.com/questions/5139205/… ). Non voglio fare affidamento su questo, il mio punto è che quando un numero sufficiente di persone accetta l'input, diventa di fatto standard (perché non si nota che si tratta di un errore), che porta a qualcosa che abbiamo riscontrato in HTML: che gli errori diventare così banale che non puoi più ignorarli come input errato.
keppla,

1
@keppla, ciò dovrebbe fallire in moz e Chrome. Essendo principalmente uno sviluppatore di JS, mi fa incazzare il contrario (almeno una volta in Moz). Rende il debug più difficile, non più semplice. IE sta facendo quello che dovrebbe fare. Fail @ codice errato. HTML è una cosa. Non abbiamo bisogno di questa merda in un linguaggio di scripting. È un esempio di terribile applicazione del principio Robust, che è qualcosa in cui eccellono i venditori di browser.
Erik Reppen,

15

Sicuramente no. Tecniche come la programmazione difensiva oscurano i bug, rendendo il loro aspetto meno probabile e più casuale, il che rende più difficile la loro rilevazione e rende più difficile isolarli.

Il Codice Solido di Scrittura ampiamente sottovalutato è stato straordinario nel sottolineare ripetutamente la necessità e le tecniche di rendere i bug difficili da introdurre o nascondere. Attraverso l'applicazione dei suoi principi come "Elimina il comportamento casuale. Forza la riproduzione degli insetti". e "Cerca ed elimina sempre i difetti nelle tue interfacce". gli sviluppatori miglioreranno notevolmente la qualità del loro software eliminando l'ambiguità e gli effetti collaterali incontrollati che sono responsabili di una grande quantità di bug.


9

L'applicazione eccessiva di robustezza ti porta a indovinare ciò che l'utente voleva, il che va bene fino a quando non sbagli. Richiede anche la fiducia completamente fuorviante che i tuoi clienti non abusino della tua fiducia e creino incomprensioni casuali che sembrano funzionare, ma che non sarai in grado di supportare nella versione 2.

Una domanda eccessiva di correttezza ti porta a negare ai tuoi clienti il ​​diritto di fare piccoli errori, il che va bene fino a quando non si lamentano che le loro cose funzionano bene sul prodotto del tuo concorrente e ti dicono cosa puoi fare con il tuo standard di 5.000 pagine che ha la parola "DRAFT" è ancora scarabocchiato sulla copertina a matita, e almeno 3 esperti affermano che è fondamentalmente imperfetto, e altri 200 esperti onesti affermano di non capire appieno.

La mia soluzione personale è sempre stata la deprecazione. Li supportate, ma dite loro che stanno sbagliando e (se possibile) il percorso più semplice verso la correttezza. In questo modo, quando disattivi la funzionalità bug 10 anni dopo, hai almeno la scia di carta per affermare che "ti abbiamo avvertito che ciò potrebbe accadere".


+1 per deprecare , è davvero un concetto importante e sono sorpreso che fino ad ora sia stato trascurato.
Matthieu M.,

9

Sfortunatamente il cosiddetto "principio di robustezza" non porta alla robustezza. Prendi HTML come esempio. Molti problemi, lacrime, perdita di tempo ed energia avrebbero potuto essere evitati se i browser avessero analizzato rigorosamente HTML dall'inizio invece di provare a indovinare il significato di contenuto non valido.

Il browser dovrebbe semplicemente aver visualizzato un messaggio di errore invece di provare a risolverlo sotto le copertine. Ciò avrebbe costretto tutti i pasticceri a sistemare il loro pasticcio.


Citando me stesso (deve invecchiare): "tuttavia ho sempre pensato che la sua applicazione a HTML / CSS fosse un fallimento totale"
Matthieu M.

3
È vero, ma la stessa tolleranza ai guasti ha anche contribuito a rendere il Web così popolare.
MaR,

I venditori del browser non sono riusciti su quello. Con doctypes abbiamo avuto la possibilità di fare la nostra scelta proprio in questo senso, ma alla fine della giornata tutto finì praticamente per comportarsi allo stesso modo fino a quando non hai dichiarato qualsiasi tipo di documento. Ora pensano che una soluzione iper-complessa di regole rigorose da seguire su come affrontare il fallimento sia la soluzione? Penso che non riescano a identificare il problema.
Erik Reppen,

Stai dicendo che il fail-fast, che è l'opposto di "robusto", è più efficiente.
Val

@MaR: è così? Molto discutibile, molto più probabile che le caratteristiche fossero importanti.
Deduplicatore

6

Divido le interfacce in diversi gruppi (aggiungine altri se vuoi):

  1. quelli che sono sotto il tuo controllo dovrebbero essere severi (classi in genere)
  2. API di libreria, che dovrebbero essere anche rigorose, ma si consiglia una convalida aggiuntiva
  3. interfacce pubbliche che devono gestire ogni tipo di abuso (tipicamente protocolli, input dell'utente, ecc.). Qui la solidità dell'input paga davvero, non puoi aspettarti che tutti sistemino le loro cose. E ricorda per l'utente che sarà colpa tua se l'applicazione non funziona, non la parte che ha inviato una merda mal formattata.

L'output deve essere sempre rigoroso.


5

Penso che HTML e il World Wide Web abbiano fornito un test su larga scala del principio di robustezza e abbiano dimostrato che si tratta di un grave fallimento. È direttamente responsabile del caos confuso di quasi standard HTML concorrenti che rendono la vita miserabile per gli sviluppatori Web (e i loro utenti) e peggiora con ogni nuova versione di Internet Explorer.

Sappiamo dagli anni '50 come validare correttamente il codice. Eseguilo attraverso un parser rigoroso e se qualcosa non è sintatticamente corretto, lancia un errore e interrompi. Non passare, non raccogliere $ 200, e per amore di tutto ciò che è binario non lasciare che qualche programma per computer tenti di leggere la mente del programmatore se ha fatto un errore!

HTML e JavaScript ci hanno mostrato esattamente cosa succede quando questi principi vengono ignorati. Il miglior modo di agire è imparare dai loro errori e non ripeterli.


4
@ChaosPandion: penso che il problema non risieda in Internet Explorer stesso, ma con tutte le pagine Web non standard accettate dalle versioni precedenti e con cui ora tutti devono convivere ... e cercare di adattarsi più o meno con successo.
Matthieu M.,

5
In realtà penso che il team di IE sia nella peggiore posizione possibile di tutti gli sviluppatori di browser. Joel riassume i miei pensieri piuttosto bene .
Dean Harding,

3
Potrebbe aver reso la vita miserabile per gli sviluppatori e i progettisti, ma poi saremmo bloccati con uno standard statico in evoluzione molto lenta - dubito che il web sarebbe come se fosse stato dato ora. I veri vincitori sono stati le persone che navigavano sul web e alla fine della giornata sono le persone che contano.
FinnNk,

4
Inoltre, mentre il principio di robustezza può rendere la vita difficile agli sviluppatori Web, è difficile definire il World Wide Web (ora parte integrante di quasi tutte le principali istituzioni del pianeta) un grande GUASTO .
Deworde,

3
"Sappiamo dagli anni '50 come convalidare correttamente il codice. Eseguilo attraverso un parser rigoroso e se qualcosa non è sintatticamente corretto, lancia un errore e interrompi." Per applicare questo a uno scenario del mondo reale: se ho rovinato una singola icona all'estrema destra della mia pagina appena sotto il taglio, rinunciare a tutta la pagina è un ottimo modo per inviare qualcuno che cerca altrove, a causa di un problema che non avrebbero nemmeno notato. Sì, puoi obiettare che non avrei dovuto commettere l'errore. Ma questo presuppone piuttosto che non sono già andato dal tuo concorrente più robusto e non sto più rispondendo alle tue chiamate.
Deworde,

3

Come contrappunto all'esempio di Mason, la mia esperienza con il Session Initiation Protocol è stata che mentre stack diversi avrebbero interpretato le RFC rilevanti in modo diverso (e sospetto che ciò accada con ogni standard mai scritto), essendo (moderatamente) liberale in ciò che accetti significa che tu può effettivamente effettuare chiamate tra due dispositivi. Poiché questi dispositivi sono normali cose fisiche rispetto a software su un desktop, devi semplicemente essere liberale in ciò che accetti, o il tuo telefono non può chiamare un altro telefono di una marca particolare. Questo non fa apparire bene il tuo telefono!

Ma se stai scrivendo una biblioteca, probabilmente non hai il problema di più parti che interpretano uno standard comune in modi reciprocamente incompatibili. In tal caso, direi essere rigoroso in ciò che accetti, perché rimuove le ambiguità.

The Jargon File ha anche una storia horror su "indovinare" l'intenzione di un utente.


Storia molto divertente :) Mi rendo conto che potresti aver bisogno di più margine di manovra quando tenti di interagire con i sistemi esistenti, poiché se non funziona sarai incolpato.
Matthieu M.,

In effetti, se il telefono non funziona con la maggior parte degli altri telefoni, il telefono è difettoso .
SamB,

1
@SamB: Sostituisci male con rotto .
Deworde,

3

Hai ragione, la regola si applica ai protocolli e non alla programmazione. Se fai un refuso durante la programmazione, riceverai un errore non appena compili (o esegui, se sei uno di quei tipi dinamici). Non c'è niente da guadagnare lasciando che il computer indovini per te. A differenza della gente comune, siamo ingegneri e siamo in grado di dire esattamente cosa intendo. ;)

Quindi, quando si progetta un'API, direi di non seguire il principio di robustezza. Se lo sviluppatore commette un errore, dovrebbe scoprirlo subito. Naturalmente, se l'API utilizza dati provenienti da una fonte esterna, come un file, dovresti essere indulgente. L'utente della tua biblioteca dovrebbe scoprire i propri errori, ma non quelli di chiunque altro.

A parte questo, immagino che nel protocollo TCP sia consentito "fallimento silenzioso" perché altrimenti, se le persone ti lanciassero pacchetti malformati, verrai bombardato da messaggi di errore. È semplice protezione DoS proprio qui.


1
"Se fai un refuso durante la programmazione, riceverai un errore non appena lo compili" Ti presento i milioni di AVVISI del compilatore che un compilatore standard emetterà, pur producendo attività perfettamente eseguibili.
Deworde,

1

IMO, la robustezza è un lato di un compromesso di progettazione, non un principio "preferire". Come molti hanno sottolineato, nulla puzza come soffiare quattro ore cercando di capire dove il tuo JS è andato storto solo per scoprire il vero problema era solo un browser ha fatto la cosa giusta con XHTML Strict. Lasciava andare la pagina in pezzi quando una parte dell'HTML offerto era un disastro completo.

D'altra parte, chi vuole cercare la documentazione per un metodo che accetta 20 argomenti e insiste sul fatto che siano nello stesso ordine esatto con segnaposto di valore vuoto o nullo per quelli che si desidera saltare? Il modo altrettanto terribile robusto per affrontare quel metodo sarebbe quello di controllare ogni argomento e provare a indovinare quale fosse per cosa basato su posizioni e tipi relativi e poi fallire silenziosamente o provare a "arrangiarsi" con argomenti insignificanti.

Oppure puoi aumentare la flessibilità nel processo passando un elenco di coppie letterale / dizionario / chiave-valore oggetto e gestire l'esistenza di ogni argomento mentre ci arrivi. Per il più piccolo compromesso di perf, questa è una torta e mangia anche lo scenario.

Il sovraccarico di argomenti in modi intelligenti e coerenti con l'interfaccia è un modo intelligente per essere solidi sulle cose. Lo stesso vale per la ridondanza di cottura in un sistema in cui si presume che la consegna dei pacchetti non riesca regolarmente a essere consegnata in una rete estremamente complessa di proprietà e gestita da tutti in un campo emergente della tecnologia con un'ampia varietà di potenziali mezzi per la trasmissione.

Tollerare il fallimento degli abject, tuttavia, specialmente all'interno di un sistema che controlli, non è mai un buon compromesso. Ad esempio, ho dovuto fare un attimo di respiro per evitare di lanciarmi in un'altra domanda su come mettere JS in cima o in fondo alla pagina. Diverse persone hanno insistito sul fatto che sarebbe stato meglio mettere JS in alto perché se la pagina non si fosse caricata completamente, si avrebbe comunque potenzialmente alcune funzionalità. Le pagine a metà lavoro sono peggiori dei busti completi. Nella migliore delle ipotesi, si traducono in un maggior numero di visitatori del tuo sito presumendo giustamente che tu sia incompetente prima di scoprirlo rispetto a se la pagina danneggiata viene semplicemente rimbalzata su una pagina di errore in caso di fallimento del proprio controllo di convalida seguito da un'e-mail automatica a qualcuno che può fare qualcosa al riguardo.

Il tentativo di offrire funzionalità 2010 su un browser del 1999 quando si poteva semplicemente consegnare una pagina di tecnologia inferiore è un altro esempio di compromesso di progettazione insensato. Le opportunità sprecate e i soldi che ho visto sprecati nel tempo degli sviluppatori speso per soluzioni alternative piene di bug solo per ottenere angoli arrotondati su un elemento che si libra sopra uno sfondo sfumato! Ad esempio, mi hanno spazzato via completamente. E per cosa? Fornire pagine di tecnologia più avanzata che offrono prestazioni tecnologiche mediocri o scarse, limitando al contempo le scelte sui browser di fascia alta.

Affinché sia ​​la scelta giusta, la scelta di gestire l'input in modo robusto dovrebbe sempre semplificare la vita su entrambi i lati del problema, a breve e lungo termine.


4
"per un metodo che accetta 20 argomenti"> non c'è bisogno di guardare oltre, dopo 5/6 il metodo è sbagliato . Grazie per la risposta però :)
Matthieu M.

1

Non fallire mai in silenzio . A parte questo, cercare di indovinare ciò che voleva l'utente di un'API / libreria, non sembra una cattiva idea. Non lo seguirei comunque; avendo un requisito rigoroso, può esporre bug nel codice chiamante e / o interpretazioni errate sulla tua API / libreria.

Inoltre, come è già stato sottolineato, dipende da quanto sia difficile indovinare effettivamente ciò che l'utente si aspettava. Se è molto semplice, hai due casi:

  1. La tua libreria dovrebbe essere progettata in modo leggermente diverso (rinominare alcune funzioni o dividerle in due), in modo che l'utente possa aspettarsi ciò che effettivamente fornisci.
  2. Se ritieni che la tua libreria sia progettata correttamente, il che significa una denominazione chiara / semplice, puoi provare a dedurre ciò che l'utente intendeva.

In ogni caso, non è ovvio e deterministico al 100%, che un input debba essere convertito in un altro, non si devono fare le conversioni, per una serie di motivi già citati (violazione della compatibilità sul refactoring, minimo stupore degli utenti).

Quando si ha a che fare con un utente finale, provare a correggere il proprio input / ipotesi è molto gradito. Si prevede che inserisca informazioni non valide; questo caso è del tutto ineccepibile. Un altro sviluppatore, tuttavia, non è un semplice utente non tecnico. Ha l'esperienza per capire un errore e l'errore può avere significato / essere benefico per lui. Pertanto, concordo con te sulla progettazione di API rigorose, mentre la rigidità ovviamente è accompagnata da chiarezza e semplicità.

Consiglierei di leggere questa mia domanda , di un caso simile.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.