Les exceptions en tant que flux de contrôle sont-elles considérées comme un antipattern sérieux? Si oui, pourquoi?

129

Vers la fin des années 90, j'ai beaucoup travaillé avec une base de code qui utilisait des exceptions comme contrôle de flux. Il a mis en œuvre une machine à états finis pour gérer les applications de téléphonie. Dernièrement, je me souviens de cette époque parce que je développais des applications Web MVC.

Ils ont tous les deux Controllerle choix de la prochaine étape et fournissent les données à la logique de destination. Les actions des utilisateurs d'un téléphone de la vieille école, telles que les tonalités DTMF, sont devenues des paramètres pour les méthodes d'action, mais au lieu de renvoyer quelque chose comme un ViewResult, elles ont jeté un StateTransitionException.

Je pense que la principale différence était que les méthodes d'action étaient des voidfonctions. Je ne me souviens pas de tout ce que j'ai fait avec ce fait, mais j'ai hésité à ne pas trop m'en souvenir, car depuis ce travail, comme il y a 15 ans, je ne l'avais jamais vu dans le code de production . J'ai supposé que c'était un signe qu'il s'agissait d'un prétendu anti-modèle.

Est-ce le cas, et si oui, pourquoi?

Mise à jour: lorsque j'ai posé la question, j'avais déjà la réponse de @ MasonWheeler en tête, alors je suis allée avec la réponse qui a le plus enrichi mes connaissances. Je pense que sa réponse est également valable.

Aaron Anodide
la source
2
Question connexe: programmers.stackexchange.com/questions/107723
Eric King
25
Non. En Python, l'utilisation d'exceptions comme flux de contrôle est considérée comme "pythonique".
user16764
4
Si je devais faire une telle chose en Java, je ne lirais certainement pas une exception. Je tirerais d'une hiérarchie non-Exception, non-Erreur, Throwable.
Thomas Eding
2
Pour ajouter aux réponses existantes, voici une brève directive qui m’a bien servi: - Ne jamais utiliser d’exceptions pour «la voie heureuse». Le chemin heureux peut être à la fois (pour le Web) la totalité de la demande ou simplement un objet / une méthode. Toutes les autres règles saines s'appliquent toujours, bien sûr :)
Houen
8
Les exceptions ne contrôlent-elles pas toujours le flux d'une application?

Réponses:

109

Il y a une discussion détaillée à ce sujet sur le Wiki de Ward . En règle générale, l'utilisation des exceptions pour le flux de contrôle est un anti-modèle, avec de nombreuses situations notable - et le langage spécifique (voir par exemple Python ) toux exceptions toux .

Voici un résumé rapide des raisons pour lesquelles c'est généralement un anti-modèle:

  • Les exceptions sont, en substance, des déclarations GOTO sophistiquées
  • La programmation avec des exceptions conduit donc à plus de difficulté à lire et à comprendre le code
  • La plupart des langues ont des structures de contrôle existantes conçues pour résoudre vos problèmes sans l'utilisation d'exceptions
  • Les arguments en faveur de l'efficacité tendent à être discutables pour les compilateurs modernes, qui ont tendance à optimiser en supposant que les exceptions ne sont pas utilisées pour le contrôle des flux.

Lisez la discussion sur le wiki de Ward pour des informations plus détaillées.


Voir aussi un duplicata de cette question, ici

les bleuets
la source
18
Votre réponse donne à penser que les exceptions sont mauvaises dans toutes les circonstances, alors que la question se concentre sur les exceptions en tant que contrôle de flux.
Whatsisname
14
@MasonWheeler La différence est que les boucles for / while contiennent leurs changements de contrôle de flux clairement et rendent le code facile à lire. Si vous voyez une instruction for dans votre code, vous n'avez pas à essayer de trouver quel fichier contient la fin de la boucle. Les Goto ne sont pas mauvais parce qu'un dieu a dit qu'ils l'étaient, ils sont mauvais simplement parce qu'ils sont plus difficiles à suivre que les constructions en boucle. Les exceptions sont similaires, pas impossibles mais suffisamment dures pour confondre les choses.
Bill K
24
@ BillK, soutenez cela, et ne faites pas de déclarations simplistes sur la façon dont les exceptions sont gotos.
Winston Ewert
6
D'accord, mais sérieusement, qu'y a-t-il entre les erreurs côté serveur et les développeurs d'applications qui cachent des erreurs avec des instructions de capture vides dans JavaScript? C'est un phénomène méchant qui m'a coûté beaucoup de temps et je ne sais pas comment demander sans râler. Les erreurs sont votre ami.
Erik Reppen
12
@mattnz: ifet foreachsont aussi des GOTOs sophistiqués . Franchement, je pense que la comparaison avec goto n'est pas utile; c'est presque comme un terme péjoratif. L'utilisation de GOTO n'est pas intrinsèquement mauvaise - elle pose de vrais problèmes et les exceptions peuvent les partager, mais pas nécessairement. Il serait plus utile d’entendre ces problèmes.
Eamon Nerbonne
110

Le cas d’utilisation pour lequel les exceptions ont été conçues est «Je viens de rencontrer une situation que je ne peux pas traiter correctement à ce stade, car je n’ai pas assez de contexte pour le gérer, mais la routine qui m’a appelé (ou quelque chose de plus avancé dans l’appel). pile) devrait savoir comment s'y prendre. "

Le cas d'utilisation secondaire est "Je viens de rencontrer une grave erreur, et pour le moment, sortir de ce flux de contrôle pour éviter la corruption des données ou d'autres dommages est plus important que d'essayer de continuer."

Si vous n'utilisez pas d'exceptions pour l'une de ces deux raisons, il existe probablement une meilleure façon de le faire.

Maçon Wheeler
la source
18
Cela ne répond pas à la question si. Ce pour quoi ils ont été conçus est sans importance; la seule chose qui soit pertinente est la raison pour laquelle leur utilisation pour le contrôle du flux est mauvaise, sujet que vous n'avez pas abordé. Par exemple, les modèles C ++ ont été conçus pour une chose, mais ils conviennent parfaitement à la métaprogrammation, une utilisation que les concepteurs n’ont jamais imaginée.
Thomas Bonini
6
@Krelp: Les concepteurs n'ont jamais anticipé beaucoup de choses, telles que la création d'un système de gabarit Turing-complete par accident! Les modèles C ++ ne sont guère un bon exemple à utiliser ici.
Mason Wheeler
15
@Krelp - Les modèles C ++ ne sont PAS parfaitement adaptés à la métaprogrammation. Ils sont un cauchemar jusqu'à ce que vous les obteniez bien, et ensuite ils tendent vers le code en écriture seule si vous n'êtes pas un génie du template. Vous voudrez peut-être choisir un meilleur exemple.
Michael Kohne
Les exceptions nuisent à la composition des fonctions en particulier et à la brièveté du code en général. Par exemple, alors que j'étais inexpérimenté, j'ai utilisé une exception dans un projet, ce qui a longtemps posé des problèmes, car 1) il faut que les gens se souviennent de l'attraper, 2) vous ne pouvez pas écrire, const myvar = theFunctioncar myvar doit être créé à partir d'essais-captures, ainsi ce n'est plus constant. Cela ne veut pas dire que je ne l'utilise pas en C #, car il s'agit d'un courant dominant pour une raison quelconque, mais j'essaie de le réduire quand même.
Bonjour Angel
2
@AndreasBonini En quoi ils sont conçus / destinés à des fins car cela aboutit souvent à des décisions d'implémentation du compilateur / framework / runtime alignées sur la conception. Par exemple, le lancement d'une exception peut être beaucoup plus «coûteux» qu'un simple retour car il collecte des informations destinées à aider quelqu'un à déboguer le code, telles que des traces de pile, etc.
binki
29

Les exceptions sont aussi puissantes que les Continuations et GOTO. Ils sont une construction de flux de contrôle universel.

Dans certaines langues, ils constituent la seule construction de flux de contrôle universelle. JavaScript, par exemple, n'a ni Continuations ni GOTOmême appels appropriés. Ainsi, si vous souhaitez implémenter un flux de contrôle sophistiqué en JavaScript, vous devez utiliser des exceptions.

Le projet Microsoft Volta était un projet de recherche (maintenant abandonné) visant à compiler du code .NET arbitraire en JavaScript. .NET a des exceptions dont la sémantique ne correspond pas exactement à JavaScript, mais plus important encore, il a des threads et vous devez les mapper en quelque sorte à JavaScript. Pour ce faire, Volta a mis en œuvre des suites Volta à l'aide d'exceptions JavaScript, puis toutes les structures de flux de contrôle .NET en termes de suites Volta. Ils ont dû utiliser Exceptions comme flux de contrôle, car il n'y a pas d'autre construction de flux de contrôle assez puissante.

Vous avez mentionné State Machines. Les SM sont simples à implémenter avec les appels de queue appropriés: chaque état est un sous-programme, chaque transition d'état est un appel de sous-programme. Les MS peuvent également être facilement implémentés avec GOTOou Coroutines ou Continuations. Cependant, Java ne dispose pas de ces quatre, mais il ne possède des exceptions. Il est donc parfaitement acceptable de les utiliser comme flux de contrôle. (En fait, le bon choix serait probablement d'utiliser un langage avec la structure de flux de contrôle appropriée, mais vous pouvez parfois être bloqué avec Java.)

Jörg W Mittag
la source
7
Si seulement nous avions eu la bonne récursion d’appels, nous aurions peut-être pu dominer le développement Web côté client avec JavaScript, puis poursuivre en se propageant côté serveur et mobile, en tant que solution pan-plate-forme ultime comme Wildfire. Hélas, mais ce n'était pas le cas. Bon sang, nos fonctions de première classe, nos bouclages et notre paradigme événementiel sont insuffisants. Ce dont nous avions vraiment besoin était la vraie chose.
Erik Reppen
20
@ErikReppen: Je réalise que vous êtes simplement sarcastique, mais. . . Je ne pense vraiment pas que le fait que nous ayons "dominé le développement Web côté client avec JavaScript" ait quelque chose à voir avec les fonctionnalités du langage. Elle a le monopole sur ce marché et a donc pu surmonter de nombreux problèmes qui ne peuvent être résolus avec sarcasme.
Ruakh
1
La récursion de la queue aurait été un bonus appréciable (les fonctions les dépréciant de l’avoir dans le futur) mais oui, je dirais qu’elle a gagné contre VB, Flash, Applets, etc. pour des raisons liées aux fonctionnalités. Si cela ne réduisait pas la complexité et ne normalisait pas aussi facilement, il y aurait eu une concurrence réelle à un moment donné. J'utilise actuellement Node.js pour gérer la réécriture de 21 fichiers de configuration pour une hideuse pile C # + Java et je sais que je ne suis pas le seul à le faire. C'est très bon à ce que c'est bon à.
Erik Reppen
1
Beaucoup de langues n'ont ni gotos (Goto considéré comme nuisibles!), Coroutines ou continuations et implémentent un contrôle de flux parfaitement valide en utilisant simplement ifs, whiles et appels de fonction (ou gosubs!). La plupart d’entre eux peuvent en fait être utilisés pour s’imiter, tout comme une continuation peut être utilisée pour représenter tout ce qui précède. (Par exemple, vous pouvez utiliser un certain temps pour effectuer un if, même si c'est une manière puante de coder). Donc, aucune exception n'est PAS nécessaire pour effectuer un contrôle de flux avancé.
Shayne
2
Eh bien oui, vous avez peut-être raison si. "For" dans sa forme de style C peut cependant être utilisé comme un argument maladroit, et un moment peut ensuite être utilisé en conjonction avec un if pour implémenter une machine à états finis qui peut ensuite émuler toutes les autres formes de contrôle de flux. Encore une fois, une mauvaise façon de coder, mais oui. Et encore, allez considéré comme nuisible. (Et je discuterais, donc aussi avec l'utilisation d'exceptions dans des circonstances non exceptionnelles). Gardez à l'esprit qu'il existe des langages parfaitement valides et très puissants qui ne fournissent ni goto ni exceptions et fonctionnent parfaitement.
Shayne
19

Comme d'autres l'ont mentionné à maintes reprises ( par exemple dans cette question de dépassement de pile ), le principe du moindre étonnement interdira que vous utilisiez des exceptions de manière excessive à des fins de contrôle de flux uniquement. D'un autre côté, aucune règle n'est exacte à 100%, et il existe toujours des cas dans lesquels une exception est "juste le bon outil" - un peu comme gotoelle, d'ailleurs, livrée sous forme breaket continuedans des langages comme Java, qui sont souvent le moyen idéal pour sortir de boucles fortement imbriquées, qui ne sont pas toujours évitables.

Le billet de blog suivant explique un cas d'utilisation assez complexe mais également intéressant pour un non-local ControlFlowException :

Il explique comment, à l’intérieur de jOOQ (une bibliothèque d’abstractions SQL pour Java) (disclaimer: je travaille pour le fournisseur), de telles exceptions sont parfois utilisées pour abandonner le processus de rendu SQL plus tôt lorsque certaines conditions "rares" sont remplies.

Des exemples de telles conditions sont:

  • Trop de valeurs de liaison sont rencontrées. Certaines bases de données ne prennent pas en charge les nombres arbitraires de valeurs de liaison dans leurs instructions SQL (SQLite: 999, Ingres 10.1.0: 1024, Sybase ASE 15.5: 2000, SQL Server 2008: 2100). Dans ces cas, jOOQ abandonne la phase de rendu SQL et rend à nouveau l'instruction SQL avec des valeurs de liaison intégrées. Exemple:

    // Pseudo-code attaching a "handler" that will
    // abort query rendering once the maximum number
    // of bind values was exceeded:
    context.attachBindValueCounter();
    String sql;
    try {
    
      // In most cases, this will succeed:
      sql = query.render();
    }
    catch (ReRenderWithInlinedVariables e) {
      sql = query.renderWithInlinedBindValues();
    }

    Si nous extrayions explicitement les valeurs de liaison de la requête AST pour les compter à chaque fois, nous gaspillerions des cycles de processeur précieux pour ces 99,9% des requêtes qui ne souffrent pas de ce problème.

  • Certaines logiques ne sont disponibles qu'indirectement via une API que nous voulons exécuter seulement "partiellement". La UpdatableRecord.store()méthode génère une instruction INSERTou UPDATE, en fonction Recorddes indicateurs internes de. De "l'extérieur", nous ne savons pas quel type de logique est contenu dans store()(par exemple, le verrouillage optimiste, la gestion d'écouteurs d'événements, etc.), nous ne voulons donc pas répéter cette logique lorsque nous stockons plusieurs enregistrements dans une instruction batch. où nous aimerions avoir store()seulement générer l’instruction SQL, pas réellement l’exécuter. Exemple:

    // Pseudo-code attaching a "handler" that will
    // prevent query execution and throw exceptions
    // instead:
    context.attachQueryCollector();
    
    // Collect the SQL for every store operation
    for (int i = 0; i < records.length; i++) {
      try {
        records[i].store();
      }
    
      // The attached handler will result in this
      // exception being thrown rather than actually
      // storing records to the database
      catch (QueryCollectorException e) {
    
        // The exception is thrown after the rendered
        // SQL statement is available
        queries.add(e.query());                
      }
    }

    Si nous avions externalisé la store()logique en une API "réutilisable" pouvant être personnalisée pour éventuellement ne pas exécuter le code SQL, nous envisagerions de créer une API plutôt difficile à maintenir, à peine réutilisable.

Conclusion

Essentiellement, notre utilisation de ces messages non locaux gotova dans le sens de ce que Mason Wheeler a dit dans sa réponse:

"Je viens de rencontrer une situation que je ne peux pas gérer correctement à ce stade, parce que je n’ai pas assez de contexte pour le gérer, mais la routine qui m’a appelé (ou quelque chose plus haut dans la pile d’appel) doit savoir comment le gérer. . "

Les deux utilisations de ControlFlowExceptionsétaient plutôt faciles à mettre en œuvre par rapport à leurs alternatives, ce qui nous permettait de réutiliser une large gamme de logique sans la refactoriser à partir des éléments internes pertinents.

Mais le sentiment d'être un peu surprenant pour les futurs responsables reste. Le code est plutôt délicat et, même s’il s’agissait du bon choix dans ce cas, nous préférerions toujours ne pas utiliser d’exceptions pour les flux de contrôle locaux , où il est facile d’éviter l’utilisation de ramifications ordinaires if - else.

Lukas Eder
la source
11

L'utilisation d'exceptions pour le contrôle de flux est généralement considérée comme un anti-modèle, mais il existe des exceptions (sans jeu de mots).

On a dit mille fois que les exceptions sont destinées à des conditions exceptionnelles. Une connexion de base de données rompue est une condition exceptionnelle. Un utilisateur qui entre des lettres dans un champ de saisie qui ne devrait autoriser que des chiffres ne l’est pas .

Un bogue dans votre logiciel qui provoque l’appel d’une fonction avec des arguments illégaux, par exemple, nulllorsque non autorisé, est une condition exceptionnelle.

En utilisant des exceptions pour quelque chose qui n'est pas exceptionnel, vous utilisez des abstractions inappropriées pour le problème que vous essayez de résoudre.

Mais il peut aussi y avoir une pénalité de performance. Certaines langues ont une implémentation plus ou moins efficace de la gestion des exceptions. Par conséquent, si votre langue de choix ne permet pas une gestion efficace des exceptions, elle peut être très coûteuse en termes de performances *.

Mais d'autres langages, par exemple Ruby, ont une syntaxe semblable à une exception pour le flux de contrôle. Les situations exceptionnelles sont gérées par les opérateurs raise/ rescue. Mais vous pouvez utiliser throw/ catchpour des constructions de flux de contrôle semblables à des exceptions **.

Ainsi, bien que les exceptions ne soient généralement pas utilisées pour le contrôle de flux, votre langue de choix peut avoir d'autres idiomes.

* En exemple d'une utilisation coûteuse d'exceptions coûteuse: J'étais auparavant configuré pour optimiser une application ASP.NET Web Form peu performante. Il s’est avéré que le rendu d’une grande table demandait int.Parse()env. un millier de chaînes vides sur une page moyenne, ce qui donne env. mille exceptions sont traitées. En remplaçant le code par int.TryParse()je me suis rasé une seconde! Pour chaque demande de page!

** Cela peut être très déroutant pour un programmeur venant d’autres langues throwet qui catchsont des mots-clés associés à des exceptions dans de nombreuses autres langues.

Pete
la source
1
+1 pour "En utilisant des exceptions pour quelque chose qui n'est pas exceptionnel, vous utilisez des abstractions inappropriées pour le problème que vous essayez de résoudre."
Giorgio
8

Il est tout à fait possible de gérer les conditions d'erreur sans utiliser d'exceptions. Certaines langues, notamment le C, ne comportent même pas d'exception et les utilisateurs parviennent toujours à créer des applications assez complexes avec. Les exceptions pour lesquelles les exceptions sont utiles sont qu'elles vous permettent de spécifier succinctement deux flux de contrôle essentiellement indépendants dans le même code: un si une erreur se produit et un autre si ce n'est pas le cas. Sans eux, vous vous retrouvez avec un code qui ressemble à ceci:

status = getValue(&inout);
if (status < 0)
{
    logError("message");
    return status;
}

doSomething(*inout);

Ou l'équivalent dans votre langue, par exemple renvoyer un tuple avec une valeur comme statut d'erreur, etc. Souvent, les personnes qui indiquent à quel point la gestion des exceptions est "coûteuse" négligent toutes les ifdéclarations supplémentaires , comme ci-dessus, que vous devez ajouter si vous ne le faites pas. t utiliser des exceptions.

Bien que cette tendance se produise le plus souvent lorsque des erreurs ou d’autres "conditions exceptionnelles" sont gérées, à mon avis, si vous commencez à voir un code standard semblable à celui-ci dans d’autres circonstances, vous disposez d’un très bon argument pour utiliser des exceptions. Selon la situation et l'implémentation, je peux voir que des exceptions sont utilisées correctement dans une machine à états, car vous avez deux flux de contrôle orthogonaux: un qui modifie l'état et l'autre pour les événements qui se produisent dans les états.

Cependant, ces situations sont rares et si vous faites une exception (jeu de mots) à la règle, vous feriez mieux de vous préparer à montrer sa supériorité par rapport à d'autres solutions. Une déviation sans cette justification s'appelle à juste titre un anti-modèle.

Karl Bielefeldt
la source
2
Tant que les instructions if n'échouent que dans des circonstances «exceptionnelles», la logique de prédiction de branche des processeurs modernes rend leur coût négligeable. C'est un endroit où les macros peuvent réellement aider, à condition de faire attention et de ne pas trop en faire.
James
5

En Python, les exceptions sont utilisées pour le générateur et la fin de l'itération. Python a des blocs try / except très efficaces, mais le fait de lever une exception a toutefois un coût supplémentaire.

En raison du manque de sauts multi-niveaux ou d'une instruction goto en Python, j'ai parfois utilisé des exceptions:

class GOTO(Exception):
  pass

try:
  # Do lots of stuff
  # in here with multiple exit points
  # each exit point does a "raise GOTO()"
except GOTO:
  pass
except Exception as e:
  #display error
gahooa
la source
6
Si vous devez terminer le calcul quelque part dans une instruction profondément imbriquée et accéder à un code de continuation commun, ce chemin d'exécution particulier peut très probablement être factorisé comme une fonction, returnà la place de goto.
9000
3
@ 9000 J'étais sur le point de commenter exactement la même chose ... Gardez les try:blocs à 1 ou 2 lignes s'il vous plaît, jamais try: # Do lots of stuff.
wim
1
@ 9000, dans certains cas, bien sûr. Mais ensuite, vous perdez l'accès aux variables locales et vous déplacez votre code à un autre endroit, lorsque le processus est un processus cohérent et linéaire.
Gahooa
4
@gahooa: Je pensais comme toi. C'était un signe de mauvaise structure de mon code. En y réfléchissant davantage, j'ai remarqué que les contextes locaux peuvent être démêlés et que tout le gâchis peut être transformé en fonctions courtes avec peu de paramètres, peu de lignes de code et une signification très précise. Je n'ai jamais regardé en arrière.
9000
4

Esquissons un tel usage de l'exception:

L'algorithme cherche récursivement jusqu'à ce que quelque chose soit trouvé. Donc, pour revenir de la récursivité, il faut vérifier le résultat et le retourner, sinon, continuez. Et cela revient à plusieurs reprises d'une certaine profondeur de récursivité.

En plus d'avoir besoin d'un booléen supplémentaire found(pour être emballé dans une classe, sinon, seul un int aurait été renvoyé), et pour la profondeur de récursion, le même postlude se produit.

Un tel dénouement d’une pile d’appels n’est qu’une exception. Il me semble donc qu’il s’agit d’un moyen de codage non similaire à celui du goto, plus immédiat et plus approprié. Pas nécessaire, usage rare, peut-être un mauvais style, mais au point. Comparable à l'opération de coupe Prolog.

Joop Eggen
la source
Hmm, le vote négatif concerne-t-il la position effectivement contraire, ou l'argumentation insuffisante ou brève? Je suis vraiment curieux.
Joop Eggen
Je suis confronté exactement à cette situation difficile, j'espérais que vous pourriez voir ce que vous pensez de ma question suivante? Utilisation récursive d'exceptions pour accumuler le motif (message) d'une exception de niveau supérieur codereview.stackexchange.com/questions/107862/…
CL22
@Jodes Je viens de lire votre technique intéressante, mais je suis assez occupé pour l'instant. J'espère que quelqu'un d'autre nous éclairera sur la question.
Joop Eggen
4

La programmation concerne le travail

Je pense que la meilleure façon de répondre à cette question est de comprendre les progrès réalisés par OOP au fil des ans. Tout ce qui est fait dans la POO (et la plupart des paradigmes de programmation, d'ailleurs) est modelé sur le besoin de travail .

Chaque fois qu'une méthode est appelée, l'appelant dit "Je ne sais pas comment faire ce travail, mais vous savez comment, alors vous le faites pour moi".

Cela présentait une difficulté: que se passe-t-il lorsque la méthode appelée sait généralement comment faire le travail, mais pas toujours? Nous avions besoin d'un moyen de communiquer "Je voulais vous aider, je l'ai vraiment fait, mais je ne peux pas le faire."

Une des premières méthodes utilisées pour communiquer cela consistait simplement à renvoyer une valeur "déchet". Peut-être que vous vous attendez à un entier positif, la méthode appelée renvoie donc un nombre négatif. Pour ce faire, vous pouvez également définir une valeur d'erreur quelque part. Malheureusement, les deux méthodes ont abouti à ce que le code caché soit complet . Au fur et à mesure que les choses se compliquent, ce système s'effondre.

Une analogie exceptionnelle

Disons que vous avez un charpentier, un plombier et un électricien. Vous voulez que le plombier répare votre évier, alors il l'examine. Ce n'est pas très utile s'il vous dit seulement: "Désolé, je ne peux pas le réparer. C'est cassé." Enfer, c'est encore pire s'il jetait un coup d'œil, partait et vous envoyait une lettre vous disant qu'il ne pouvait pas le réparer. Maintenant, vous devez vérifier votre courrier avant même de savoir qu'il n'a pas fait ce que vous vouliez.

Ce que vous préférez, c'est qu'il vous le dise: "Ecoute, je ne pourrais pas régler le problème, car il me semble que ta pompe ne fonctionne pas."

Avec ces informations, vous pouvez en conclure que vous souhaitez que l’électricien examine le problème. L'électricien trouvera peut-être un élément lié au menuisier et vous devrez le faire réparer par le menuisier.

Heck, vous ne savez peut-être même pas que vous avez besoin d'un électricien, vous ne savez peut-être pas de qui vous avez besoin. Vous êtes juste un cadre dans une entreprise de réparation de maison et votre objectif est la plomberie. Vous dites donc que vous êtes le chef du problème, puis il demande à l'électricien de le régler.

C’est ce que les exceptions modélisent: les modes de défaillance complexes de manière découplée. Le plombier n'a pas besoin de savoir à propos d'électricien - il n'a même pas besoin de savoir que quelqu'un en amont peut résoudre le problème. Il ne fait que rendre compte du problème rencontré.

Alors ... un anti-motif?

Ok, la première étape consiste donc à comprendre le point des exceptions. La prochaine consiste à comprendre ce qu'est un anti-modèle.

Pour être qualifié d'anti-pattern, il faut

  • résoudre le problème
  • avoir des conséquences définitivement négatives

Le premier point est facilement satisfait - le système a fonctionné, non?

Le deuxième point est plus collant. La principale raison d'utiliser des exceptions en tant que flux de contrôle normal est mauvaise, car ce n'est pas leur objectif. Toute fonctionnalité donnée dans un programme doit avoir un objectif relativement clair, et la cooptation de cet objectif crée une confusion inutile.

Mais ce n'est pas un préjudice définitif . C'est une mauvaise façon de faire les choses, et bizarre, mais un anti-modèle? Non, juste ... étrange.

MirroredFate
la source
Il y a une mauvaise conséquence, du moins dans les langues fournissant une trace complète de la pile. Comme le code est fortement optimisé avec beaucoup d'inlining, la trace de pile réelle et celle qu'un développeur souhaite voir diffèrent beaucoup et, par conséquent, la génération de trace de pile est coûteuse. L'abus des exceptions est très mauvais pour la performance dans de tels langages (Java, C #).
Maaartinus
"C'est une mauvaise façon de faire les choses" - Cela ne devrait-il pas suffire à le classer comme anti-modèle?
Maybe_Factor
@ Maybe_Factor Par la définition d'un motif ant, non.
MirroredFate