web-dev-qa-db-fra.com

Conventions pour les exceptions ou les codes d'erreur

Hier, j’avais un débat animé avec un collègue sur la méthode de rapport d’erreur privilégiée. Nous avons principalement discuté de l'utilisation d'exceptions ou de codes d'erreur pour signaler des erreurs entre des couches d'application ou des modules.

Quelles règles utilisez-vous pour décider si vous déclenchez des exceptions ou si vous retournez des codes d'erreur pour signaler les erreurs?

96
Jorge Ferreira

Je préfère normalement les exceptions, car elles ont plus d'informations contextuelles et peuvent transmettre (lorsqu'elles sont correctement utilisées) l'erreur au programmeur de manière plus claire.

D'autre part, les codes d'erreur sont plus légers que les exceptions, mais ils sont plus difficiles à gérer. Une vérification d'erreur peut être omise par inadvertance. Les codes d'erreur sont plus difficiles à gérer car vous devez conserver un catalogue avec tous les codes d'erreur, puis activer le résultat pour voir quelle erreur a été générée. Les plages d'erreur peuvent être utiles ici, car si la seule chose qui nous intéresse, si nous sommes en présence ou non d'une erreur, il est plus simple de vérifier (par exemple, un code d'erreur HRESULT supérieur ou égal à 0 est succès moins de zéro est un échec). Ils peuvent être omis par inadvertance, car le développeur ne doit pas forcément vérifier par code les codes d'erreur. D'autre part, vous ne pouvez pas ignorer les exceptions.

Pour résumer, je préfère les exceptions aux codes d'erreur dans presque toutes les situations.

51
Jorge Ferreira

En haut niveau, des exceptions; en bas niveau des choses, des codes d'erreur.

Le comportement par défaut d'une exception est de dérouler la pile et d'arrêter le programme. Si j'écris un script et que je recherche une clé qui n'est pas dans un dictionnaire, c'est probablement une erreur, et je veux que le programme s'arrête et me laisse tout savoir à ce sujet.

Si, toutefois, j'écris un morceau de code dont je dois connaître le comportement dans toutes les situations possibles, alors je veux des codes d'erreur. Sinon, je dois connaître toutes les exceptions pouvant être émises par chaque ligne de ma fonction pour savoir ce qu’elle fera (Lire L’exception qui fonde une compagnie aérienne pour avoir une idée de la complexité de cette opération). Il est fastidieux et difficile d'écrire du code qui réagisse de manière appropriée à chaque situation (y compris aux malheureux), mais c'est parce qu'écrire du code sans erreur est fastidieux et difficile, et non pas parce que vous transmettez des codes d'erreur.

Les deux Raymond ChenetJoel ont formulé des arguments éloquents contre l'utilisation d'exceptions pour tout.

78
Tom Dunham

Je préfère les exceptions parce que

  • ils interrompent le flux de la logique
  • ils bénéficient de la hiérarchie des classes qui donne plus de fonctionnalités/fonctionnalités
  • lorsqu'il est utilisé correctement, il peut représenter un large éventail d'erreurs (par exemple, une exception InvalidMethodCallException est également une exception LogicException, car les deux se produisent lorsqu'un bogue dans votre code doit être détectable avant l'exécution)
  • elles peuvent être utilisées pour améliorer l'erreur (c'est-à-dire qu'une définition de classe FileReadException peut ensuite contenir du code pour vérifier si le fichier existe, s'il est verrouillé, etc.)
22
JamShady

Les codes d'erreur peuvent être ignorés (et le sont souvent!) Par les appelants de vos fonctions. Les exceptions les forcent au moins à traiter l'erreur d'une manière ou d'une autre. Même si leur version consiste à avoir un gestionnaire de captures vide (soupir).

17
Maxam

Exceptions sur les codes d'erreur, sans aucun doute à ce sujet. Les exceptions offrent les mêmes avantages que les codes d’erreur, mais aussi bien plus, sans les inconvénients des codes d’erreur Le seul inconvénient, c’est qu’il est légèrement plus onéreux; mais de nos jours, ces frais généraux devraient être considérés comme négligeables pour presque toutes les applications.

Voici quelques articles discutant, comparant et contrastant les deux techniques:

Il existe de bons liens dans ceux qui peuvent vous donner des lectures supplémentaires.

15
Pistos

Je ne mélangerais jamais les deux modèles ... Il est trop difficile de passer de l'un à l'autre lorsque vous passez d'une partie de la pile qui utilise des codes d'erreur à une partie supérieure qui utilise des exceptions.

Les exceptions concernent "tout ce qui empêche ou empêche la méthode ou le sous-programme de faire ce que vous lui avez demandé de faire" ... NE PAS renvoyer de messages à propos d'irrégularités ou de circonstances inhabituelles, ni sur l'état du système, etc. (ou out) paramètres pour cela.

Les exceptions permettent aux méthodes d'être écrites (et utilisées) avec une sémantique dépendant de la fonction de la méthode, c'est-à-dire qu'une méthode qui retourne un objet Employé ou une liste d'employés peut être typée pour le faire, et que vous pouvez l'utiliser en appelant. 

Employee EmpOfMonth = GetEmployeeOfTheMonth();

Avec les codes d'erreur, toutes les méthodes renvoient un code d'erreur. Par conséquent, pour celles qui doivent renvoyer quelque chose d'autre à utiliser par le code appelant, vous devez transmettre une variable de référence à renseigner avec ces données et tester la valeur de retour pour le paramètre. code d'erreur et le gérer à chaque appel de fonction ou de méthode.

Employee EmpOfMonth; 
if (getEmployeeOfTheMonth(ref EmpOfMonth) == ERROR)
    // code to Handle the error here

Si vous codez pour que chaque méthode ne fasse qu'une et une seule chose simple, vous devriez alors lever une exception chaque fois que la méthode ne peut pas atteindre l'objectif souhaité de la méthode. Les exceptions sont beaucoup plus riches et faciles à utiliser de cette façon que les codes d'erreur. Votre code est beaucoup plus propre - Le flux standard du chemin de code "normal" peut être consacré strictement au cas où la méthode IS est capable d'accomplir ce que vous vouliez qu'elle fasse ... Et ensuite le code à nettoyer ou gérer les circonstances "exceptionnelles" en cas de problème empêchant la méthode de fonctionner correctement peut être éliminé du code normal. De plus, si vous ne pouvez pas gérer l’exception où elle s’est produite et que vous devez transmettre la pile à une interface utilisateur (ou pire, d’un composant de niveau intermédiaire à une interface utilisateur), vous pouvez alors utiliser le modèle d’exception. vous n'avez pas besoin de coder chaque méthode intermédiaire de votre pile pour reconnaître et faire passer l'exception sur la pile ... Le modèle d'exception le fait automatiquement pour vous .... Avec les codes d'erreur, cette pièce du puzzle peut devenir très pénible très rapidement .

14
Charles Bretana

Il peut y avoir quelques situations où utiliser des exceptions de manière propre, claire et correcte est fastidieux, mais la grande majorité des exceptions de temps constituent un choix évident. Le principal avantage des exceptions en matière de gestion des codes d’erreur réside dans le fait qu’il modifie le flux d’exécution, ce qui est important pour deux raisons.

Lorsqu'une exception se produit, l'application ne suit plus son chemin d'exécution "normal". La première raison pour laquelle cela est si important est que, à moins que l'auteur du code ne soit vraiment mauvais, le programme s'arrête et ne continue pas à faire des choses imprévisibles. Si un code d'erreur n'est pas vérifié et que les actions appropriées ne sont pas entreprises en réponse à un code d'erreur incorrect, le programme continuera à faire ce qu'il est en train de faire et qui sait quel sera le résultat de cette action. Dans de nombreux cas, le fait de faire ce programme peut coûter très cher. Envisagez un programme qui récupère des informations sur les performances de divers instruments financiers vendus par une société et fournit ces informations aux courtiers/grossistes. Si quelque chose ne va pas et que le programme continue, il pourrait envoyer des données de performance erronées aux courtiers et aux grossistes. Je ne connais personne d'autre, mais je ne veux pas être celui qui siège dans un bureau de vice-président pour expliquer pourquoi mon code a poussé la société à se voir imposer une amende réglementaire correspondant à 7 chiffres. Il est généralement préférable d'envoyer un message d'erreur aux clients plutôt que de fournir des données erronées qui pourraient sembler «réelles». Cette dernière situation est beaucoup plus facile à gérer avec une approche beaucoup moins agressive, telle que les codes d'erreur.

La deuxième raison pour laquelle j'aime les exceptions et leur interruption de l'exécution normale est qu'il est beaucoup plus facile de garder la logique "les choses normales se passent" séparément de la "logique qui a mal tourné". Pour moi, ceci:

try {
    // Normal things are happening logic
catch (// A problem) {
    // Something went wrong logic
}

... est préférable à ceci:

// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}
// Some normal stuff logic
if (errorCode means error) {
    // Some stuff went wrong logic
}

Il y a d'autres petites choses au sujet des exceptions qui sont Nice, aussi. Avoir un code d'erreur renvoyé par toute une série de logiques conditionnelles permettant de savoir si l'une des méthodes appelées dans une fonction a été renvoyée et renvoyé ce code d'erreur plus haut, cela prend beaucoup de temps. En fait, il y a beaucoup de problèmes de chaudière. J'ai beaucoup plus confiance dans le système d'exception de la plupart des langues que dans un nid de rats énonçant des déclarations if-else-if-else selon lesquelles 'Fred a récemment écrit', et j'ai beaucoup mieux à faire avec mon temps que le code en revue ledit nid de rat.

10
Dogs

Dans le passé, j'ai rejoint le camp errorcode (trop de programmation en C). Mais maintenant j'ai vu la lumière. 

Oui, les exceptions représentent un fardeau pour le système. Mais ils simplifient le code en réduisant le nombre d'erreurs (et de WTF).

Donc utilisez exception mais utilisez-les judicieusement. Et ils seront ton ami.

En note de côté. J'ai appris à documenter quelle exception peut être levée par quelle méthode. Malheureusement, cela n’est pas requis par la plupart des langues. Mais cela augmente les chances de gérer les bonnes exceptions au bon niveau.

9
Toon Krijthe

Vous devriez utiliser les deux. La chose est de décider quand utiliser chacun.

Il existe quelques quelques scénarios dans lesquels les exceptions constituent le choix évident:

  1. Dans certaines situations, vous ne pouvez rien faire avec le code d'erreur et vous devez simplement le gérer à un niveau supérieur de la pile d'appels, généralement, enregistrez simplement l'erreur, affichez quelque chose à l'utilisateur ou fermer le programme. Dans ces cas, les codes d'erreur vous obligeraient à les éjecter manuellement, niveau par niveau, ce qui est évidemment beaucoup plus facile à faire avec des exceptions. Le fait est que cela concerne des situations inattendues et non gérables.

  2. Cependant, à propos de la situation 1 (où quelque chose d’inattendu et d’inconfortable se produit et que vous ne voulez pas simplement la consigner), des exceptions peuvent être utiles car vous pouvez ajouter des informations contextuelles. Par exemple, si j'obtiens une exception SqlException dans mes assistants de données de niveau inférieur, je voudrai intercepter cette erreur en bas niveau (où je connais la commande SQL qui a provoqué l'erreur) afin de pouvoir capturer cette information et pour afficher à nouveau avec des informations supplémentaires. S'il vous plaît noter le mot magique ici: Rethrow, et ne pas avaler. Première règle de gestion des exceptions: ne pas avaler les exceptions . En outre, notez que ma capture interne n'a pas besoin de journaliser quoi que ce soit car la capture externe aura la trace entière de la pile et pourra la journaliser.

  3. Dans certaines situations, vous avez une séquence de commandes et si l’une d’elles échoue, vous devriez nettoyer/disposer des ressources (*), qu’il s’agisse ou non d’une situation irrécupérable (qui doit être lancée) ou situation récupérable (auquel cas vous pouvez gérer localement ou dans le code de l'appelant mais vous n'avez pas besoin d'exceptions). Évidemment, il est beaucoup plus facile de mettre toutes ces commandes en un seul essai, au lieu de tester les codes d'erreur après chaque méthode et de nettoyer/éliminer dans le bloc finally. Veuillez noter que si vous voulez que l'erreur soit corrigée (ce qui est probablement ce que vous voulez), vous n'avez même pas besoin de l'attraper - vous utilisez simplement la commande finally pour le nettoyage/éliminer - vous ne devez utiliser que l'attrape/reculer si vous souhaitez ajouter des informations contextuelles (voir point 2). 

    Un exemple serait une séquence d'instructions SQL à l'intérieur d'un bloc de transaction. Encore une fois, c’est aussi une situation "incontrôlable", même si vous décidez de l’attaquer tôt (traitez-la localement au lieu de la faire bouillonner au maximum), c’est toujours une situation fatale dans laquelle le meilleur résultat est d’avorter tout ou moins avorter une grande partie du processus.
    (*) Cela ressemble au on error goto que nous utilisions dans l’ancien Visual Basic

  4. Dans les constructeurs, vous ne pouvez lancer que des exceptions.

Cela dit, dans toutes les autres situations où vous renvoyez des informations sur lesquelles l'appelant PEUT/DEVRAIT agir,, l'utilisation de codes de retour est probablement une meilleure solution. Cela inclut toutes les "erreurs" attendues, car elles devraient probablement être gérées par l'appelant immédiat, et il sera à peine nécessaire de faire remonter les niveaux de la pile.

Bien sûr, il est toujours possible de traiter les erreurs attendues comme des exceptions, puis de capturer immédiatement un niveau supérieur. Il est également possible de regrouper chaque ligne de code dans une tentative de capture et de prendre des mesures pour chaque erreur possible. OMI, c’est une mauvaise conception, non seulement parce que beaucoup plus verbeuse, mais surtout parce que les exceptions possibles qui pourraient être levées ne sont pas évidentes sans la lecture du code source - et que des exceptions pourraient être levées depuis n’importe quelle méthode en profondeur, en créant invisible. aller à S . Ils cassent la structure du code en créant plusieurs points de sortie invisibles rendant le code difficile à lire et à inspecter. En d'autres termes, vous ne devez jamais utiliser exceptions en tant que flow-control, car il serait difficile à comprendre et à gérer pour les autres. Il peut même devenir difficile de comprendre tous les flux de code possibles pour les tests.
Encore une fois: pour un nettoyage/élimination correct, vous pouvez utiliser try-finally sans rien attraper.

La critique la plus répandue à propos des codes de retour est qu '"une personne peut ignorer les codes d'erreur, mais dans le même sens, elle peut aussi avaler des exceptions. La gestion des exceptions est facile dans les deux méthodes. Mais écrire une bonne erreur- programme basé sur code est toujours beaucoup plus facile que d’écrire un programme basé sur exception . Et si, pour une raison quelconque, décide d’ignorer toutes les erreurs (l’ancien on error resume next), vous pouvez facilement le faire avec des codes de retour et vous ne pouvez pas faites-le sans trop d'essais.

La deuxième critique la plus répandue au sujet des codes de retour est qu'il est "difficile de faire une bulle", mais c'est parce que les gens ne comprennent pas que les exceptions s'appliquent aux situations non récupérables, contrairement aux codes d'erreur. 

Le choix entre les exceptions et les codes d'erreur est une zone grise. Il est même possible que vous deviez obtenir un code d'erreur à partir d'une méthode métier réutilisable, puis vous décidez de l'intégrer dans une exception (éventuellement en ajoutant des informations) et de le laisser bouillonner. Mais c’est une erreur de conception de supposer que TOUTES les erreurs doivent être levées comme des exceptions.Résumer:.

  • .

  • Cette différence entre les exceptions et les codes d'erreur est l'un des principes de conception du langage GO, qui utilise la "panique" pour les situations inattendues fatales, tandis que les situations attendues habituelles sont renvoyées sous forme d'erreurs.

Pourtant, à propos de GO, il permet également plusieurs valeurs de retour , ce qui est très utile lors de l’utilisation de codes de retour, puisque vous pouvez simultanément renvoyer une erreur et autre chose. Sur C #/Java, nous pouvons y parvenir sans paramètres, Tuples ou (mon préféré) Génériques, qui, combinés à des énumérations, peuvent fournir des codes d'erreur clairs à l'appelant:.

public MethodResult<CreateOrderResultCodeEnum, Order> CreateOrder(CreateOrderOptions options) { .... return MethodResult<CreateOrderResultCodeEnum>.CreateError(CreateOrderResultCodeEnum.NO_DELIVERY_AVAILABLE, "There is no delivery service in your area"); ... return MethodResult<CreateOrderResultCodeEnum>.CreateSuccess(CreateOrderResultCodeEnum.SUCCESS, order); } var result = CreateOrder(options); if (result.ResultCode == CreateOrderResultCodeEnum.OUT_OF_STOCK) // do something else if (result.ResultCode == CreateOrderResultCodeEnum.SUCCESS) order = result.Entity; // etc...

If I add a new possible return in my method, I can even check all callers if they are covering that new value in a switch statement for example. You really can't do that with exceptions. When you use return codes, you'll usually know in advance all possible errors, and test for them. With exceptions you usually don't know what might happen. Wrapping enums inside exceptions (instead of Generics) is an alternative (as long as it's clear the type of exceptions that each method will throw), but IMO it's still bad design.

5
drizin

Je suis peut-être assis sur la clôture ici, mais ...

  1. Cela dépend de la langue.
  2. Quel que soit le modèle que vous choisissez, soyez cohérent quant à la manière dont vous l'utilisez.

En Python, l'utilisation d'exceptions est une pratique courante, et je suis assez heureux de définir mes propres exceptions. En C, vous n’avez pas d’exception du tout.

En C++ (du moins en STL), les exceptions ne sont généralement générées que pour des erreurs vraiment exceptionnelles (je ne les vois pratiquement jamais). Je ne vois aucune raison de faire quelque chose de différent dans mon propre code. Oui, il est facile d'ignorer les valeurs renvoyées, mais C++ ne vous oblige pas non plus à intercepter des exceptions. Je pense que vous devez juste prendre l'habitude de le faire.

La base de code sur laquelle je travaille est principalement C++ et nous utilisons des codes d'erreur presque partout, mais il existe un module qui soulève des exceptions pour toute erreur, y compris très peu exceptionnelles, et tout le code qui utilise ce module est assez horrible. Mais c'est peut-être simplement parce que nous avons mélangé des exceptions et des codes d'erreur. Le code qui utilise systématiquement les codes d'erreur est beaucoup plus facile à utiliser. Si notre code utilisait systématiquement des exceptions, peut-être que ce ne serait pas aussi grave. Mélanger les deux ne semble pas fonctionner si bien.

4
jrb

Depuis que je travaille avec C++ et que je dispose de la norme RAII pour une utilisation en toute sécurité, j’utilise les exceptions presque exclusivement. Il extrait le traitement des erreurs du flux de programme normal et rend l'intention plus claire. 

Je laisse des exceptions pour des circonstances exceptionnelles cependant. Si je m'attends à ce qu'une certaine erreur se produise beaucoup, je vérifierai que l'opération aboutira avant de l'exécuter ou j'appellerai une version de la fonction utilisant des codes d'erreur à la place (comme TryParse())

4
Eclipse

Mon approche est que nous pouvons utiliser les deux codes d’exception et d’erreur en même temps. 

Je suis habitué à définir plusieurs types d'exceptions (ex: DataValidationException ou ProcessInterruptExcepion) et à l'intérieur de chaque exception, à définir une description plus détaillée de chaque problème.

Un exemple simple en Java:

public class DataValidationException extends Exception {


    private DataValidation error;

    /**
     * 
     */
    DataValidationException(DataValidation dataValidation) {
        super();
        this.error = dataValidation;
    }


}

enum DataValidation{

    TOO_SMALL(1,"The input is too small"),

    TOO_LARGE(2,"The input is too large");


    private DataValidation(int code, String input) {
        this.input = input;
        this.code = code;
    }

    private String input;

    private int code;

}

De cette façon, j'utilise des exceptions pour définir les erreurs de catégorie et des codes d'erreur pour définir des informations plus détaillées sur le problème.

3
sakana

Les signatures de méthode doivent vous communiquer le travail de la méthode. Quelque chose comme long errorCode = getErrorCode (); pourrait convenir, mais long errorCode = fetchRecord (); est déroutant.

3
Paul Croarkin

Mon raisonnement serait que si vous écrivez un pilote de bas niveau qui a vraiment besoin de performances, utilisez des codes d'erreur. Mais si vous utilisez ce code dans une application de niveau supérieur et qu'il peut gérer un peu de surcharge, enveloppez-le ensuite d'une interface qui vérifie ces codes d'erreur et déclenche des exceptions.

Dans tous les autres cas, les exceptions sont probablement la voie à suivre.

3
Claudiu

Les exceptions concernent les {exceptionnelles} _ circonstances, c'est-à-dire lorsqu'elles ne font pas partie du flux normal du code. 

Il est tout à fait légitime de mélanger des exceptions et des codes d'erreur, les codes d'erreur représentant le statut de quelque chose plutôt qu'une erreur dans l'exécution du code en soi (par exemple, vérifier le code de retour d'un processus enfant).

Mais quand une circonstance exceptionnelle se produit, j’estime que les exceptions sont le modèle le plus expressif.

Dans certains cas, vous pouvez préférer ou devoir utiliser des codes d'erreur à la place des exceptions, et ceux-ci ont déjà été traités de manière adéquate (autres que d'autres contraintes évidentes telles que le support du compilateur).

Mais en allant dans le sens inverse, utiliser Exceptions vous permet de créer des abstractions de niveau encore plus élevé pour la gestion des erreurs, ce qui rendra votre code encore plus expressif et naturel. Je recommanderais vivement de lire cet excellent article de Andrei Alexandrescu, expert en C++, au sujet de ce qu’il appelle, "Enforcements": http://www.ddj.com/cpp/184403864 . Bien que ce soit un article sur C++, les principes sont généralement applicables et j'ai traduit le concept de renforcement en C # avec succès.

2
philsquared

Premièrement, je suis d’accord avec la réponse - answer de Tom pour les exceptions d’utilisation de matériel de haut niveau et pour les codes d’erreur d’utilisation de bas niveau, tant que ce n’est pas une architecture orientée service (SOA).

Dans la SOA, où les méthodes peuvent être appelées sur différentes machines, les exceptions ne peuvent pas être passées sur le réseau. Nous utilisons plutôt les réponses de réussite/échec avec une structure comme ci-dessous (C #):

public class ServiceResponse
{
    public bool IsSuccess => string.IsNullOrEmpty(this.ErrorMessage);

    public string ErrorMessage { get; set; }
}

public class ServiceResponse<TResult> : ServiceResponse
{
    public TResult Result { get; set; }
}

Et utilisez comme ceci:

public async Task<ServiceResponse<string>> GetUserName(Guid userId)
{
    var response = await this.GetUser(userId);
    if (!response.IsSuccess) return new ServiceResponse<string>
    {
        ErrorMessage = $"Failed to get user."
    };
    return new ServiceResponse<string>
    {
        Result = user.Name
    };
}

Lorsque ceux-ci sont utilisés de manière cohérente dans vos réponses de service, cela crée un modèle très agréable de traitement des succès/échecs dans l'application. Cela permet de gérer plus facilement les erreurs lors d'appels asynchrones au sein de services et entre services.

2
orad

Je préférerais Exceptions pour tous les cas d'erreur, sauf lorsqu'une défaillance est un résultat attendu sans bug d'une fonction qui renvoie un type de données primitif. Par exemple. La recherche de l'index d'une sous-chaîne dans une chaîne plus grande renvoie généralement -1, si elle n'est pas trouvée, au lieu de déclencher une exception NotFoundException.

Renvoyer des pointeurs non valides pouvant être déréférencés (par exemple, causant NullPointerException en Java) n'est pas acceptable.

L'utilisation de plusieurs codes d'erreur numériques différents (-1, -2) en tant que valeurs de retour pour la même fonction constitue généralement un style incorrect, car les clients peuvent effectuer une vérification "== -1" au lieu de "<0".

Il faut garder à l'esprit l'évolution des API au fil du temps. Une bonne API permet de modifier et d'étendre le comportement en cas de défaillance de plusieurs manières sans casser les clients. Par exemple. si un descripteur d'erreur client a vérifié 4 cas d'erreur et que vous ajoutez une cinquième valeur d'erreur à votre fonction, le gestionnaire client peut ne pas le tester et rompre. Si vous déclenchez des exceptions, cela facilitera généralement la migration des clients vers une version plus récente d'une bibliothèque.

Une autre chose à considérer est de savoir quand vous travaillez en équipe, où tracer une ligne claire pour que tous les développeurs puissent prendre une telle décision. Par exemple. "Les exceptions pour les commandes de haut niveau, les codes d'erreur pour les commandes de bas niveau" sont très subjectives.

Dans tous les cas, où plus d'un type d'erreur trivial est possible, le code source ne doit jamais utiliser le littéral numérique pour renvoyer un code d'erreur ou le traiter (retourne -7, si x == -7 ...), mais toujours une constante nommée (retourne NO_SUCH_FOO, si x == NO_SUCH_FOO).

1
tkruse

Si vous travaillez dans un grand projet, vous ne pouvez utiliser que des exceptions ou des codes d'erreur. Dans différents cas, vous devez utiliser différentes approches.

Par exemple, vous décidez d'utiliser uniquement des exceptions. Mais une fois que vous décidez d'utiliser le traitement des événements async. Il est déconseillé d’utiliser des exceptions pour la gestion des erreurs dans ces situations. Mais utiliser des codes d'erreur partout dans l'application est fastidieux.

Je pense donc qu'il est normal d'utiliser simultanément les exceptions et les codes d'erreur.

1
gomons

Ma règle générale est:

  • Une seule erreur peut apparaître dans une fonction: utilisez le code d'erreur (en tant que paramètre de la fonction)
  • Plus d'une erreur spécifique pourrait apparaître: throw exception
0
DEADBEEF

Pour la plupart des applications, les exceptions sont meilleures. L'exception est lorsque le logiciel doit communiquer avec d'autres périphériques. Le domaine dans lequel je travaille est celui des contrôles industriels. Ici, les codes d'erreur sont préférés et attendus. Donc, ma réponse est que cela dépend de la situation.

0
Jim C

Je pense que cela dépend aussi de savoir si vous avez vraiment besoin d'informations telles que la trace de pile du résultat. Si oui, vous optez certainement pour Exception qui fournit à l'objet complet de nombreuses informations sur le problème. Cependant, si vous êtes simplement intéressé par le résultat et ne vous souciez pas de savoir pourquoi, alors utilisez le code d'erreur. 

par exemple. Lorsque vous traitez un fichier et que vous faites face à une exception IOException, le client peut vouloir savoir d'où cela a été déclenché, en ouvrant ou en analysant un fichier, etc. Il vaut donc mieux renvoyer IOException ou sa sous-classe spécifique. Cependant, si vous avez une méthode de connexion et que vous voulez savoir si elle a abouti ou non, il vous suffit de renvoyer un booléen ou d'afficher le message correct, ainsi que le code d'erreur. Ici, le client n'est pas intéressé à savoir quelle partie de la logique a provoqué ce code d'erreur. Il sait seulement si son identifiant est invalide ou s'il est verrouillé, etc.

Un autre cas auquel je peux penser est celui où les données voyagent sur le réseau. Votre méthode distante peut renvoyer uniquement le code d'erreur au lieu de Exception afin de minimiser le transfert de données. 

0
ashah