J'ai des données brutes sur lesquelles je dois faire beaucoup de choses (le déplacer, le faire pivoter, le mettre à l'échelle le long d'un certain axe, le faire pivoter vers une position finale) et je ne sais pas quelle est la meilleure façon de le faire pour maintenir la lisibilité du code. D'une part, je peux faire une seule méthode avec de nombreux paramètres (10+) pour faire ce dont j'ai besoin, mais c'est un cauchemar de lecture de code. D'un autre côté, je pourrais créer plusieurs méthodes avec 1 à 3 paramètres chacune, mais ces méthodes devraient être appelées dans un ordre très spécifique pour obtenir le résultat correct. J'ai lu qu'il est préférable que les méthodes fassent une chose et le fassent bien, mais il semble que de nombreuses méthodes doivent être appelées pour ouvrir le code des bogues difficiles à trouver.
Existe-t-il un paradigme de programmation que je pourrais utiliser pour minimiser les bogues et faciliter la lecture du code?
la source
Réponses:
Attention au couplage temporel . Cependant, ce n'est pas toujours un problème.
Si vous devez exécuter les étapes dans l'ordre, il s'ensuit que l'étape 1 produit un objet requis pour l'étape 2 (par exemple, un flux de fichiers ou une autre structure de données). Cela seul exige que la seconde fonction doit être appelée après la première, il est même possible de les appeler dans le mauvais ordre accidentellement.
En divisant votre fonctionnalité en morceaux de la taille d'une bouchée, chaque partie est plus facile à comprendre et certainement plus facile à tester de manière isolée. Si vous avez une énorme fonction de 100 lignes et quelque chose au milieu, comment votre échec de test vous indique-t-il ce qui ne va pas? Si l'une de vos cinq méthodes de ligne se casse, votre test unitaire échoué vous dirige immédiatement vers le morceau de code qui nécessite votre attention.
Voici à quoi devrait ressembler un code complexe :
À tout moment pendant le processus de conversion des données brutes en un widget fini, chaque fonction renvoie quelque chose requis par l'étape suivante du processus. On ne peut pas former un alliage à partir de scories, il faut d'abord le fondre (purifier). On ne peut pas créer un widget sans l'autorisation appropriée (par exemple l'acier) en entrée.
Les détails spécifiques de chaque étape sont contenus dans des fonctions individuelles qui peuvent être testées: plutôt que de tester en bloc l'ensemble du processus d'extraction de roches et de création de widgets, testez chaque étape spécifique. Vous avez maintenant un moyen facile de vous assurer que si votre processus de "création de widget" échoue, vous pouvez affiner la raison spécifique.
Mis à part les avantages de tester et de prouver l'exactitude, l'écriture de code de cette façon est beaucoup plus facile à lire. Personne ne peut comprendre une énorme liste de paramètres . Décomposez-le en petits morceaux et montrez ce que signifie chaque petit morceau: c'est grokkable .
la source
L'argument "doit être exécuté dans l'ordre" est théorique car presque tout votre code doit être exécuté dans le bon ordre. Après tout, vous ne pouvez pas écrire dans un fichier, puis l'ouvrir puis le fermer, n'est-ce pas?
Vous devez vous concentrer sur ce qui rend votre code le plus facile à maintenir. Cela signifie généralement des fonctions d'écriture petites et faciles à comprendre. Chaque fonction doit avoir un objectif unique et ne pas avoir d'effets secondaires imprévus.
la source
Je créerais un » ImageProcesssor « (ou n'importe quel nom convenant à votre projet) et un objet de configuration ProcessConfiguration , qui contient tous les paramètres nécessaires.
À l'intérieur du processeur d'image, vous encapsulez l'ensemble du processus derrière un mehtod
process()
Cette méthode appelle les méthodes de transformation dans l'ordre correct
shift()
,rotate()
. Chaque méthode obtient les paramètres appropriés de la ProcessConfiguration passée .J'ai utilisé des interfaces fluides
qui permet une initialisation astucieuse (comme vu ci-dessus).
L'avantage évident, encapsulant les paramètres nécessaires dans un seul objet. Vos signatures de méthode deviennent lisibles:
private void shift(Image i, ProcessConfiguration c)
Il s'agit de déplacer une image et les paramètres détaillés sont en quelque sorte configurés .
Alternativement, vous pouvez créer un ProcessingPipeline :
Un appel de méthode à une méthode
processImage
instancierait un tel pipeline et rendrait transparent quoi et dans quel ordre est fait: décalage , rotationla source
Avez-vous envisagé d'utiliser une sorte de curry ? Imaginez que vous ayez une classe
Processee
et une classeProcessor
:Vous pouvez maintenant remplacer la classe
Processor
par deux classesProcessor1
etProcessor2
:Vous pouvez ensuite appeler les opérations dans le bon ordre en utilisant:
Vous pouvez appliquer ce modèle plusieurs fois si vous avez plus de deux paramètres. Vous pouvez également grouper les arguments comme vous le souhaitez, c'est-à-dire que vous n'avez pas besoin que chaque
process
méthode prenne exactement un argument.la source