J'ai récemment découvert le cadre de Microsoft pour les contrats de code.
J'ai lu un peu de documentation et je me suis constamment demandé: "Pourquoi voudrais-je jamais faire cela, car il ne fait pas et souvent ne peut pas effectuer une analyse statique."
Maintenant, j'ai déjà une sorte de style de programmation défensive, avec des exceptions de garde comme celle-ci:
if(var == null) { throw new NullArgumentException(); }
J'utilise également beaucoup de modèles NullObject et j'ai rarement des problèmes. Ajoutez-y des tests unitaires et vous êtes tous prêts.
Je n'ai jamais utilisé d'assertions et je ne les ai jamais manquées. Bien au contraire. Je déteste vraiment le code qui contient beaucoup d'assertions dénuées de sens, ce qui est juste du bruit pour moi et me distrait de ce que je veux vraiment voir. Les contrats de code, au moins à la manière de Microsoft, sont sensiblement les mêmes - et pire encore. Ils ajoutent beaucoup de bruit et de complexité au code. Dans 99%, une exception sera levée de toute façon - donc je me fiche que ce soit de l'assertion / du contrat ou du problème réel. Il ne reste que très, très peu de cas où les états du programme sont réellement corrompus.
Alors, franchement, quel est l'avantage d'utiliser des contrats de code? Y en a-t-il du tout? Si vous utilisez déjà des tests unitaires et du code de manière défensive, je pense que l'introduction de contrats ne vaut tout simplement pas le coût et fait du bruit dans votre code qu'un responsable maudira lorsqu'il mettra à jour cette méthode, un peu comme je le fais quand je ne vois pas ce que fait le code en raison d'affirmations inutiles. Je n'ai pas encore vu une bonne raison de payer ce prix.
la source
Réponses:
Vous auriez tout aussi bien pu demander quand la frappe statique est meilleure que la frappe dynamique. Un débat qui fait rage depuis des années sans fin en vue. Alors jetez un oeil à des questions comme les études de langues typiquement vs statiquement
Mais l'argument de base serait la possibilité de découvrir et de résoudre des problèmes au moment de la compilation qui, autrement, auraient pu glisser en production.
Contrats contre gardes
Même avec des gardes et des exceptions, vous êtes toujours confronté au problème selon lequel le système ne pourra pas exécuter sa tâche prévue dans certains cas. Peut-être une instance qui sera assez critique et coûteuse à échouer.
Contrats vs tests unitaires
L'argument habituel sur celui-ci est que les tests prouvent la présence de bugs, tandis que les types (contrats) prouvent l'absence. F.ex. en utilisant un type, vous savez qu'aucun chemin dans le programme ne pourrait éventuellement fournir une entrée non valide, tandis qu'un test pourrait seulement vous dire que le chemin couvert a fourni la bonne entrée.
Contrats vs modèle d'objet nul
Maintenant, c'est au moins dans le même parc de balle. Des langages comme Scala et Haskell ont eu beaucoup de succès avec cette approche pour éliminer entièrement les références nulles des programmes. (Même si Scala autorise formellement les null, la convention est de ne jamais les utiliser)
Si vous utilisez déjà ce modèle pour éliminer les NRE, vous avez essentiellement supprimé la plus grande source d'échecs d'exécution, essentiellement de la manière dont les contrats vous permettent de le faire.
La différence pourrait être que les contrats ont une option pour exiger automatiquement tout votre code pour éviter la null, et donc vous forcer à utiliser ce modèle dans plus d'endroits pour passer la compilation.
En plus de cela, les contrats vous donnent également la flexibilité de cibler des choses au-delà de zéro. Donc, si vous ne voyez plus de NRE dans vos bogues, vous voudrez peut-être utiliser des contrats pour étrangler le prochain problème le plus courant que vous pourriez avoir. Off par un? Index hors limites?
Mais...
Tout cela étant dit. Je suis d'accord que les contrats de bruit syntaxique (et même de bruit structurel) ajoutés au code sont assez importants et l'impact de l'analyse sur votre temps de construction ne doit pas être sous-estimé. Donc, si vous décidez d'ajouter des contrats à votre système, il serait probablement judicieux de le faire très soigneusement en vous concentrant sur la classe de bogues que vous essayez de résoudre.
la source
Je ne sais pas d'où vient l'affirmation selon laquelle "il ne fait pas et ne peut souvent pas effectuer une analyse statique". La première partie de l'affirmation est manifestement erronée. Le second dépend de ce que vous entendez par «souvent». Je dirais plutôt que souvent , il effectue une analyse statique et rarement, il échoue. Dans une application commerciale ordinaire, devient rarement beaucoup plus proche que jamais .
Le voici donc, le premier avantage:
Avantage 1: analyse statique
Les assertions ordinaires et la vérification des arguments ont un inconvénient: elles sont reportées jusqu'à l'exécution du code. En revanche, les contrats de code se manifestent à un niveau beaucoup plus précoce, soit à l'étape de codage, soit lors de la compilation de l'application. Plus vous détectez une erreur tôt, moins il est coûteux de la corriger.
Avantage 2: sorte de documentation toujours à jour
Les contrats de code fournissent également une sorte de documentation toujours à jour. Si le commentaire XML de la méthode
SetProductPrice(int newPrice)
indique que celle-cinewPrice
doit être supérieure ou égale à zéro, vous pouvez espérer que la documentation est à jour, mais vous pouvez également découvrir que quelqu'un a changé la méthode de sorte quenewPrice = 0
jette unArgumentOutOfRangeException
, mais n'a jamais changé la documentation correspondante. Étant donné la corrélation entre les contrats de code et le code lui-même, vous n'avez pas le problème de documentation désynchronisée.Le type de documentation fourni par les contrats de code est également précieux d'une manière qui, souvent, les commentaires XML n'expliquent pas bien les valeurs acceptables. Combien de fois je me demandais si
null
oustring.Empty
ou\r\n
était une valeur autorisée pour une méthode, et les commentaires XML étaient silencieux à ce sujet!En conclusion, sans contrats de code, beaucoup de morceaux de code sont comme ça:
Avec les contrats de code, cela devient:
Avantage 3: contrats d'interfaces
Un troisième avantage est que les contrats de code renforcent les interfaces. Disons que vous avez quelque chose comme:
Comment garantissez-vous, en utilisant uniquement des assertions et des exceptions, que vous
CommitChanges
ne pouvez être appelé que lorsqu'ilPendingChanges
n'est pas vide? Comment garantiriez-vous que cePendingChanges
n'est jamaisnull
?Avantage 4: appliquer les résultats d'une méthode
Enfin, le quatrième avantage est de pouvoir bénéficier
Contract.Ensure
des résultats. Et si, lors de l'écriture d'une méthode qui renvoie un entier, je veux être sûr que la valeur n'est jamais inférieure ou égale à zéro? Y compris cinq ans plus tard, après avoir subi de nombreux changements de la part de nombreux développeurs? Dès qu'une méthode a plusieurs points de retour, celaAssert
devient un cauchemar de maintenance pour cela.Considérez les contrats de code non seulement comme un moyen d'exactitude de votre code, mais comme un moyen plus strict d'écrire du code. De la même manière, une personne qui utilise exclusivement des langages dynamiques peut se demander pourquoi appliquer des types au niveau du langage, alors que vous pouvez faire la même chose dans les assertions si nécessaire. Vous pouvez, mais la saisie statique est plus facile à utiliser, moins sujette aux erreurs par rapport à un tas d'assertions et à l'auto-documentation.
La différence entre le typage dynamique et le typage statique est extrêmement proche de la différence entre la programmation ordinaire et la programmation par contrats.
la source
Je sais que c'est un peu tard pour la question, mais il y a un autre avantage aux contrats de code qui mérite d'être mentionné
Les contrats sont vérifiés en dehors de la méthode
Lorsque nous avons des conditions de garde à l'intérieur de notre méthode, c'est l'endroit où la vérification a lieu et où les erreurs sont signalées. Il se peut alors que nous devions enquêter sur la trace de la pile pour savoir où se trouve la source réelle de l'erreur.
Les contrats de code sont situés dans la méthode, mais les conditions préalables sont vérifiées en dehors de la méthode lorsque quelque chose tente d'appeler cette méthode. Les contrats font partie de la méthode et déterminent si elle peut être appelée ou non. Cela signifie que nous obtenons une erreur signalée beaucoup plus près de la source réelle du problème.
Si vous avez une méthode protégée par contrat qui est appelée pour de nombreux endroits, cela peut être un réel avantage.
la source
Deux choses vraiment:
la source