combien de classes par paquet? méthodes par classe? lignes par méthode?

Je dois donner une note générale à un énorme projet Java pour lequel je n’ai que peu de visibilité et je me demandais s’il existait des directives pour déterminer:

  • quel nombre de classes par paquet peut être considéré comme correct, trop faible ou trop élevé (ce projet a 3,89 classes par paquet, ce qui me semble un peu trop petit),
  • nombre de méthodes par classe? (ce projet a 6,54 méthodes par classe …
  • nombre de lignes par méthode? (ce projet a environ 7 lignes par méthode (semble plutôt bon pour moi, peut-être un peu bas))

Je dois noter que cette question ne concerne que la volumésortinge. J’ai un tas de rapports provenant d’outils de qualité (checkstyle, jdepend, cpd, pmd, ncss) qui me donnent plus de vision sur la redondance du code, l’utilisation des classes, les bogues, etc.

Steve McConnell, dans son livre Code Complete, recommande environ 7 méthodes par classe et plus aucune ligne dans une méthode ne peut être visualisée sur un seul écran sans défilement.

Je ne suis pas sûr des classes par paquet.

Je recommande fortement de lire Code Complete pour plus d’informations sur ces sujets.

Je pense que des statistiques comme celle-là sont plutôt inutiles, comment connaître les lignes par méthode montre-t-il si elle est utile au projet ou non? Je pense que vous devriez regarder plus dans le sens de:

  1. Vos paquets englobent-ils des classes similaires?
  2. Vos cours fonctionnent-ils comme une entité à part entière?
  3. Les méthodes au sein des classes fonctionnent-elles correctement et efficacement?

À part l’utilisation de la mémoire, peu importe que la méthode soit volumineuse ou non? L’autre chose à rechercher dans les méthodes très longues est de savoir si la trace de la stack sera plus grande que l’ajout de cette fonctionnalité à une méthode parente. Je me méfierais de mesurer le succès d’un projet en fonction des lignes de code.

Robert C. Martin, qui a récemment publié le livre “Clean Code”, déclare que le nombre de lignes par méthode devrait être le plus petit possible. Entre 1 et 7 lignes est une bonne règle de base.

Le livre The ThoughtWorks Anthology, dans l’essai «Object Calisthenics» de Jeff Bay, contient également un argument intéressant. Il suggère 9 contraintes plutôt difficiles qui feront de vous un meilleur développeur OO sur le long terme. En savoir plus sur eux ici.

Pour répondre à vos questions spécifiques, ce sont les contraintes spécifiques à vous: – Pas plus de 10 classes par package – Un maximum de 50 lignes par classe

Ces contraintes peuvent ne pas être idéales pour tous vos projets réels, mais leur utilisation dans un petit projet (de loisir?) Vous obligera à adopter une meilleure pratique.

Malheureusement, il n’y a pas de notion absolue (objective) de qualité dans les logiciels. Ainsi, il n’y a pas de “bonne” valeur pour ceux-ci. Cependant, voici deux observations (personnelles):

3.89 classes / paquet est très faible. Cela signifie que vous vous battrez à travers un arbre compliqué de paquets.

7 lignes par méthode: en effet, ça sonne bien. Toutefois, si ce nombre a été obtenu à la suite d’un effort intentionnel visant à réduire le nombre de lignes de méthodes, il est possible qu’une seule tâche logique ait été répartie autour de plusieurs méthodes privées, ce qui compliquera la compréhension de la classe ( dans certains cas). En fait, dans CodeComplete-2, l’auteur cite une recherche qui a révélé que la longueur de la méthode est beaucoup moins importante que sa complexité cyclomatique et son niveau d’imbrication.

Une directive de conception utile indique que chaque classe ne doit faire qu’une seule chose et bien le faire. Cela ne vous donnera pas un nombre fixe de méthodes par classe, mais cela limitera le nombre et rendra la classe plus facile à comprendre et à maintenir.

Pour les méthodes, vous pouvez adopter une vue similaire et viser des méthodes aussi petites que possible, mais pas plus petites. Pensez-y de cette façon: si vous pouvez diviser la méthode en deux ou plusieurs parties distinctes, elle n’est évidemment pas aussi petite qu’elle pourrait l’être. Les petites méthodes sont faciles à comprendre et en divisant le code comme celui-ci, vous obtiendrez une meilleure vue d’ensemble des méthodes de haut niveau et propulguerez les détails à des méthodes de bas niveau.

(note: tl; dr disponible tout en bas pour mon opinion réelle)

Je ne vais pas citer de grand nom et dire que c’est la bonne réponse parce que c’est toujours très dépendant de la façon dont vous faites tout ça. Par exemple, le nombre de méthodes: Si vous créez un logiciel de contrôle pour la télécommande moderne des téléviseurs LCD HD avec environ 40 à 50 boutons, comment pouvez-vous diviser ces classes de manière cohérente pour avoir, par exemple, 7 méthodes? par classe?

Personnellement, j’aime garder toutes les méthodes d’un niveau d’accesseur dans une classe, ce qui signifie que certaines classes d’utilitaires peuvent avoir des centaines de méthodes, mais selon moi, il est plus facile de faire quelque chose comme SsortingngUtil.escapeXMLspecialCharacters(someSsortingng) que SsortingngUtil.XML.escapeSpecialCharacters(someSsortingng) ou XMLUtil.escapeSpecialCharacters(someSsortingng) . Bien que toutes ces solutions soient apparemment correctes, la première prospère (du moins dans mon esprit!) Parce que c’est un moyen simple et très facile d’accéder à cette méthode: vous n’avez pas à penser si la chaîne que vous manipulez contient XML ou XHTML ou JSON ou autre, vous ne choisirez qu’une méthode du groupe général de méthodes et c’est tout.

En gardant l’analogie avec la télévision précédente, supposons que vous les divisez en plusieurs classes. Si nous nous permettons d’avoir 7 de ces méthodes par classe en moyenne et que nous MenuButtons à regrouper les boutons de la télécommande en groupes sensés tels que MenuButtons , AdjustmentButtons et ‘NumberSelectorButtons’, nous nous retrouvons avec une dizaine de classes. Ce n’est pas une mauvaise chose en fait, mais cela devient un peu déroutant, surtout si on ne les divise pas avec soin en groupes sensuels. Imaginez les messages de votre bureau TVRemotes’R’Us Inc.: “Qui a dit que le bouton marche / arrêt était un bouton de commande?” “Qui est le joker qui a mis le volume +/- sur les boutons de menu? PRE / CH (le bouton qui commute entre le canal actuel et le bouton précédent et / ou la source d’image) n’est pas un bouton numérique!” “Le bouton guide ouvre à la fois le guide TV et le menu de navigation en fonction du contexte, que ferons-nous avec cela?”

Comme vous pouvez le voir avec cet exemple, l’utilisation d’un nombre arbitraire pour vous limiter pourrait introduire une complexité inutile et briser le stream logique de l’application.

Avant de lancer mes deux derniers centimes, une chose sur le nombre de lignes par méthode: pensez au code comme à des blocs. Chaque boucle est un bloc, chaque condition est un bloc et ainsi de suite. Quel est le montant minimum de ces blocs nécessaires pour une unité de code qui a une responsabilité unique? Cela devrait être votre limiteur, pas le désir d’avoir “Seven partout”. à partir du nombre de classes dans le package, méthodes dans les classes et lignes de code dans les méthodes.

Et voici le TL; DR :

Donc, mon véritable avis est le suivant: le nombre de classes dans le package devrait être assez faible. J’ai commencé récemment à faire ce qui suit, mais je ne suis pas sûr de pouvoir suivre:

  • Le paquet foo contient des interfaces et d’autres classes communes pour les implémentations.
  • Le paquetage foo.bar contient l’implémentation des interfaces pour la bar fonctions
  • Le paquet foo.baz contient l’implémentation desdites interfaces pour la fonction baz

Cela signifie généralement que toute ma structure a un nombre de classes cohérent (et probablement faible) et que, en lisant les interfaces de classe de niveau supérieur (et leurs commentaires), je devrais aussi comprendre les autres packages.

Méthodes par classe: Tout ce qui est nécessaire comme je l’ai expliqué ci-dessus. Si votre classe ne peut pas vivre sans 170 méthodes, laissez-la en avoir. Le refactoring est une vertu, pas quelque chose qui peut être appliqué tout le temps.

Lignes par méthode: aussi bas que possible, je finis généralement avec 10 à 25 lignes par méthode et 25 est un peu élevé pour moi, donc je dirais que 10 est un bon point d’équilibre pour cela.