J'ai un projet suffisamment grand pour que je ne puisse plus garder tous les aspects en tête. Je traite avec un certain nombre de classes et de fonctions, et je transmets des données.
Avec le temps, j'ai remarqué que je continuais à recevoir des erreurs, car j'avais oublié la forme précise que les données devaient avoir lorsque je les transmettais à différentes fonctions ( par exemple, une fonction accepte et génère un tableau de chaînes, une autre fonction, que j'ai écrite beaucoup plus tard, accepte les chaînes qui sont conservées dans un dictionnaire, etc., donc je dois transformer les chaînes avec lesquelles je travaille, de les avoir dans un tableau à les avoir dans un dictionnaire ).
Pour éviter d'avoir toujours à comprendre ce qui s'est cassé où, j'ai commencé à traiter chaque fonction et classe comme étant une "entité isolée" dans le sens où elle ne peut pas s'appuyer sur du code extérieur lui donnant la bonne entrée et doit effectuer elle-même des vérifications d'entrée (ou, dans certains cas, refonte des données, si les données sont fournies sous une forme incorrecte).
Cela a considérablement réduit le temps que je passe à m'assurer que les données que je transmets "tiennent" dans chaque fonction, car les classes et les fonctions elles-mêmes m'avertissent désormais lorsqu'une entrée est mauvaise (et parfois même corrige cela) et je ne le fais pas avoir à aller avec un débogueur à travers le code entier pour comprendre où quelque chose s'est détraqué.
D'un autre côté, cela a également augmenté le code global.
Ma question est, si ce style de code est approprié pour résoudre ce problème?
Bien sûr, la meilleure solution serait de refactoriser complètement le projet et de s'assurer que les données ont une structure uniforme pour toutes les fonctions - mais comme ce projet est en croissance constante, je finirais par dépenser plus et m'inquiéter du code propre que d'ajouter réellement de nouvelles choses .
(FYI: Je suis toujours un débutant, alors veuillez excuser si cette question était naïve; mon projet est en Python.)
la source
Réponses:
Une meilleure solution consiste à tirer davantage parti des fonctionnalités et des outils du langage Python.
Ce problème est atténué avec un
namedtuple
. Il est léger et donne une signification sémantique facile aux membres de votre tableau.Pour profiter de la vérification automatique de type sans changer de langue, vous pouvez profiter de l' indication de type . Un bon IDE peut l'utiliser pour vous faire savoir quand vous faites quelque chose de stupide.
Vous semblez également inquiet de voir les fonctions devenir obsolètes lorsque les exigences changent. Cela peut être détecté par des tests automatisés .
Bien que je ne dise pas que la vérification manuelle n'est jamais appropriée, une meilleure utilisation des fonctionnalités linguistiques disponibles peut vous aider à résoudre ce problème de manière plus maintenable.
la source
namedtuple
et toutes les autres belles choses. Je ne savais pasnamedtuple
- et même si je connaissais les tests automatisés, je ne l'ai jamais vraiment utilisé beaucoup et je ne savais pas à quel point cela pourrait m'aider dans ce cas. Tout cela semble vraiment être aussi bon qu'une analyse statique. (Les tests automatisés pourraient même être meilleurs, car je peux attraper toutes les choses subtiles qui ne seraient pas prises dans une analyse statique!) Si vous en connaissez d'autres, faites-le moi savoir. Je vais laisser la question ouverte encore un peu, mais si aucune autre réponse ne vient, j'accepterai la vôtre.OK, le problème réel est décrit dans un commentaire sous cette réponse:
Le problème ici est l'utilisation d'une liste de chaînes où l'ordre signifie la sémantique. Il s'agit d'une approche propice aux erreurs. Au lieu de cela, vous devez créer une classe personnalisée avec deux champs nommés
title
etbibliographical_reference
. De cette façon, vous n'allez pas les mélanger et vous éviterez ce problème à l'avenir. Bien sûr, cela nécessite une refactorisation si vous utilisez déjà des listes de chaînes dans de nombreux endroits, mais croyez-moi, ce sera moins cher à long terme.L'approche courante dans les langages de types dynamiques est le "typage de canard", ce qui signifie que vous ne vous souciez pas vraiment du "type" de l'objet passé, vous ne vous souciez que s'il prend en charge les méthodes que vous appelez. Dans votre cas, vous lirez simplement le champ appelé
bibliographical_reference
lorsque vous en aurez besoin. Si ce champ n'existe pas sur l'objet passé, vous obtiendrez une erreur, ce qui indique que le mauvais type est passé à la fonction. C'est une vérification de type aussi bonne que n'importe quelle autre.la source
Tout d'abord, ce que vous ressentez en ce moment, c'est l' odeur de code - essayez de vous rappeler ce qui vous a amené à devenir conscient de l'odeur et à affiner votre nez "mental", car plus tôt vous remarquerez une odeur de code, plus tôt - et plus facilement - vous pouvez résoudre le problème sous-jacent.
La programmation défensive - comme cette technique est appelée - est un outil valide et souvent utilisé. Cependant, comme pour tout, il est important d'utiliser la bonne quantité, trop peu de chèques et vous n'attraperez pas de problèmes, trop et votre code sera trop gonflé.
Cela pourrait être une moins bonne idée. Si vous remarquez qu'une partie de votre programme appelle une fonction avec des données incorrectement formatées, CORRIGEZ CETTE PARTIE , ne modifiez pas la fonction appelée pour pouvoir digérer les mauvaises données de toute façon.
L'amélioration de la qualité et de la maintenabilité de votre code est un gain de temps à long terme (en ce sens, je dois à nouveau mettre en garde contre la fonctionnalité d'autocorrection que vous avez intégrée à certaines de vos fonctions - elles pourraient être une source insidieuse de bogues. Tout simplement parce que votre le programme ne plante pas et ne brûle pas ne signifie pas qu'il fonctionne correctement ...)
Pour répondre enfin à votre question: Oui, une programmation défensive (c'est-à-dire vérifier la validité des paramètres fournis) est - à un degré sain - une bonne stratégie. Cela dit , comme vous l'avez dit vous-même, votre code est incohérent, et je vous recommande fortement de passer du temps à refactoriser les parties qui sentent - vous avez dit que vous ne voulez pas vous soucier du code propre tout le temps, en passant plus de temps sur "nettoyage" que sur les nouvelles fonctionnalités ... Si vous ne gardez pas votre code propre, vous pourriez passer deux fois plus de temps à "éviter" de ne pas garder un code propre pour éliminer les bogues ET aurez du mal à implémenter de nouvelles fonctionnalités - la dette technique peut vous écraser.
la source
C'est bon. J'avais l'habitude de coder dans FoxPro, où j'avais un bloc TRY..CATCH presque dans chaque grande fonction. Maintenant, je code en JavaScript / LiveScript et vérifie rarement les paramètres dans les fonctions "internes" ou "privées".
"Combien vérifier" dépend plus du projet / langage choisi que de votre compétence en code.
la source