2 points par GN⁺ 2024-02-17 | 2 commentaires | Partager sur WhatsApp

Quand une API ne fait rien, bien ne rien faire

  • Lorsqu'une API ne doit rien faire, il est important de s'assurer qu'elle ne fait rien de la bonne manière.
  • Par exemple, Windows dispose d'une vaste infrastructure d'impression, mais Xbox ne dispose pas d'une telle infrastructure.
  • Lorsqu'une application tente d'imprimer sur Xbox, lever une NotSupportedException est une mauvaise approche.
  • Comme l'application a probablement été principalement testée sur PC, l'exception peut ne pas être gérée lors de son exécution sur Xbox, ce qui peut provoquer son plantage.
  • Une meilleure conception pour « prendre en charge » l'impression sur Xbox consiste à faire réussir la fonction d'impression tout en signalant qu'aucune imprimante n'est installée.
  • Si l'utilisateur tente d'imprimer, le système lui demande de choisir une imprimante, mais la liste est vide, si bien qu'il comprend qu'il n'y a pas d'imprimante et annule la demande d'impression.
  • Pour les applications qui tentent d'installer une imprimante, la fonction d'installation peut retourner immédiatement avec un code de résultat indiquant que l'utilisateur a annulé l'opération.
  • L'objectif est de se comporter comme si la fonctionnalité d'impression était entièrement prise en charge, tout en agissant en réalité comme s'il n'y avait simplement pas d'imprimante.
  • Sur un système où l'impression ne fonctionne pas du tout, on peut ajouter une fonction qui vérifie si l'impression est possible afin de masquer le bouton d'impression dans l'interface utilisateur.
  • Ce comportement est qualifié d'« inerte ».
  • La surface d'API existe toujours et fonctionne conformément à la spécification, mais en pratique elle ne fait rien.
  • L'important est de ne rien faire d'une manière cohérente avec la documentation afin de minimiser les problèmes avec le code existant.

Exemple de désactivation d'une API

  • Il existe un exemple de désactivation d'une API comprenant plusieurs fonctions pour créer un handle de widget, des fonctions qui prennent un handle de widget en argument, et une fonction pour fermer ce handle.
  • L'équipe a d'abord proposé de désactiver l'API en faisant en sorte que CreateWidget réussisse mais renvoie un pointeur nul.
  • Mais cette approche risque de dérouter les applications : « l'appel a réussi, mais je n'ai pas reçu de handle valide ? »
  • Le fait que EnableWidget renvoie « handle invalide » peut également créer de la confusion.
  • Ils ont trouvé dans la documentation existante une valeur de retour, ERROR_CANCELLED, qui signifie que la création du widget a été annulée par l'utilisateur.
  • Il devient donc possible de répondre systématiquement « non, l'utilisateur a annulé » chaque fois qu'une application tente de créer un widget.

L'avis de GN⁺

  • Le point le plus important de cet article est que lorsqu'une API ne fait rien, elle doit ne rien faire d'une manière qui ne dégrade pas l'expérience utilisateur et qui préserve la compatibilité avec le code existant.
  • Cette approche souligne, pour les développeurs, l'importance de la conception d'API et contribue à offrir une expérience logicielle plus conviviale.
  • Cet article met en lumière un aspect minutieux du software engineering et propose un cas intéressant sur la manière dont une application peut échouer avec élégance même dans des environnements inattendus.

2 commentaires

 
GN⁺ 2024-02-17
Avis sur Hacker News
  • Avis sur le fait de « masquer les erreurs » :

    • Masquer les erreurs est une mauvaise pratique.
    • Cela ne résout pas le problème et rend la découverte des bugs ainsi que les tests plus difficiles en dissimulant les défauts du logiciel.
    • Le panic de Go est un bon moyen de signaler bruyamment les erreurs du programmeur pendant les tests.
    • Si les acteurs d’un système essaient de cacher leurs propres défauts, il devient bien plus difficile d’identifier et de résoudre les problèmes.
  • Avis sur la rétrocompatibilité :

    • La rétrocompatibilité est toujours un travail ingrat, et le choix se fait entre quelque chose d’imparfait et ne rien faire du tout.
    • C’est pour cette raison que, lorsqu’on clique sur un fichier Word '97 ou sur un fichier de jeu MS-DOS, il s’ouvre encore aujourd’hui comme prévu sur un ordinateur moderne.
  • Plaintes sur le design d’UI :

    • Une UI qui propose des périphériques qui n’existent peut-être même pas est extrêmement frustrante.
    • On finit par perdre du temps à chercher des appareils qui ne sont en réalité pas pris en charge.
  • Remarque sur l’incapacité de Microsoft à apprendre :

    • Même après 30 ans, Microsoft continue de répéter les mêmes erreurs.
    • Afficher une liste vide lorsqu’une application essaie de trouver une imprimante revient à reproduire les problèmes du passé.
  • Avis sur l’absence de prise en charge de l’impression sur Xbox :

    • Si la Xbox ne prend pas en charge l’impression, c’est parce que Microsoft l’a décidé ainsi.
    • Côté matériel, elle a les mêmes capacités d’impression que les autres appareils Windows.
    • Cette « solution » est un problème causé par une décision irrationnelle de Microsoft.
  • Conseil sur l’usage des API :

    • Il est vrai qu’un composant doit rencontrer le problème avant l’utilisateur, mais la manière dont l’auteur le formule ne convainc pas.
    • Il n’y a rien de mauvais à ce qu’une fonction d’impression lève une NotSupported­Exception.
    • Ce que décrit l’auteur est un hack destiné à prendre en charge des clients défectueux.
  • Sentiment sur la « conformité malveillante » :

    • J’aime et je déteste à la fois cette manière de traiter le problème.
    • Mais si l’objectif est de permettre à davantage d’utilisateurs d’exécuter davantage de logiciels sur la plateforme, cette approche est bonne.
  • Avis positif sur la sécurité :

    • Ignorer correctement un appel d’API empêche le programme d’adopter un comportement plus nuisible.
  • Retour sur la stratégie des navigateurs :

    • La stratégie consistant à afficher une page du mieux possible même lorsque le code HTML contient des erreurs a un temps été considérée comme une bonne stratégie.
    • Les utilisateurs ne veulent pas d’erreurs, et c’est quelque chose qu’on aurait dû apprendre de cette expérience.
  • Incompréhension des critiques sur la gestion des exceptions :

    • Les critiques passent à côté d’un point dans les situations où il n’est pas nécessaire de lever une exception.
    • Si le périphérique (l’imprimante) n’est pas connecté, l’application doit gérer proprement cette situation et ne pas planter.
 
GN⁺ 4 일 전
Avis sur Lobste.rs
  • Ce qui est décrit ici, c’est que les fonctionnalités d’impression se comportent de manière cohérente comme si l’impression était entièrement prise en charge, alors qu’étrangement il n’y aura jamais réellement d’imprimante pour imprimer, ce qui explique beaucoup de choses
    Blague à part, je ne suis pas d’accord avec ce genre de programmation excessivement défensive ni avec cette expérience utilisateur. Dans ce cas, le logiciel ne fait pas son travail sans qu’on sache pourquoi, et il n’y a aucun moyen de le découvrir. L’application devrait intercepter l’erreur et, si possible, produire un message convivial pour l’utilisateur, ou au moins lui afficher le message d’erreur d’origine. S’il s’agit d’une tâche en arrière-plan, il devrait y avoir des journaux d’erreurs
    Je reconnais que cet article est écrit du point de vue d’un développeur d’API plutôt que d’un développeur d’applications. Il faut donc documenter les erreurs d’API et fournir des messages d’erreur exploitables par la partie appelante
    Je n’aime pas non plus le fait de masquer un bouton dans l’interface sous prétexte qu’on n’a pas les droits d’accès. Si l’espace le permet, il vaut mieux afficher le bouton mais le désactiver, puis fournir un message au survol indiquant comment l’activer
    • Il faut aussi garder à l’esprit que cet article est écrit non pas du point de vue d’un simple développeur d’API, mais d’un développeur de l’API Windows. La position historique de Microsoft est que l’API Windows ne doit pas casser la compatibilité d’une version à l’autre
    • C’est une discussion classique autour de la loi de Postel / principe de robustesse. Tout le monde sait désormais que le principe de robustesse a mal vieilli et qu’il a engendré des monstres comme HTML ou d’énormes protocoles et formats de fichiers qu’il est difficile d’analyser correctement
      Globalement, il vaut mieux exiger de la rigueur. Mais quand on a un milliard d’utilisateurs existants, éviter autant que possible de tout casser est extrêmement judicieux, et du point de vue de l’utilisateur, cela crée aussi une vraie valeur au niveau système puisque « ça marche ». Au final, l’attitude devrait être : échouer vite, mais sans faire échouer trop de choses
    • Dans ce cas précis, l’une des API existantes n’a pas d’erreur documentée, donc il est très probable qu’aucune gestion d’erreur n’ait été prévue au départ. Si l’on ne veut pas casser tous les logiciels existants, il faut recourir à un mensonge pieux
      Cela relève moins de l’API que de la stabilité ABI. Sous Windows, même un logiciel compilé il y a 15 ans doit continuer à fonctionner autant que possible sur un nouvel OS. Comme on ne peut pas changer la signature d’une fonction, il faut parfois recourir à un mensonge pieux pour qu’une API qui n’a plus vraiment de sens continue tout de même de fonctionner
      Par exemple, l’API fait encore comme si Active Desktop existait. L’alternative serait de casser en masse de vieux logiciels existants
    • Je suis tout à fait d’accord. Il y a peu de choses plus frustrantes que de chercher un bouton qui n’apparaît pas sur mon écran, alors qu’une personne à côté de moi ou un tutoriel me dit qu’il est là
      On ne sait plus si la fonctionnalité a disparu ou si elle a simplement été enfouie ailleurs entre-temps
    • L’application devrait bien intercepter l’erreur et l’afficher à l’utilisateur.
      Mais si elle ne le fait pas, les gens qui utilisent cette application reprocheront cela à Windows. Ils accuseront Windows, pas l’application, et c’est pareil même quand l’application plante
      C’est pour cela que Microsoft met en place des contournements. Il est bien plus simple de laisser la tâche d’impression disparaître discrètement, et l’utilisateur finit alors par se dire après un instant : « Ah oui, c’est vrai, il n’y a pas d’imprimante »
  • Si une fonction d’installation d’imprimante peut revenir immédiatement en renvoyant comme code de résultat l’utilisateur a annulé l’opération, du point de vue du support applicatif, cela mènera presque à coup sûr à un comportement indésirable bien plus difficile à gérer qu’une API d’impression qui lèverait une exception dès le départ
  • En ce moment, je fais beaucoup de programmation assistée par IA, et je vois souvent les agents ajouter des tests if pour vérifier la nullité. Chaque fois que je vois ça, cet article me revient en tête
    J’ai donc demandé à l’agent de ne pas répéter les vérifications de nullité, d’utiliser des fonctions inoffensives, et de vérifier une bonne fois au moment de la déclaration que la valeur ne sera jamais nulle