2010-02-12 4 views
1

Je vais développer ici un commentaire que j'ai fait à When a method has too many parameters? où l'OP avait des problèmes mineurs avec la fonction de quelqu'un d'autre qui avait 97 paramètres. Je suis un grand croyant dans l'écriture de code maintenable (et il est souvent plus facile d'écrire que de lire, d'où Steve McConnell (éloge soit sur son nom) "écrire seulement le code"). Comme les statistiques montrent comment la plupart des accidents de voiture se produisent aux intersections et mon expérience (ymmv) montre que la plupart des anomalies se produisent aux interfaces, je vais lister certaines choses que je fais pour éviter les malentendus aux interfaces et inviter vos commentaires si Je vais vraiment mal. Mais, plus important encore, j'invite vos suggestions pour rendre les choses encore plus prophylactiques (voir, il y a une question après tout - comment améliorer les choses?).Comment améliorer la maintenabilité des fonctions

  • Une documentation adéquate, sous la forme de commentaires au format DoxyGen (à jour) décrivant la nature et le marsouin de chaque paramètre.
  • absolument NON shenanigans de porte arrière avec des variables globales comme paramètres cachés. Essayez de limiter les paramètres à six ou à huit. Si plus, passez les paramètres liés en tant que structure; si elles ne sont pas liées alors reconsidérer sérieusement la fonction. S'il a besoin d'autant d'informations, est-ce trop complexe à maintenir? Peut-il être décomposé en plusieurs fonctions plus petites?
  • utiliser le CONST aussi souvent que possible et significatif.
  • une norme de codage qui dit que les paramètres d'entrée viennent en premier, puis seulement en sortie, et enfin en entrée/sortie, qui sont modifiés par la fonction.
  • J'ai aussi quelques macros #define vides pour faire des déclarations encore plus facile à lire:

    # Définir l'entrée
    # définir SORTIE
    # définissent MODIFY
    bool DoSomething (INPUT int howOften, ACTUALISATION Wdiget * MyWidget, SORTIE WidgetPtr * const nextWidget)

Juste quelques idées. Comment puis-je améliorer cela? Merci.

+1

Limiter les paramètres à six ou huit? Pourquoi pas sept? Et quand le maximum serait-il l'un ou l'autre? – waiwai933

+2

Quoi de neuf avec le titre? – womp

+1

Votre fonction DoSomething a ses paramètres dans le désordre. :-) – xpda

Répondre

4

Aborder vos points dans l'ordre:

  1. types rendent généralement le format Doxygen bien conçus commente une perte de temps.
  2. Bien que vrai comme indiqué ("les manigances" sont mauvaises par définition), toute utilisation de globals n'est pas aussi mauvaise que beaucoup de gens l'impliquent. Si vous devez passer un paramètre plus de quatre fois avant qu'il ne soit vraiment utilisé, il est probable qu'un global sera moins sujette aux erreurs.
  3. Huit ou même six paramètres sont généralement excessifs. Tout plus de deux ou trois commence à indiquer que la fonction fait plus d'une chose. Une exception évidente est un constructeur qui agrège un certain nombre d'autres éléments dans un objet (par exemple un objet adresse qui prend un nom de rue, un numéro, une ville, un pays, un code postal, etc., comme entrées).
  4. Mieux indiqué comme "écriture du code const-correct".
  5. Étant donné la capacité de paramètre par défaut de C++, il est généralement préférable de trier par ordre croissant de probabilité d'utiliser une valeur par défaut.
  6. Ne pas. Ne fais pas ça! Si ce n'est pas évident ce que sont les entrées et les sorties, cela prouve à peu près que le design de base est fatalement défectueux.

Quant aux idées que je pense sont en fait bien:

  1. Comme il ressort du premier point, se concentrer sur les types. Une fois que vous les avez compris, la plupart des autres problèmes disparaissent.
  2. Utilisez quelques thèmes centraux (même un seul). Pour Lisp, tout est une liste. Pour Unix, tout est un fichier (et les fichiers sont tous des simples flux d'octets). Emuler cette simplicité.

Edit: répondre aux commentaires:

  1. Alors que vous avez quelque chose d'un point, mon expérience indique encore que les documents produits avec Doxygen (et similaires tels que javadoc) est presque inutile universellement. En théorie, l'outil n'empêche pas la documentation décente, mais en fait c'est rare au mieux.
  2. Les globals peuvent certainement causer des problèmes - mais je suis assez vieux pour avoir utilisé Fortran avant qu'il fournisse beaucoup d'alternative, et avec un peu de soin ce n'était pas aussi mauvais que beaucoup de gens l'impliquent. Beaucoup d'histoires semblent être au moins de troisième main, avec un peu de "piment" supplémentaire ajouté chaque fois qu'ils sont redit. J'ai vu une histoire qui ressemble beaucoup à une version exagérée de celle que j'ai racontée il y a quelques décennies ...
  3. Hm ... La mise en forme de Markdown ne semble pas approuver mes numéros de saut.
  4. Et encore ...
  5. Mon commentaire était spécifique à C++, mais un grand nombre d'autres langages supportent également les paramètres par défaut et/ou la surcharge, et peuvent s'appliquer aussi bien à la plupart d'entre eux. Même sans cela, un appel comme f(param1, param2, 0,0,0); est assez facile à voir comme ayant des paramètres par défaut. Dans une certaine mesure, commander par l'utilisation est pratique, mais lorsque vous faites la commande, vous choisissez peu importe presque autant que d'être cohérent.
  6. True, un paramètre void * ne vous en dit pas beaucoup - mais un MODIFY void * est un peu mieux. Un type réel et une utilisation cohérente de const fournit beaucoup plus d'informations et est vérifié par le compilateur. Les autres langages n'ont peut-être pas/utilisent const, mais ils n'ont probablement pas de macros non plus. OTOH, certains prennent directement en charge ce que vous voulez - par exemple, Ada a in, out et inout spécificateurs.
+0

+1 pour les commentaires sur les types. Bien que tout ne soit pas nécessairement une liste dans Lisp, c'est toujours un bon point. – asm

+0

@Andrew: Ma surimplification est simplement un autre exemple de la même idée. C'est mon histoire et je m'en tiens à ça! –

+0

1 "Les types bien conçus rendent généralement les commentaires au format Doxygen une perte de temps" - peut-être si vous regardez dans le code. Peut-être pas si vous cherchez sur l'itra-web de l'entreprise pour la documentation de l'interface (qui est plus facile à naviguer avec des hyperliens). 2 - globales pas mal ?? Hmm, ok, fais ces globals "nus". Si elles ne sont pas enveloppées dans une fucntion, les globals sont une mauvaise chose. YMMNV. 3 - oui, j'ai tendance à sentir mauvais code à environ 4. 5 - excellent point !! (bien que le message soit agnostique) EST-il suffisant si je réorganise pour sortir, modifier, entrer? contd ... – Mawg

2

Je ne suis pas sûr que nous finirons à un seul point d'accord à ce sujet, tout le monde va venir avec des idées différentes (bonnes ou mauvaises en perspective de l'autre). Cela dit, je trouve Code Complete être un bon endroit où aller quand je suis coincé avec ce genre de problèmes.

+0

+1 pour le code complet (bien que je ne sois pas sûr où il aborde ce sujet) – Mawg

0

J'utiliserais la 'règle' proposée par Oncle Bob dans son livre Clean Code.

Ces ceux que je pense que je me souviens:

  • 2 paramètres sont corrects, 3 sont mauvais, plus besoin refactorisation
  • Les commentaires sont un signe de mauvais noms. Donc, il devrait y avoir aucun, et le but de la fonction et les paramètres doivent être claires à partir des noms
  • rendre le procédé court. Visez moins de 10 lignes de code.
+1

un nom de fonction peut être clair pour vous mais pas pour certains dev aléatoire qui lira votre code des années plus tard. Je pense que des commentaires sont toujours nécessaires pour rendre les choses vraiment claires! –

+1

Je suis Bob, et je suis un oncle, et je supporte les commentaires. Même avec un bon code, l'utilisation correcte des commentaires rendra le logiciel non trivial plus rapide à comprendre. – xpda

+0

Son commentaire sur les commentaires est basé sur des commentaires pauvres - ceux qui tentent de répondre à la question de "quoi". Les commentaires utiles répondent le plus souvent à la question du "pourquoi". Par exemple: "Cela utilise le tri par insertion au lieu du tri rapide car les données commencent toujours par être triées à au moins 95%." Ils sont particulièrement utiles dans des cas comme celui-là, où un choix inhabituel est fait, et un lecteur plus tard * pourrait * supposer qu'il a été fait par ignorance et perdrait du temps sur des changements mal guidés. –

1

Une grosse bête noire est le couplage de contrôle entre les fonctions. (Couplage de contrôle est quand un module contrôle le flux d'exécution d'une autre, par des drapeaux passant dire la fonction appelée ce qu'il faut faire.)

Par exemple (couper & coller du code que je viens d'avoir à travailler):

void UartEnable(bool enable, int baud); 

par opposition à:

void UartEnable(int baud); 
void UartDisable(void); 

d'autres termes - paramètres sont pour le passage de "données", et non "contrôle".