Est-ce une bonne pratique d'implémenter une gestion des exceptions inutile, juste au cas où une autre partie du code ne serait pas codée correctement?
Exemple de base
Un simple, donc je ne perds pas tout le monde :).
Disons que j'écris une application qui affichera les informations d'une personne (nom, adresse, etc.), les données étant extraites d'une base de données. Disons que je suis celui qui code la partie de l'interface utilisateur et que quelqu'un d'autre écrit le code de requête DB.
Imaginez maintenant que les spécifications de votre application indiquent que si les informations de la personne sont incomplètes (disons, le nom est manquant dans la base de données), la personne codant la requête doit gérer cela en retournant "NA" pour le champ manquant.
Que faire si la requête est mal codée et ne gère pas ce cas? Et si le gars qui a écrit la requête vous traite d'un résultat incomplet, et lorsque vous essayez d'afficher les informations, tout se bloque, car votre code n'est pas prêt à afficher des éléments vides?
Cet exemple est très basique. Je pense que la plupart d'entre vous diront "ce n'est pas votre problème, vous n'êtes pas responsable de cet accident". Mais, c'est toujours votre partie du code qui plante.
Un autre exemple
Disons que c'est maintenant moi qui rédige la requête. Les spécifications ne disent pas la même chose que ci-dessus, mais le gars qui écrit la requête "insert" doit s'assurer que tous les champs sont remplis lors de l'ajout d'une personne à la base de données pour éviter d'insérer des informations incomplètes. Dois-je protéger ma requête "select" pour m'assurer que je donne les informations complètes au gars de l'interface
Questions
Que se passe-t-il si les spécifications ne disent pas explicitement "c'est ce type qui est chargé de gérer cette situation"? Que faire si une troisième personne implémente une autre requête (similaire à la première, mais sur une autre base de données) et utilise votre code d'interface utilisateur pour l'afficher, mais ne gère pas ce cas dans son code?
Dois-je faire ce qui est nécessaire pour éviter un éventuel crash, même si ce n'est pas moi qui suis censé gérer le mauvais dossier?
Je ne cherche pas une réponse comme "(s) il est le seul responsable du crash", car je ne résout pas un conflit ici, j'aimerais savoir, si je protège mon code contre des situations ce n'est pas ma responsabilité gérer? Ici, un simple "si vide fait quelque chose" suffirait.
En général, cette question aborde la gestion des exceptions redondantes. Je le demande parce que lorsque je travaille seul sur un projet, je peux coder 2 à 3 fois une gestion d'exception similaire dans les fonctions successives, "juste au cas où" j'ai fait quelque chose de mal et j'ai laissé un mauvais cas passer.
Réponses:
Vous parlez ici de limites de confiance . Faites-vous confiance à la frontière entre votre application et la base de données? La base de données est-elle sûre que les données de l'application sont toujours pré-validées?
C'est une décision qui doit être prise dans chaque demande et il n'y a pas de bonnes et de mauvaises réponses. J'ai tendance à pécher par excès d'appeler trop de frontières une limite de confiance, les autres développeurs se feront un plaisir de faire confiance aux API tierces pour faire ce que vous attendez d'eux, tout le temps, à chaque fois.
la source
Le principe de robustesse «Soyez conservateur dans ce que vous envoyez, soyez libéral dans ce que vous acceptez» est ce que vous recherchez. C'est un bon principe - EDIT: tant que son application ne cache pas de graves erreurs - mais je suis d'accord avec @pdr que cela dépend toujours de la situation si vous devez l'appliquer ou non.
la source
Cela dépend de ce que vous testez; mais supposons que la portée de votre test est uniquement votre propre code. Dans ce cas, vous devez tester:
Pour ce faire, vous ne pouvez pas utiliser le composant de votre collègue: utilisez plutôt le mocking , c'est-à-dire remplacez le reste de l'application par des modules "faux" que vous pouvez contrôler à partir du framework de test. La façon exacte de procéder dépend de la façon dont les modules s'interfacent; cela peut suffire d'appeler simplement les méthodes de votre module avec des arguments codés en dur, et cela peut devenir aussi complexe que d'écrire un framework entier qui connecte les interfaces publiques des autres modules avec l'environnement de test.
C'est juste le cas de test unitaire, cependant. Vous voulez également des tests d'intégration, où vous testez tous les modules de concert. Encore une fois, vous voulez tester à la fois le cas heureux et les échecs.
Dans votre cas "Exemple de base", pour tester votre code à l'unité, écrivez une classe fictive qui simule la couche de base de données. Cependant, votre classe fictive ne va pas vraiment dans la base de données: vous la préchargez simplement avec les entrées et les sorties fixes attendues. En pseudocode:
Et voici comment tester les champs manquants correctement signalés :
Maintenant, les choses deviennent intéressantes. Et si la vraie classe DB se comporte mal? Par exemple, il pourrait lever une exception pour des raisons peu claires. Nous ne savons pas si c'est le cas, mais nous voulons que notre propre code le gère avec élégance. Pas de problème, il suffit de faire une exception à notre MockDB, par exemple en ajoutant une méthode comme celle-ci:
Et puis notre cas de test ressemble à ceci:
Ce sont vos tests unitaires. Pour le test d'intégration, vous n'utilisez pas la classe MockDB; au lieu de cela, vous enchaînez les deux classes réelles ensemble. Vous avez encore besoin de luminaires; par exemple, vous devez initialiser la base de données de test à un état connu avant d'exécuter le test.
Maintenant, en ce qui concerne les responsabilités: votre code doit s'attendre à ce que le reste de la base de code soit implémenté conformément aux spécifications, mais il doit également être prêt à gérer les choses avec élégance lorsque les autres se gâchent. Vous n'êtes pas responsable de tester un autre code que le vôtre, mais vous êtes responsable de faire en sorte que votre code résiste aux mauvais comportements du code à l'autre extrémité, et vous êtes également responsable du test de la résilience de votre code. C'est ce que fait le troisième test ci-dessus.
la source
Il y a 3 principes principaux que j'essaie de coder:
SEC
BAISER
YAGNI
Le hic, c'est que vous risquez d'écrire du code de validation qui est dupliqué ailleurs. Si les règles de validation changent, celles-ci devront être mises à jour à plusieurs endroits.
Bien sûr, à un moment donné dans le futur, vous pourriez remplacer votre base de données (cela arrive), auquel cas vous pourriez penser que le code à plusieurs endroits serait avantageux. Mais ... vous codez pour quelque chose qui pourrait ne pas arriver.
Tout code supplémentaire (même s'il ne change jamais) est une surcharge car il devra être écrit, lu, stocké et testé.
Tout cela étant vrai, il serait négligent de votre part de ne faire aucune validation. Pour afficher un nom complet dans l'application, vous auriez besoin de données de base - même si vous ne validez pas les données elles-mêmes.
la source
Dans les mots du profane.
Il n'y a rien de tel que "la base de données" ou "l'application" .
Encore:
la source