Un serveur doit-il être "indulgent" dans ce qu'il accepte et "éliminer silencieusement les entrées défectueuses"?


27

J'avais l'impression que maintenant tout le monde était d'accord que cette maxime était une erreur. Mais j'ai récemment vu cette réponse qui a un commentaire "soyez indulgents" voté 137 fois (à ce jour).

À mon avis, la clémence dans ce que les navigateurs acceptent était la cause directe du désordre absolu que HTML et certaines autres normes Web étaient il y a quelques années, et n'ont commencé à se cristalliser correctement que récemment. La façon dont je le vois, être clément dans ce que vous acceptez va conduire à cela.

La deuxième partie de la maxime est «éliminer silencieusement les entrées défectueuses, sans renvoyer un message d'erreur à moins que cela ne soit requis par la spécification» , et cela semble offensant à la limite. Tout programmeur qui s'est cogné la tête contre le mur quand quelque chose échoue silencieusement saura ce que je veux dire.

Alors, je me trompe complètement à ce sujet? Mon programme doit-il être indulgent dans ce qu'il accepte et avaler les erreurs en silence? Ou suis-je mal interprété ce que cela est censé signifier?


La question initiale disait «programme», et je comprends tout le monde à ce sujet. Il peut être logique que les programmes soient indulgents. Ce que je voulais vraiment dire, cependant, ce sont les API: des interfaces exposées à d' autres programmes , plutôt qu'à des personnes. HTTP est un exemple. Le protocole est une interface que seuls les autres programmes utilisent. Les gens ne fournissent jamais directement les dates qui entrent dans des en-têtes comme "If-Modified-Since".

Donc, la question est: le serveur implémentant une norme doit-il être indulgent et autoriser les dates dans plusieurs autres formats, en plus de celui qui est réellement requis par la norme? Je crois que "être indulgent" est censé s'appliquer à cette situation, plutôt qu'aux interfaces humaines.

Si le serveur est indulgent, cela peut sembler une amélioration globale, mais je pense qu'en pratique, cela ne mène qu'à des implémentations client qui finissent par s'appuyer sur la clémence et donc à ne pas travailler avec un autre serveur qui est indulgent de manière légèrement différente.

Donc, un serveur exposant une API devrait-il être indulgent ou est-ce une très mauvaise idée?


Passons maintenant à la gestion clémente des entrées utilisateur. Considérez YouTrack (un logiciel de suivi des bogues). Il utilise une langue pour la saisie de texte qui rappelle Markdown. Sauf que c'est "indulgent". Par exemple, écrire

- foo
- bar
- baz

n'est pas un moyen documenté de créer une liste à puces, et pourtant cela a fonctionné. Par conséquent, il a fini par être beaucoup utilisé dans notre bugtracker interne. La version suivante sort, et cette fonctionnalité indulgente commence à fonctionner légèrement différemment, cassant un tas de listes qui ont (mal) utilisé cette (non) fonctionnalité. La manière documentée de créer des listes à puces fonctionne toujours, bien sûr.

Alors, mon logiciel doit-il être indulgent dans les entrées utilisateur qu'il accepte?


4
En ce qui concerne «éliminer silencieusement les entrées défectueuses», je demanderais pour chaque cas ce qui devrait être considéré comme une entrée défectueuse. Si vous posez une question à un utilisateur et attendez "oui" ou "non", "OUI" est-il une entrée défectueuse? Et "y"? Et "oui"? En général, n'hésitez pas à dire à l'utilisateur que sa contribution n'est pas celle que vous attendez. Cependant, assurez-vous que vous avez été aussi inclusif que possible - dans mon esprit, c'est ce que l'on entend par "soyez indulgents".

3
Si vous parlez de la contribution de l'utilisateur final - qui se rapporte aux lignes d'amis de votre application, alors vous devriez être leinent; pour une entrée générée automatiquement par une machine (à partir d'une API), vous devez être prolixe (strict).
Burhan Khalid

2
En fait, la clémence du HTML était la raison pour laquelle il est devenu si populaire (et la rigueur du XHTML pourquoi il a été abandonné).
Oliver Weiler

1
Je pense que la clé est que si c'est un scénario où vous pouvez lui permettre d'échouer gracieusement, c'est que vous enregistrez au moins l'événement.
Rig

2
@OliverWeiler Je pense que l'échec de XHTML a quelque chose à voir avec le fait qu'il était totalement inutile. HTML était déjà là et fonctionnait un peu. De plus, bien que le HTML soit bien sûr extrêmement populaire, il est plutôt triste que nous qualifions cette technologie de succès. Il satisfait la demande, mais il le fait aussi bien que Symbian a satisfait la demande de smartphones.
Roman Starkov

Réponses:


9

Bien sûr, vous avez tout à fait raison. Les programmes ne doivent jamais être «indulgents» car cela ne sert qu'à masquer les problèmes. Les problèmes doivent être mis en évidence et non balayés sous le tapis. Un message d'erreur informatif est un must absolu pour qu'un programme soit utile à l'utilisateur.

La plupart du temps, lorsque des données incorrectes / invalides sont fournies, le fournisseur de ces données (qu'il s'agisse d'un utilisateur ou de la sortie d'un autre programme) ne savait probablement pas qu'elles étaient invalides. Avaler l'erreur les gardera dans la conviction qu'elle est (ou pourrait être) valide, ce qui prolifère des données invalides.

La seule façon pour les systèmes d'interopérer est que cette interopération soit définie de manière complète et sans ambiguïté. Un programme qui accepte des données en dehors de la spécification fait que les données sont acceptées de facto même si elles ne sont pas valides par la spécification, ce qui non seulement rend la compatibilité une charge énorme plus difficile, mais signifie également qu'elle n'est plus définie officiellement. Le programme lui-même est désormais la norme de facto . Ainsi, les programmes indulgents sont impossibles à développer davantage ou à remplacer car vous ne pouvez pas apporter le moindre changement à son fonctionnement.


25

Je pense que tout dépend de qui est votre cible démographique. Si ce sont des programmeurs, alors absolument pas. Votre programme devrait échouer et crier au meurtre sanglant. Cependant, si votre public cible n'est pas des programmeurs, votre programme doit être indulgent lorsqu'il peut gérer les exceptions avec élégance, sinon, chuchoter un meurtre sanglant.

Comme étude de cas, prenez le lecteur Flash NPAPI. Il existe une version "release" pour ceux qui ne se soucient pas vraiment de 99% des erreurs qui peuvent se produire, mais il existe également une version "debug" qui peut être utilisée pour crier un meurtre sanglant en cas de problème. Chacun prend en charge la lecture de contenu Flash bien sûr, mais est ciblé sur deux données démographiques complètement différentes.

Au final, je pense que l'important est: de quoi vos utilisateurs se soucient-ils?


4
La grande majorité des outils de ligne de commande Unixy qui prétendent avoir un public cible en dehors des programmeurs sont néanmoins inutiles pour les utilisateurs qui font des erreurs. Même si vous n'êtes pas programmeur, il est généralement préférable pour un programme d'expliquer un problème plutôt que de faire quelque chose de non sensé ou involontaire.
Timwi

2
@romkyns: Pas complètement, je dis que votre application doit gérer les erreurs de manière sensée pour les utilisateurs ciblés.
Demian Brecht

@Timwi: Dans ce cas, ces outils de ligne de commande Unixy sont mal architecturés;)
Demian Brecht

3
@romkyns - Je pense qu'un bon exemple serait: En mode débogage, vous voulez qu'un programme s'arrête en cas de problème et vous dise ce qui s'est mal passé. En mode production, vous souhaitez que votre programme continue de fonctionner aussi bien qu'il le peut et enregistre tous les problèmes qu'il peut gérer. De cette façon, les programmeurs peuvent voir ce qu'ils ont fait de mal et le réparer, mais les utilisateurs ne seront pas gênés par des choses qu'ils ne peuvent pas réparer. Certains problèmes ne peuvent évidemment pas être résolus, mais un bon exemple est les règles de style CSS, où vous pouvez toujours rendre un site, même si vous ne comprenez pas l'une des règles de style.
Rétablir Monica le

1
@ Le commentaire de BrendanLong frappe à peu près le clou sur la tête - parfois produire une sortie est plus important qu'être correct. Certaines erreurs (ou avertissements) peuvent être récupérées avec élégance, sans intervention de l'utilisateur; c'est à vous de décider ce que vous voulez que votre application fasse dans ces cas.
Daniel B

7

Il existe deux types de "clémence": l'un consiste à accepter une entrée incorrecte et à essayer de lui donner un sens, et l'autre consiste à accepter différents types d'entrée.

En général, vous voulez toujours le second quand c'est possible. Le premier, c'est quand tu meurs vite et fort. Un exemple: les dates.

Voici quelques exemples d'entrées, notamment valides, invalides et ambiguës.

  • 2011-01-02
  • 01/02/2011
  • Jan 2, 2011
  • 2-Jan-2011
  • Green

Il n'y a qu'une seule entrée non valide ici: Green. N'essayez même pas de l'accepter comme date. Puisqu'il ne Greens'agit évidemment pas d'une date, il s'agit d'un cas où l'échec silencieux est acceptable.

01/02/2011est valide, mais ambigu. Vous ne savez pas nécessairement si elle a été entrée comme date aux États-Unis (2 janvier) ou non (1 février). Ici, il est probablement préférable d'échouer bruyamment et de demander à l'utilisateur une date sans ambiguïté.

2011-01-02est généralement considéré comme sans ambiguïté, il est donc souvent bien d'aller de l'avant et de supposer que c'est le format "AAAA-MM-JJ", et d'échouer uniquement plus loin sur la ligne. C'est un peu un jugement, cependant, lorsqu'il s'agit de la saisie de l'utilisateur.

Jan 2, 2011et 2-Jan-2011sont valides et sans ambiguïté, ils doivent être acceptés. Cependant, The Second of January of the year 2011est également valide et sans ambiguïté, mais aller aussi loin dans un souci de clémence est exagéré. Allez-y et échouez silencieusement, tout comme Green.

En bref , la réponse est "cela dépend". Jetez un œil à ce qui peut être saisi et assurez-vous que vous n'acceptez jamais des types d'entrée conflictuels (comme DD/MM/YYYYvs MM/DD/YYYY).

Dans le contexte de la question / du commentaire lié , c'est un cas de 2011-01-02. L'entrée ressemble à JSON et sera validée comme JSON même si le type MIME est incorrect; allez-y et essayez de l'utiliser même s'il échoue à un moment donné plus loin sur la ligne.


1
Il n'y a qu'une chose que vous ne pensez pas ici. Si l' utilisateur a tapé cette chaîne alors oui, je devrais accepter différents formats, sans aucun doute à ce sujet. Mais nous parlons d'API. Les clients des API sont d'autres programmes. S'il est clément dans son format de date, chaque futur serveur exposant cette API devra être clément de la même manière ou risque d'incompatibilité. La clémence finit par être préjudiciable plutôt qu'utile, ne pensez-vous pas?
Roman Starkov

1
@romkyns Je pense que vous ne comprenez pas bien où réside la clémence. L'API doit faire preuve d' indulgence en ce qu'il accepte (il doit comprendre tous 2011-01-02, Jan 2, 2011et 2-Jan-2011, si elle est pas trop difficile à mettre en œuvre), et non pas dans ce qu'elle génère . Les futurs clients de cette API n'ont même pas besoin d'en connaître un, tant qu'ils en saisissent correctement l'un. Idéalement, la couche API convertirait tout cela en la même représentation interne que le code utilise avant de le transmettre.
Izkata

@romkyns Output pourrait, par exemple, toujours être au 2011-01-02format, et c'est celui que vous mettriez dans votre documentation. Je ne vois aucun effet néfaste.
Izkata

4
@Izkata: Vous avez mal compris. Imaginez qu'il y avait un ancien programme qui n'est disponible qu'en binaire. Vous devez écrire un nouveau programme qui accepte les mêmes entrées que l'ancien. Si l'ancien programme était bien défini dans ce qu'il accepte, votre travail est bien défini. S'il est indulgent, alors votre travail est impossible.
Timwi

1
Un fort désaccord. sauf s'il s'agit d'une entrée entrée par l'utilisateur, soyez toujours strict à la fois en entrée et en sortie. Que se passe-t-il lorsque votre service doit être réimplémenté? Avez-vous documenté tous les formats de date possibles? Vous devrez tous les implémenter, car vous ne voulez pas que les anciens clients se cassent. Veuillez utiliser ISO 8601 pour toutes les instances et périodes de date générées par la machine: elle est bien spécifiée et largement disponible dans les bibliothèques. Au fait, que veut vraiment dire le 2011-01-02? La période de temps de 00h00 le 2 jusqu'à 00h00 le 3? Dans quel fuseau horaire?
Dibbeke

6

Échouer en silence est la pire chose que vous puissiez faire, jamais. Avez-vous essayé de déboguer une API avec échec silencieux? C'est impossible .

Il y a "Faites de votre mieux pour récupérer mais envoyez une erreur détaillée" et il y a "Échec silencieux".


3

Il me semble que la loi de Postel - "Soyez conservateur dans ce que vous faites, soyez libéral dans ce que vous acceptez des autres" est ce qui est discuté pour un service JSON. Ceci est généralement appliqué aux services Web et non à l'interface utilisateur.

Pour l'interface utilisateur, les commentaires constructifs et les entrées utilisateur contraignantes sont la règle de base que nous utilisons.


Mais si vous regardez les réponses ici, tout le monde semble convenir que cela n'a de sens que pour les interfaces utilisateur, c'est-à-dire le contraire de la loi d'origine.
Roman Starkov

Je vois ce que vous dites et je suis d'accord avec les affiches qu'un API / service strict et strict est le but, mais pour le meilleur ou pour le pire, je sais que j'ai ajouté de la «robustesse» sous une forme ou une autre à mes services. Habituellement, une traduction de valeur ou deux à la limite. Tant que le sens est clair, l'application sait comment traiter le message et aucune règle métier n'est violée, puis l'ajout de robustesse contribuera à l'interopérabilité.
MarcLawrence

Jusqu'à ce que quelqu'un d'autre aille et implémente votre spécification, seulement pour constater que la «robustesse», sur laquelle des centaines de clients s'appuient, n'était pas réellement dans la spécification et doit être inversée ...
Roman Starkov

3

Je pense que cela est bien couvert dans le chapitre 1, section 6 de TAOUP. Plus précisément, la règle de réparation , qui stipule qu'un programme doit faire ce qu'il peut avec une entrée, transmettre les données correctes et si la réponse correcte est un échec, le faire le plus tôt possible.

Un concept similaire est la programmation défensive . Vous ne savez pas quel type d'entrée vous recevrez, mais votre programme devrait être suffisamment robuste pour couvrir tous les cas. Cela signifie qu'il devrait être programmé dans les cas de récupération pour les problèmes connus comme l'entrée mutilée et un cas de capture pour gérer les inconnues.

Donc jeter entrée défectueuse est silencieusement bien, tant que vous êtes manipulez cette entrée. Vous ne devriez jamais le laisser tomber sur le sol, pour ainsi dire.


Pour une API, je pense que la clémence est la même que pour un programme. L'entrée est toujours incorrecte , mais vous essayez de réparer autant que possible. La différence est ce qui est considéré comme une réparation valide . Comme vous le faites remarquer, une API indulgente peut causer des problèmes car les gens utilisent des "fonctionnalités" qui n'existent pas.

Bien sûr, une API n'est qu'une version de niveau inférieur de la règle de composition . En tant que tel, il est vraiment couvert par la règle de la moindre surprise , car il s'agit d'une interface.

Comme le note la citation de Spencer, évitez les similitudes superficielles, qui peuvent être discutées à propos des entrées "floues". Dans ces conditions, je dirais normalement que tout indique que le programme est incapable de réparer, car il ne saura pas ce qui est souhaité, et c'est moins surprenant pour la base d'utilisateurs.

Cependant, vous avez affaire à des dates qui ont de nombreuses "normes". Parfois, ceux-ci sont même mélangés dans un seul programme (chaîne). Puisque vous savez qu'une date est attendue, tenter de reconnaître la date est juste une bonne conception. Surtout si la date provient d'un programme externe et est passée sans modification par une seconde sur son chemin vers vous.


2

Les programmes déployés sur le serveur, la plupart du temps, sont censés accepter des milliers de demandes chaque minute, ou parfois chaque seconde. Si un programme serveur accepte et corrige les entrées défectueuses des clients, je crains qu'il n'ait 2 inconvénients:

  1. Perte de temps précieux sur le serveur. Avec plus de 1000 requêtes par seconde, la vérification des défauts dans chaque requête peut se traduire par une réponse lente pour chaque client.
  2. Injuste envers le client / les programmes clients qui fournissent une entrée correcte. En dehors de cela, lorsqu'un programmeur côté serveur est assis sur le code du serveur, il / elle doit réfléchir aux différents cas de ce que peuvent être des entrées défectueuses. Qui décidera cela?

Les programmes serveur ne doivent pas accepter les entrées défectueuses, mais les serveurs doivent renvoyer un message d'erreur au client, s'il y a une entrée défectueuse.


2

Le comportement idéal, sur le plan conceptuel, est de faire ce qui peut être fait en toute sécurité, tout en s'assurant simultanément que quelqu'un qui peut résoudre les problèmes est en quelque sorte informé à leur sujet. Dans la pratique, bien sûr, cette dernière contrainte est souvent impossible à rencontrer directement, et il est donc préférable de traiter les intrants douteux.

Une chose qui peut être très utile dans la conception d'un protocole, d'une spécification de mise en forme ou d'un «langage» est d'avoir un moyen de distinguer quatre catégories d'éléments potentiels non compris:

  1. Les choses qui devraient être filtrées si elles ne sont pas comprises.
  2. Éléments qui doivent être ignorés s'ils ne sont pas compris, mais néanmoins conservés si les données doivent être transmises (peut-être dans une sorte de wrapper pour indiquer qu'elles ont traversé au moins une étape qui ne les a pas comprises)
  3. Les choses qui devraient générer un avertissement si elles ne sont pas comprises, mais ne devraient pas empêcher une tentative de récupération de données (par exemple, dans une page Web, un objet dont le type est inconnu, mais dont la fin dans le fichier est bien défini, peut être affiché en rouge "X" sans empêcher le rendu du reste de la page.)
  4. Des choses qui indiqueraient que tout ce qui ne peut pas les comprendre est susceptible d'avoir des problèmes graves et irrécupérables ailleurs (par exemple, un indicateur que les données restantes sont compressées et que tout ce qui serait compris par tout ce qui pourrait effectuer la décompression requise).

Avoir une convention bien définie par laquelle les applications qui peuvent lire n'importe quelle version d'un format de données sera en mesure de reconnaître quelle catégorie est appropriée pour tout ce qui est généré conformément aux versions ultérieures est une bien meilleure approche que d'essayer de se faufiler dans des mesures de compatibilité ad hoc plus tard. Par exemple, si un format de fichier comporte des lignes de la forme "Tag: Value", on pourrait spécifier que le premier caractère de n'importe quelle balise indiquera la catégorie à laquelle il appartient; pour les balises des catégories silent-ignore, le premier caractère pourrait également indiquer la version de la norme pour laquelle la balise devrait être valide (de sorte que si une balise "silent-ignore" prétend être présente dans la version 3 de la norme, un analyseur pour la version l'ignorerait silencieusement, mais un analyseur pour la version 3 ou plus tard grincerait s'il ne pouvait pas l'analyser).

La chose la plus importante dans tous les cas est d'éviter de convertir des données ambiguës ou mal comprises en données erronées. Dans certains cas, il peut être préférable de refuser de propager des données ambiguës, mais dans d'autres cas, il peut être préférable de les propager précisément telles qu'elles ont été reçues au cas où le destinataire les considérerait comme non ambiguë. Ce qui est vraiment dangereux sinon carrément mal est la conversion de données en utilisant différentes hypothèses, par exemple la conversion d'une liste de dates comme:

01/12/12
13/12/12
99/12/12

dans une liste de dates comme

2012-01-12
2012-12-13
1999-12-12

Même si l'on avait une liste avec quelques dates saisies de manière erronée, il peut être possible pour un être humain donné une liste dans le format d'origine de déterminer quel format était correct et de signaler des valeurs douteuses pour des recherches ultérieures (vérification par rapport à d'autres enregistrements, etc. ) Le rendu des dates dans ce dernier format, cependant, les brouillerait désespérément et de manière irrécupérable.


Bien dit. J'aime la façon dont votre réponse va un peu plus loin. Je suis tenté d'accepter cela, mais étant donné l'intérêt général que cette question a suscité, je pense que je vais laisser cela de côté pendant un certain temps.
Roman Starkov

1

Mon expérience de l'interface utilisateur provient principalement des systèmes de bureau. Les sites Web sont différents, bien que j'aie vu quelques sites qui pourraient contester un système de bureau. Mais pour ce que ça vaut:

J'ai trouvé que les messages d'erreur devraient être le tout dernier recours; un système idéal ne les aurait pas du tout. La meilleure chose à faire est de ne pas autoriser les mauvaises entrées en premier lieu: l'utilisateur ne peut pas entrer "vert" s'il sélectionne dans une liste déroulante de mois. Il ne peut pas appuyer sur un bouton grisé.

La prochaine meilleure chose à faire est d'accepter les mauvaises données. Supposons que vous affichez un histogramme des ventes quotidiennes pendant un mois. Après saisie par l'utilisateur, le graphique couvre un siècle et la barre un siècle plus tard est 10 fois plus élevée que les autres. L'utilisateur sait maintenant qu'il a fait quelque chose de mal et, en outre, en sait beaucoup plus sur ce qu'il a fait de mal que tout message pourrait lui dire. Lorsque l'entrée est graphique - en faisant glisser une souris, par exemple - ce type de rétroaction fonctionne toujours et est inestimable. Un certain nombre d'entrées peuvent être invalides, mais en utilisant cette méthode, l'utilisateur obtient une rétroaction instantanée et détaillée sur les résultats de chaque position de la souris.

Cela dit, l'utilisateur a parfois besoin de savoir pourquoi le bouton est grisé pour ne pas pouvoir le pousser. Ensuite , il n'y a aucune aide pour elle (s'il est , laissez - moi savoir) mais ungray le bouton et, quand il clique dessus, lui donner une bonne explication des raisons pour lesquelles le bouton ne fonctionne pas à l'heure actuelle.


0

La déclaration concerne l'envoi d'informations sur Internet. L’envoi d’informations sur Internet a notamment pour conséquence qu’elles ne parviendront pas toujours à la cible ou qu’elles seront fragmentées.


0

Quelque chose qui semble manquer ici - quelles sont les conséquences d'un échec?

Afficher une page Web? Vous devez faire tout votre possible pour tolérer une mauvaise saisie. Vos choix sont d'afficher ce que vous pouvez ou de lancer une erreur. Ce dernier cours ne donne rien à l'utilisateur et ne devrait donc être qu'un dernier recours car il donne à l'utilisateur un résultat complètement inutile, il serait assez difficile qu'une erreur soit pire que cela.

D'un autre côté, s'il demande la cible d'un Minuteman III, vous rejetez "Moscou" en entrée car il est potentiellement ambigu.


Donc, même si vous êtes un programmeur et que vous avez écrit un code stupide, le système devrait aller de l'avant et faire de son mieux pour montrer quelque chose, au lieu d'arrêter et de crier "oi, vous avez foiré ici (numéro de ligne)"? Ne pensez-vous pas que c'est exactement ce qui mène à un code incroyablement mauvais?
Roman Starkov, le

@romkyns: Vous avez des modes de débogage pour ce genre de chose qui sont stricts sur le cri des erreurs.
Loren Pechtel
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.