[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":
- algorithmes phonétiques de correspondance de nom ( Double Metaphone )
- algorithmes de distances de chaîne ( distance de Levenshtein )
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.
Réponses:
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.
la source
{"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.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.
la source
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".
la source
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.
la source
Je divise les interfaces en plusieurs groupes (ajoutez-en d'autres si vous voulez):
La sortie doit toujours être stricte.
la source
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.
la source
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.
la source
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.
la source
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.
la source
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:
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.
la source