Lors de la programmation par contrat, une fonction ou une méthode vérifie d'abord si ses conditions préalables sont remplies, avant de commencer à travailler sur ses responsabilités, non? Les deux méthodes les plus importantes pour effectuer ces vérifications sont peu assert
à peu exception
.
- assert échoue uniquement en mode débogage. Pour s'assurer qu'il est crucial de tester (unitaire) toutes les conditions préalables du contrat pour voir si elles échouent réellement.
- l'exception échoue en mode débogage et version. Cela présente l'avantage que le comportement de débogage testé est identique au comportement de version, mais il entraîne une pénalité des performances d'exécution.
Selon vous, lequel est préférable?
Voir la question répétée ici
exception
assert
design-by-contract
andreas buykx
la source
la source
Réponses:
Désactiver l'assert dans les versions de version revient à dire "Je n'aurai jamais aucun problème dans une version de version", ce qui n'est souvent pas le cas. Donc, assert ne doit pas être désactivé dans une version de version. Mais vous ne voulez pas non plus que la version de version plante chaque fois que des erreurs se produisent, n'est-ce pas?
Alors utilisez les exceptions et utilisez-les bien. Utilisez une bonne hiérarchie d'exceptions solide et assurez-vous que vous attrapez et que vous pouvez mettre un crochet sur le lancement d'exceptions dans votre débogueur pour l'attraper, et en mode de libération, vous pouvez compenser l'erreur plutôt qu'un simple crash. C'est la manière la plus sûre d'aller.
la source
La règle de base est que vous devez utiliser des assertions lorsque vous essayez de détecter vos propres erreurs et des exceptions lorsque vous essayez de détecter les erreurs des autres. En d'autres termes, vous devez utiliser des exceptions pour vérifier les conditions préalables des fonctions API publiques et chaque fois que vous obtenez des données externes à votre système. Vous devez utiliser des assertions pour les fonctions ou les données internes à votre système.
la source
Le principe que je suis est le suivant: si une situation peut être évitée de manière réaliste par le codage, utilisez une assertion. Sinon, utilisez une exception.
Les affirmations visent à garantir que le contrat est respecté. Le contrat doit être équitable, de sorte que le client doit être en mesure de garantir sa conformité. Par exemple, vous pouvez indiquer dans un contrat qu'une URL doit être valide car les règles concernant ce qui est et ce qui n'est pas une URL valide sont connues et cohérentes.
Les exceptions concernent les situations qui échappent au contrôle du client et du serveur. Une exception signifie que quelque chose a mal tourné et que rien n'aurait pu être fait pour l'éviter. Par exemple, la connectivité réseau est hors du contrôle des applications, il n'y a donc rien qui puisse être fait pour éviter une erreur réseau.
Je voudrais ajouter que la distinction Assertion / Exception n'est pas vraiment la meilleure façon d'y penser. Ce à quoi vous voulez vraiment penser, c'est le contrat et comment il peut être appliqué. Dans mon exemple d'URL ci-dessus, la meilleure chose à faire est d'avoir une classe qui encapsule une URL et qui est soit Null, soit une URL valide. C'est la conversion d'une chaîne en URL qui applique le contrat et une exception est levée si elle n'est pas valide. Une méthode avec un paramètre URL est beaucoup plus claire qu'une méthode avec un paramètre String et une assertion qui spécifie une URL.
la source
Les affirmations servent à détecter quelque chose qu'un développeur a mal fait (pas seulement vous-même - un autre développeur de votre équipe également). S'il est raisonnable qu'une erreur de l'utilisateur puisse créer cette condition, il devrait s'agir d'une exception.
Pensez également aux conséquences. Une assertion ferme généralement l'application. S'il y a une attente réaliste à partir de laquelle la condition pourrait être récupérée, vous devriez probablement utiliser une exception.
D'un autre côté, si le problème ne peut être dû qu'à une erreur de programmeur, utilisez une assertion, car vous voulez en savoir le plus tôt possible. Une exception peut être interceptée et gérée, et vous ne le découvrirez jamais. Et oui, vous devez désactiver les assertions dans le code de version, car vous souhaitez que l'application se rétablisse s'il y a la moindre chance. Même si l'état de votre programme est profondément interrompu, l'utilisateur peut simplement enregistrer son travail.
la source
Il n'est pas tout à fait vrai que "l'assertion échoue uniquement en mode débogage".
Dans Object Oriented Software Construction, 2e édition de Bertrand Meyer, l'auteur laisse une porte ouverte pour vérifier les conditions préalables en mode release. Dans ce cas, ce qui se passe lorsqu'une assertion échoue, c'est que ... une exception de violation d'assertion est déclenchée! Dans ce cas, il n'y a pas de récupération de la situation: quelque chose d'utile pourrait cependant être fait, et c'est de générer automatiquement un rapport d'erreur et, dans certains cas, de redémarrer l'application.
La motivation derrière ceci est que les conditions préalables sont généralement moins chères à tester que les invariants et les post-conditions, et que dans certains cas, l'exactitude et la «sécurité» dans la version de la version sont plus importantes que la vitesse. c'est-à-dire que pour de nombreuses applications, la vitesse n'est pas un problème, mais la robustesse (la capacité du programme à se comporter de manière sûre lorsque son comportement n'est pas correct, c'est-à-dire lorsqu'un contrat est rompu).
Devez-vous toujours laisser les vérifications des conditions préalables activées? Ça dépend. C'est à vous. Il n'y a pas de réponse universelle. Si vous créez un logiciel pour une banque, il peut être préférable d'interrompre l'exécution avec un message alarmant plutôt que de transférer 1 000 000 $ au lieu de 1 000 $. Mais que faire si vous programmez un jeu? Peut-être avez-vous besoin de toute la vitesse que vous pouvez obtenir, et si quelqu'un obtient 1000 points au lieu de 10 à cause d'un bug que les conditions préalables n'ont pas détecté (car elles ne sont pas activées), pas de chance.
Dans les deux cas, vous devriez idéalement avoir détecté ce bogue pendant les tests, et vous devriez effectuer une partie importante de vos tests avec les assertions activées. Ce qui est discuté ici est la meilleure stratégie pour les rares cas où les conditions préalables échouent dans le code de production dans un scénario qui n'a pas été détecté plus tôt en raison de tests incomplets.
Pour résumer, vous pouvez avoir des assertions et toujours obtenir les exceptions automatiquement , si vous les laissez activées - du moins dans Eiffel. Je pense que pour faire la même chose en C ++, vous devez le taper vous-même.
Voir aussi: Quand les assertions doivent-elles rester dans le code de production?
la source
Il y avait un énorme fil de discussion concernant l'activation / la désactivation des assertions dans les versions de version sur comp.lang.c ++. Modéré, qui si vous avez quelques semaines, vous pouvez voir à quel point les opinions sont variées à ce sujet. :)
Contrairement à coppro , je crois que si vous n'êtes pas sûr qu'une assertion puisse être désactivée dans une version de version, alors cela n'aurait pas dû être une assertion. Les affirmations visent à protéger contre la rupture des invariants de programme. Dans un tel cas, en ce qui concerne le client de votre code, il y aura l'un des deux résultats possibles:
Il n'y a aucune différence pour l'utilisateur, cependant, il est possible que les assertions ajoutent un coût de performance inutile dans le code qui est présent dans la grande majorité des exécutions où le code n'échoue pas.
La réponse à la question dépend en fait beaucoup plus de qui seront les clients de l'API. Si vous écrivez une bibliothèque fournissant une API, vous avez besoin d'une forme de mécanisme pour informer vos clients qu'ils ont utilisé l'API de manière incorrecte. À moins que vous ne fournissiez deux versions de la bibliothèque (une avec assertions, une sans), assert est très peu probable le choix approprié.
Personnellement, cependant, je ne suis pas sûr que j'irais avec des exceptions pour ce cas non plus. Les exceptions sont mieux adaptées aux endroits où une forme appropriée de récupération peut avoir lieu. Par exemple, il se peut que vous essayiez d'allouer de la mémoire. Lorsque vous rencontrez une exception 'std :: bad_alloc', il peut être possible de libérer de la mémoire et de réessayer.
la source
J'ai exposé ici mon point de vue sur l'état de la question: Comment valider l'état interne d'un objet? . En règle générale, faites valoir vos revendications et jetez-les pour violation par d'autres. Pour désactiver les assertions dans les versions de version, vous pouvez faire:
Bien sûr, dans les versions de version, les assertions ayant échoué et les exceptions non interceptées devraient être gérées d'une autre manière que dans les versions de débogage (où il pourrait simplement appeler std :: abort). Écrivez un journal de l'erreur quelque part (éventuellement dans un fichier), informez le client qu'une erreur interne s'est produite. Le client pourra vous envoyer le fichier journal.
la source
vous demandez la différence entre les erreurs de conception et d'exécution.
les assertions sont des notifications «hé programmeur, c'est cassé», elles sont là pour vous rappeler des bogues que vous n'auriez pas remarqués lorsqu'ils se sont produits.
les exceptions sont les notifications `` hé utilisateur, quelque chose a mal tourné '' (évidemment, vous pouvez coder pour les attraper afin que l'utilisateur ne soit jamais informé) mais elles sont conçues pour se produire au moment de l'exécution lorsque l'utilisateur Joe utilise l'application.
Donc, si vous pensez pouvoir éliminer tous vos bogues, n'utilisez que des exceptions. Si vous pensez que vous ne pouvez pas ..... utiliser des exceptions. Vous pouvez toujours utiliser des assertions de débogage pour réduire le nombre d'exceptions bien sûr.
N'oubliez pas que la plupart des conditions préalables seront des données fournies par l'utilisateur, vous aurez donc besoin d'un bon moyen d'informer l'utilisateur que ses données n'étaient pas bonnes. Pour ce faire, vous devrez souvent renvoyer des données d'erreur dans la pile d'appels aux bits avec lesquels il interagit. Les assertions ne seront alors pas utiles - doublement si votre application est à n-tiers.
Enfin, je n'utiliserais ni l'un ni l'autre - les codes d'erreur sont bien supérieurs pour les erreurs que vous pensez se produire régulièrement. :)
la source
Je préfère le second. Bien que vos tests se soient bien déroulés , Murphy dit que quelque chose d'inattendu va mal tourner. Ainsi, au lieu d'obtenir une exception lors de l'appel de méthode erroné, vous finissez par tracer une NullPointerException (ou équivalent) de 10 images de pile plus profondes.
la source
Les réponses précédentes sont correctes: utilisez des exceptions pour les fonctions API publiques. Le seul moment où vous voudrez peut-être contourner cette règle est lorsque la vérification est coûteuse en calcul. Dans ce cas, vous pouvez le mettre dans une assert.
Si vous pensez que la violation de cette condition préalable est probable, conservez-la comme une exception ou modifiez la condition préalable.
la source
Vous devez utiliser les deux. Les affirmations sont pour votre commodité en tant que développeur. Les exceptions capturent les choses que vous avez manquées ou auxquelles vous ne vous attendiez pas pendant l'exécution.
Je suis devenu friand des fonctions de rapport d'erreurs de glib au lieu d'assertions anciennes. Ils se comportent comme des instructions assert mais au lieu d'arrêter le programme, ils renvoient simplement une valeur et laissent le programme continuer. Cela fonctionne étonnamment bien, et en prime, vous voyez ce qui arrive au reste de votre programme lorsqu'une fonction ne renvoie pas "ce qu'elle est censée faire". S'il se bloque, vous savez que votre vérification des erreurs est laxiste ailleurs sur la route.
Dans mon dernier projet, j'ai utilisé ce style de fonctions pour implémenter la vérification des conditions préalables, et si l'une d'entre elles échouait, j'imprimais une trace de pile dans le fichier journal mais je continuerais à fonctionner. M'a sauvé des tonnes de temps de débogage lorsque d'autres personnes rencontraient un problème lors de l'exécution de ma version de débogage.
Si j'avais besoin d'une vérification à l'exécution des arguments, je ferais ceci:
la source
J'ai essayé de synthétiser plusieurs des autres réponses ici avec mes propres opinions.
Utilisez des assertions pour les cas où vous souhaitez le désactiver en production, dans l'erreur de les laisser. La seule vraie raison de désactiver en production, mais pas en développement, est d'accélérer le programme. Dans la plupart des cas, cette accélération ne sera pas significative, mais parfois le code est critique en termes de temps ou le test est coûteux en calcul. Si le code est essentiel à la mission, les exceptions peuvent être les meilleures malgré le ralentissement.
S'il existe une chance réelle de récupération, utilisez une exception car les assertions ne sont pas conçues pour être récupérées. Par exemple, le code est rarement conçu pour récupérer des erreurs de programmation, mais il est conçu pour récupérer des facteurs tels que des pannes de réseau ou des fichiers verrouillés. Les erreurs ne doivent pas être traitées comme des exceptions simplement parce qu'elles échappent au contrôle du programmeur. Au contraire, la prévisibilité de ces erreurs, par rapport aux erreurs de codage, les rend plus faciles à récupérer.
Re argument selon lequel il est plus facile de déboguer les assertions: la trace de pile d'une exception correctement nommée est aussi facile à lire qu'une assertion. Un bon code ne doit capturer que des types d'exceptions spécifiques, de sorte que les exceptions ne doivent pas passer inaperçues car elles sont capturées. Cependant, je pense que Java vous oblige parfois à attraper toutes les exceptions.
la source
La règle d'or, pour moi, est d'utiliser des expressions d'assert pour trouver les erreurs internes et les exceptions pour les erreurs externes. Vous pouvez profiter de la discussion suivante de Greg à partir d' ici .
PS: vous voudrez peut-être consulter la question similaire: Exception Vs Assertion .
la source
Voir aussi cette question :
la source