Soyez libéral dans ce que vous acceptez… ou pas?


45

[Avertissement: cette question est subjective, mais je préférerais obtenir des réponses étayées par des faits et / ou des réflexions]

Je pense que tout le monde connaît le principe de robustesse , généralement résumé par la loi de Postel:

Soyez conservateur dans ce que vous envoyez. soyez libéral dans ce que vous acceptez.

Je conviens que pour la conception d'un protocole de communication répandu, cela peut avoir un sens (dans le but de permettre une extension facile), mais j'ai toujours pensé que son application au HTML / CSS était un échec total, chaque navigateur mettant en œuvre son propre ajustement silencieux. détection / comportement, ce qui rend pratiquement impossible l’obtention d’un rendu cohérent sur plusieurs navigateurs.

Je remarque cependant que la RFC du protocole TCP considère que "l'échec silencieux" est acceptable, sauf indication contraire ... ce qui est un comportement intéressant, pour le moins qu'on puisse dire.

Il existe d'autres exemples d'application de ce principe dans le commerce de logiciels qui apparaissent régulièrement parce qu'ils ont mordu les développeurs, du haut de ma tête:

  • Insertion de point-virgule Javascript
  • Conversions intégrées C (silencieuses) (qui ne seraient pas si mauvaises si elles n'étaient pas tronquées ...)

et il existe des outils pour aider à implémenter un comportement "intelligent":

Cependant, j'estime que cette approche, bien qu'elle puisse être utile pour traiter avec des utilisateurs non techniques ou pour aider les utilisateurs dans le processus de récupération d'erreur, présente certains inconvénients lorsqu'elle est appliquée à la conception de l'interface bibliothèque / classes:

  • il est quelque peu subjectif de savoir si l'algorithme devine "vrai", et cela peut donc aller à l'encontre du principe de moindre étonnement
  • cela rend la mise en œuvre plus difficile, donc plus de chances d'introduire des bugs (violation de YAGNI ?)
  • cela rend le comportement plus susceptible de changer, car toute modification de la routine "deviner" peut casser les anciens programmes, ce qui exclut presque les possibilités de refactorisation ... dès le départ!

Et c'est ce qui m'a amené à la question suivante:

Lorsque vous concevez une interface (bibliothèque, classe, message), vous penchez-vous ou non vers le principe de robustesse?

J'ai moi-même tendance à être assez strict, en utilisant une validation d'entrée étendue sur mes interfaces, et je me demandais si j'étais peut-être trop strict.


Je me demande quelle est la différence entre HTML et données générales? Le principe de robustesse concerne la communication. On écrit - on lit. Pourquoi la communication réseau est différente de visuelle ou API? J'ai un exemple d'API où le principe d'être libéral à ce que nous acceptons simplifie la vie des utilisateurs qui sont programmeurs , réduit la taille du code et, par conséquent, améliore les performances et élimine les bugs. Regardez stackoverflow.com/questions/18576849
Val le

@ Val: en fait, votre exemple ne correspond pas. "être libéral dans ce que vous acceptez" n'est pas simplement une question de base / dérivée, c'est aller au-delà de cela et également accepter (et interpréter) des entrées légèrement erronées.
Matthieu M.

Comment montrer un cas ne montre pas ce cas?
Val le

Réponses:


34

Je dirais robustesse quand cela n'introduit pas d'ambiguïtés .

Par exemple: lors de l'analyse d'une liste séparée par des virgules, le fait qu'il y ait ou non un espace avant / après la virgule ne modifie pas la signification sémantique.

Lors de l'analyse d'un guide de chaîne, il doit accepter n'importe quel nombre de formats courants (avec ou sans tirets, avec ou sans accolades).

La plupart des langages de programmation sont robustes et utilisent des espaces blancs. Particulièrement partout où cela n'affecte pas la signification du code. Même en Python, où les espaces sont pertinents, ils restent flexibles lorsque vous êtes à l'intérieur d'une liste ou d'une déclaration de dictionnaire.

Je suis tout à fait d’accord pour dire que si quelque chose peut être interprété de différentes manières ou si ce n’est pas clair à 100%, alors trop de robustesse peut devenir un problème, mais il ya beaucoup de place pour la robustesse sans être ambigu.


1
Je suis d'accord, la robustesse quand elle ne coûte pas beaucoup vaut la peine.
Matthieu M.

2
Même la liste séparée par des virgules pose des problèmes, en quelque sorte: le moteur javascript de chrome et de firefox semble accepter {"key": "value",}comme valide, IE non. Je suis souvent tombé sur ce problème particulier jusqu'à ce que j'améliore mon processus de construction avec JSlint.
keppla

2
@keppla c'est un problème d'implémentation plutôt que de design. Je ne sais pas si cela est légal au regard de la spécification JavaScript et si IE ne suit pas, ou si c'est une "fonctionnalité intéressante" ajoutée par FF et Chrome, mais en Python, cela est spécifié pour être valide et implémenté en tant que tel. Si elle est spécifiée comme valide et que cela ne fonctionne pas, c'est une implémentation erronée. Si ce n'est pas spécifié, on ne devrait pas vraiment s'y fier (bien que pour des raisons pratiques, si cela ne fonctionne pas dans un navigateur majeur, on pourrait tout aussi bien en tenir compte dans les spécifications si vous ne contrôlez pas l'utilisateur)
Davy8

7
@ Davy8: La virgule suivante semble illégale ( stackoverflow.com/questions/5139205/… ). Je ne veux pas compter sur cela, mon point est que, quand suffisamment de personnes acceptent l'entrée, cela devient une norme de facto (car on ne remarque pas que c'est une erreur), ce qui conduit à quelque chose que nous avons rencontré en HTML: que les erreurs devenu si banal que vous ne pouvez plus les ignorer en tant que mauvaise entrée.
keppla

1
@keppla, cela devrait échouer dans moz et Chrome. En tant que développeur principalement JS, cela me fait chier de ne pas le faire (cela se faisait dans Moz au moins). Cela rend le débogage plus difficile, pas plus facile. IE fait ce qu'il est censé faire. Fail @ bad code. Le HTML est une chose. Nous n'avons pas besoin de cette merde dans un langage de script. C'est un exemple d'application horrible du principe Robust, auquel les fournisseurs de navigateurs sont excellents.
Erik Reppen

15

Définitivement pas. Des techniques telles que la programmation défensive masquent les bogues, rendant leur apparition moins probable et plus aléatoire, ce qui rend leur détection plus difficile, ce qui rend leur isolement plus difficile.

Writing Solid Code, largement sous-estimé, soulignait avec insistance le besoin et les techniques de rendre les bogues aussi difficiles à introduire ou à cacher. En appliquant ses principes tels que "Eliminer le comportement aléatoire. Forcer les bugs à être reproductibles". et "Recherchez et éliminez toujours les défauts de vos interfaces." Les développeurs vont considérablement améliorer la qualité de leurs logiciels en éliminant l'ambiguïté et les effets secondaires incontrôlés à l'origine d'une grande quantité de bogues.


9

Une application excessive de la robustesse vous amène à deviner ce que l'utilisateur souhaitait, ce qui est bien jusqu'à ce que vous vous trompiez. Cela nécessite également la confiance totalement erronée que vos clients n'abuseront pas de votre confiance et ne créeront pas un charabia aléatoire qui fonctionnera, mais que vous ne pourrez pas prendre en charge dans la version 2.

Une surapplication de la correction entraîne le refus du droit de vos clients de commettre des erreurs mineures, ce qui est correct jusqu'à ce qu'ils se plaignent que leur contenu fonctionne bien sur le produit de votre concurrent et vous indiquent ce que vous pouvez faire avec votre norme de 5 000 pages. "DRAFT" est encore griffonné au crayon, et au moins trois experts affirment qu'il est fondamentalement défectueux, et 200 autres experts honnêtes affirment ne pas comprendre parfaitement.

Ma solution personnelle a toujours été la dépréciation. Vous les soutenez, mais leur dites qu'ils agissent mal et (si possible) le chemin le plus simple vers la correction. De cette façon, lorsque vous désactivez la fonctionnalité de bogue 10 ans plus tard, vous avez au moins la trace écrite indiquant que "nous vous avions prévenu que cela pourrait se produire".


+1 pour dépréciation , il s'agit bien d'un concept important et je suis surpris qu'il ait été négligé jusqu'à présent.
Matthieu M.

9

Malheureusement, le prétendu "principe de robustesse" ne conduit pas à la robustesse. Prenez HTML comme exemple. On aurait pu éviter beaucoup d'ennuis, de larmes, de perte de temps et d'énergie si les navigateurs avaient analysé le code HTML dès le début au lieu d'essayer de deviner la signification du contenu malformé.

Le navigateur aurait simplement dû afficher un message d'erreur au lieu d'essayer de le corriger sous les couvertures. Cela aurait forcé tous les bunglers à réparer leurs dégâts.


Je me cite (il faut que je vieillisse): "Cependant, j'ai toujours pensé que son application à HTML / CSS était un échec total"
Matthieu M.

3
C'est vrai, mais la même tolérance aux pannes a également contribué à la popularité du Web.
MaR

Les vendeurs de navigateurs ont échoué sur celui-là. Avec les doctypes, nous avions la possibilité de faire notre propre choix à cet égard, mais à la fin de la journée, tout se passait plus ou moins de la même manière, à condition que tout doctype soit déclaré. Maintenant, ils pensent qu'un ensemble hyper-complexe de règles rigoureuses à suivre en matière de gestion de l'échec est la solution? Je pense qu'ils ne parviennent pas à identifier le problème.
Erik Reppen

Vous dites que l’échec rapide, qui est le contraire de «robuste», est plus efficace.
Val le

@MaR: Est-ce vrai? Très contestable, les caractéristiques étaient probablement beaucoup plus importantes.
Déduplicateur

6

Je divise les interfaces en plusieurs groupes (ajoutez-en d'autres si vous voulez):

  1. ceux qui sont sous votre contrôle doivent être stricts (classes en général)
  2. API de bibliothèque, cela devrait également être strict, mais une validation supplémentaire est conseillée
  3. interfaces publiques devant gérer tous les types d'abus (protocoles, entrées utilisateur, etc.). Ici, la robustesse des entrées est vraiment rentable, vous ne pouvez pas vous attendre à ce que tout le monde répare ses problèmes. Et rappelez-vous pour l'utilisateur que ce sera votre faute si l'application ne fonctionne pas, pas la partie qui a envoyé de la merde mal formatée.

La sortie doit toujours être stricte.


5

Je pense que HTML et le World Wide Web ont fourni un test réel et à grande échelle du principe de robustesse et l'ont démontré comme un échec massif. Il est directement responsable du désordre déroutant des normes HTML concurrentes, qui rend la vie difficile pour les développeurs Web (et leurs utilisateurs), et empire à chaque nouvelle version d'Internet Explorer.

Nous savons depuis les années 1950 comment valider correctement le code. Exécutez-le avec un analyseur strict et si quelque chose n'est pas correct du point de vue syntaxique, envoyez une erreur et abandonnez. Ne passez pas, ne collectez pas 200 $ et, pour l'amour de tout ce qui est binaire , ne laissez pas un programme informatique tenter de lire dans la tête du codeur s'il se trompait!

HTML et JavaScript nous ont montré exactement ce qui se passe lorsque ces principes sont ignorés. Le meilleur plan d'action est d'apprendre de leurs erreurs et de ne pas les répéter.


4
@ ChaosPandion: le problème ne réside pas avec Internet Explorer lui-même, mais avec toutes les pages Web non standard acceptées par les versions précédentes et que tout le monde doit vivre avec ... et essayer de s'adapter avec plus ou moins de succès.
Matthieu M.

5
Je pense en fait que l'équipe IE est dans la pire position possible de tous les développeurs de navigateurs. Joel résume assez bien mes pensées .
Dean Harding

3
Cela a peut-être rendu la vie misérable pour les développeurs et les concepteurs, mais nous serions alors coincés dans une norme évoluant très lentement et statique - je doute que le Web soit comme il l'est maintenant. Les véritables gagnants sont les internautes et, en fin de compte, ce sont eux qui comptent.
FinnNk

4
En outre, bien que le principe de robustesse puisse rendre la vie difficile aux développeurs Web, il est difficile d'appeler le World Wide Web (maintenant partie intégrante de presque toutes les grandes institutions de la planète) un échec massif .
deworde

3
"Nous savons, depuis les années 1950, comment valider le code correctement. Exécutez-le avec un analyseur syntaxique strict et si quelque chose n'est pas correct sur le plan syntaxique, envoyez une erreur et abandonnez." Pour appliquer cela à un scénario du monde réel: si j'ai foiré une seule icône à l'extrême droite de ma page juste en dessous de la coupe, abandonner toute la page est un très bon moyen d'envoyer quelqu'un qui regarde ailleurs, à cause d'un problème, ils n'auraient même pas remarqué. Oui, vous pouvez soutenir que je n'aurais pas dû faire l'erreur. Mais cela présuppose plutôt que je ne suis pas déjà allé chez votre concurrent plus robuste et que je ne prends plus vos appels.
deworde

3

En contrepoint de l'exemple de Mason, mon expérience avec le protocole d'initiation de session était que, même si différentes piles interprètent différemment les RFC pertinents (et je suppose que cela se produit avec chaque norme jamais écrite), vous êtes (modérément) libéral dans ce que vous acceptez. peut réellement faire des appels entre deux appareils. Parce que ces appareils sont des objets physiques habituels par opposition à des logiciels sur un ordinateur de bureau, vous devez simplement accepter ce que vous acceptez, ou votre téléphone ne peut pas appeler un autre téléphone d'une marque en particulier. Cela ne rend pas votre téléphone beau!

Mais si vous écrivez une bibliothèque, vous n'avez probablement pas le problème de l'interprétation par plusieurs parties d'une norme commune de manière incompatible. Dans ce cas, je dirais qu'il faut être strict dans ce que vous acceptez, car cela supprime les ambiguïtés.

Le fichier de jargon a également une histoire d'horreur sur "deviner" l'intention d'un utilisateur.


Histoire très amusante :) Je réalise que vous pouvez avoir besoin de plus de marge de manœuvre lorsque vous essayez d’interagir avec des systèmes existants, car si cela ne fonctionne pas, vous serez blâmé.
Matthieu M.

En fait, si votre téléphone ne fonctionne pas avec la plupart des autres téléphones, votre téléphone est défectueux .
SamB

1
@SamB: Remplacer mauvais par cassé .
deworde

3

Vous avez raison, la règle s'applique aux protocoles et non à la programmation. Si vous faites une faute de frappe pendant la programmation, vous obtiendrez une erreur dès que vous compilerez (ou exécuterez, si vous êtes l'un de ces types dynamiques). Il n'y a rien à gagner à laisser l'ordinateur deviner pour vous. Contrairement aux gens ordinaires, nous sommes des ingénieurs et capables de dire exactement ce que je veux dire. ;)

Ainsi, lors de la conception d'une API, je dirais qu'il ne faut pas suivre le principe de robustesse. Si le développeur fait une erreur, il devrait le savoir immédiatement. Bien sûr, si votre API utilise des données provenant d'une source externe, comme un fichier, vous devriez être indulgent. L'utilisateur de votre bibliothèque devrait découvrir ses propres erreurs, mais pas celles de quelqu'un d'autre.

En passant, je suppose que le "protocole d'échec silencieux" est autorisé dans le protocole TCP, car sinon, si des personnes vous envoyaient des paquets mal formés, vous seriez bombardé de messages d'erreur. C’est là une simple protection DoS.


1
"Si vous faites une faute de frappe lors de la programmation, vous obtiendrez une erreur dès que vous compilerez" Je vous présente les millions d'avertissements du compilateur qu'un compilateur standard va cracher tout en produisant des tâches parfaitement exécutables.
deworde

1

OMI, la robustesse est l’un des aspects d’un compromis de conception et non d’un principe de "préférence". Comme beaucoup l'ont fait remarquer, rien ne pèse moins que quatre heures à essayer de comprendre où votre JS a mal tourné et de découvrir que le vrai problème est qu'un seul navigateur a fait le bon choix avec XHTML Strict. Il a laissé la page en morceaux lorsqu'une partie du code HTML servi était un désastre complet.

D'autre part, qui souhaite consulter la documentation d'une méthode prenant 20 arguments et insistant sur le fait qu'ils doivent être dans le même ordre avec des espaces vides ou nuls pour ceux que vous souhaitez ignorer? La méthode tout aussi terrible pour traiter cette méthode serait de vérifier chaque argument et d'essayer de deviner lequel était basé sur des positions et des types relatifs, puis d'échouer en silence ou d'essayer de "se débrouiller" avec des arguments dénués de sens.

Vous pouvez également apporter de la flexibilité au processus en passant une liste de paires littéral / dictionnaire / clé-valeur et en gérant l’existence de chaque argument au fur et à mesure. Pour le très petit compromis de perf, c'est un gâteau et mangez-le aussi scénario.

Surcharger les arguments de manière intelligente et cohérente sur l’interface est un moyen intelligent d’être robuste dans tous les domaines. Il en va de même pour la redondance dans un système qui suppose que la livraison de paquets échouera régulièrement dans un réseau extrêmement complexe, géré et géré par tout le monde dans un domaine technologique émergent avec une grande variété de moyens de transmission potentiels.

Tolérer un échec abject, cependant, en particulier dans un système que vous contrôlez, n’est jamais un bon compromis. Par exemple, je devais prendre une pause pour éviter de perdre mon sang-froid dans une autre question sur le fait de placer JS en haut ou en bas de la page. Plusieurs personnes ont insisté sur le fait qu'il était préférable de placer JS en haut de la liste, car si le chargement de la page échouait complètement, vous auriez peut-être encore des fonctionnalités. Les demi-pages de travail sont pires que des bustes complets. Dans le meilleur des cas, le nombre de visiteurs de votre site Web étant supposé correctement si vous êtes incompétent avant que vous ne le sachiez, la page décomposée est simplement renvoyée à une page d'erreur si elle échoue à sa propre vérification de validation suivie d'un e-mail automatisé. quelqu'un qui peut faire quelque chose à ce sujet.

Tenter de fournir les fonctionnalités de 2010 sur un navigateur de 1999 alors que vous pouviez simplement fournir une page de technologie inférieure est un autre exemple d'un compromis de conception imprudent. Les opportunités saisies et l’argent que j’ai vu gaspiller sur le temps consacré par les développeurs à des solutions de contournement corrigées par les bogues, juste pour obtenir des angles arrondis sur un élément planant au-dessus d’un arrière-plan dégradé, par exemple, m’ont complètement ébloui. Et pour quoi? Fournir des pages de technologie plus performante aux performances technophobes éprouvées tout en vous limitant aux choix de navigateurs haut de gamme.

Pour que ce soit le bon choix, le choix de gérer les entrées de manière robuste devrait toujours faciliter la vie des deux côtés du problème, à court et à long terme.


4
"pour une méthode qui prend 20 arguments"> pas besoin de chercher plus loin, après 5/6 la méthode est fausse . Merci pour la réponse cependant :)
Matthieu M.

1

Ne jamais échouer en silence . En dehors de cela, essayer de deviner ce que l'utilisateur d'une API / bibliothèque voulait, ne semble pas être une mauvaise idée. Je ne le suivrais pas cependant; ayant une exigence stricte, peut exposer des bogues dans le code d'appel et / ou une interprétation erronée de votre API / bibliothèque.

En outre, comme cela a déjà été souligné, tout dépend de la difficulté de deviner les attentes de l'utilisateur. Si c'est très facile, alors vous avez deux cas:

  1. Votre bibliothèque doit être conçue un peu différemment (renommer une fonction ou la scinder en deux), afin que l'utilisateur puisse s'attendre à ce que vous fournissez.
  2. Si vous pensez que votre bibliothèque est conçue correctement, ce qui signifie une dénomination claire / simple, vous pouvez alors essayer de déduire ce que l'utilisateur a voulu.

Dans tous les cas où il n'est pas évident et déterministe à 100%, qu'une entrée doit être convertie en une autre, vous ne devez pas effectuer de conversions, pour un certain nombre de raisons déjà mentionnées (rupture de compatibilité lors du refactoring, moindre étonnement des utilisateurs).

Lorsque vous traitez avec un utilisateur final, essayez de corriger leur apport / estimation est la bienvenue. Il est censé entrer des informations non valides. cette affaire est tout à fait inhabituelle. Un autre développeur, cependant, n’est pas un simple utilisateur non technique. Il a l'expertise nécessaire pour comprendre une erreur et l'erreur peut avoir une signification / être bénéfique pour lui. Ainsi, je suis d’accord avec vous sur la conception d’API strictes, bien que la rigueur soit bien sûr accompagnée de clarté et de simplicité.

Je vous recommanderais de lire cette question mienne d'un cas similaire.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.