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
Avis sur Hacker News
Avis sur le fait de « masquer les erreurs » :
panicde Go est un bon moyen de signaler bruyamment les erreurs du programmeur pendant les tests.Avis sur la rétrocompatibilité :
Plaintes sur le design d’UI :
Remarque sur l’incapacité de Microsoft à apprendre :
Avis sur l’absence de prise en charge de l’impression sur Xbox :
Conseil sur l’usage des API :
NotSupportedException.Sentiment sur la « conformité malveillante » :
Avis positif sur la sécurité :
Retour sur la stratégie des navigateurs :
Incompréhension des critiques sur la gestion des exceptions :
Avis sur Lobste.rs
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
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
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
On ne sait plus si la fonctionnalité a disparu ou si elle a simplement été enfouie ailleurs entre-temps
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 »
ifpour vérifier la nullité. Chaque fois que je vois ça, cet article me revient en têteJ’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