Les #regions sont-elles un anti-modèle ou une odeur de code?

267

C # permet l'utilisation de #region/ #endregionkeywords pour rendre des zones de code réductibles dans l'éditeur. Chaque fois que je le fais bien, je le fais pour cacher de gros morceaux de code qui pourraient probablement être refactorisés dans d'autres classes ou méthodes. Par exemple, j'ai vu des méthodes qui contiennent 500 lignes de code avec 3 ou 4 régions juste pour le rendre gérable.

Une utilisation judicieuse des régions est-elle donc un signe de problème? Cela semble être le cas pour moi.

Craig
la source
9
FYI: CodeMap élimine à peu près les besoins des régions. visualstudiogallery.msdn.microsoft.com/… - Cliquez et cela vous mènera à la méthode / attribut / peu importe. Je l'utilise tous les jours et c'est incroyable de voir combien vous gagnez en productivité et en termes cognitifs. Vous obtenez une vue beaucoup plus claire de la classe.
7
Quelqu'un peut-il en faire un wiki? Il n’ya pas de bonne ou de mauvaise réponse à cette question (enfin, dans des limites raisonnables), c’est presque complètement subjectif.
Ed S.
6
Pour ce que ça vaut, Jeff Atwood les déteste . Il soutient qu'ils cachent le mauvais code.
Brian
3
Code odor est un développeur qui ne se douche pas et n'utilise pas de déodorant!
marko
5
Des régions soigneusement codées en code puant sont ce que quelques pincements de Febreeze font sur un canapé croustillant. Cela le rend supportable jusqu'à ce que vous trouviez le temps nécessaire pour le remplacer.
Newtopian

Réponses:

285

Une odeur de code est un symptôme qui indique qu'il y a un problème dans la conception qui risque d'augmenter le nombre de bogues: ce n'est pas le cas pour les régions, mais les régions peuvent contribuer à créer des odeurs de code, comme les méthodes longues.

Puisque:

Un anti-modèle (ou anti-modèle) est un modèle utilisé dans les opérations sociales ou commerciales ou dans l'ingénierie logicielle qui peut être couramment utilisé mais qui est inefficace et / ou contre-productif dans la pratique.

les régions sont anti-modèles. Ils nécessitent plus de travail qui n'améliore pas la qualité ou la lisibilité du code, qui ne réduit pas le nombre de bogues, et qui ne peut que rendre le code plus compliqué à refactoriser.

N'utilisez pas de régions dans les méthodes; refactor à la place

Les méthodes doivent être courtes . S'il n'y a que dix lignes dans une méthode, vous n'utiliserez probablement pas de régions pour en cacher cinq lorsque vous travaillez sur les cinq autres.

En outre, chaque méthode doit faire une et une seule chose . Les régions, par contre, sont destinées à séparer différentes choses . Si votre méthode utilise A, puis B, il est logique de créer deux régions, mais c'est une mauvaise approche. au lieu de cela, vous devez reformuler la méthode en deux méthodes distinctes.

L'utilisation de régions dans ce cas peut également rendre la refactorisation plus difficile. Imaginez que vous avez:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    if (!verification)
    {
        throw new DataCorruptedException();
    }

    Do(data);
    DoSomethingElse(data);
    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine();
    auditEngine.Submit(data);
    #endregion
}

Réduire la première région pour se concentrer sur la seconde est non seulement risqué: nous pouvons facilement oublier l'exception qui stoppe le flux (il pourrait y avoir une clause de garde avec une returnsubstitution, ce qui est encore plus difficile à repérer), mais aurait également un problème. si le code doit être refait de cette façon:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    var info = DoSomethingElse(data);

    if (verification)
    {
        Do(data);
    }

    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine(info);
    auditEngine.Submit(
        verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
    #endregion
}

Désormais, les régions n'ont aucun sens et il est impossible de lire et de comprendre le code de la deuxième région sans consulter le code de la première.

Un autre cas que je vois parfois est celui-ci:

public void DoSomething(string a, int b)
{
    #region Validation of arguments
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }
    #endregion

    #region Do real work
    ...
    #endregion
}

Il est tentant d'utiliser des régions lorsque la validation des arguments commence à couvrir des dizaines de LOC, mais il existe un meilleur moyen de résoudre ce problème: celui utilisé par le code source du .NET Framework:

public void DoSomething(string a, int b)
{
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }

    InternalDoSomething(a, b);
}

private void InternalDoSomething(string a, int b)
{
    ...
}

N'utilisez pas de régions en dehors des méthodes pour regrouper

  • Certaines personnes les utilisent pour regrouper des champs, des propriétés, etc. Cette approche est incorrecte: si votre code est conforme à StyleCop, les champs, les propriétés, les méthodes privées, les constructeurs, etc. sont déjà regroupés et faciles à trouver. Si ce n'est pas le cas, il est temps de penser à appliquer des règles qui garantissent l'uniformité de votre code.

  • D'autres personnes utilisent des régions pour cacher beaucoup d'entités similaires . Par exemple, lorsque vous avez une classe avec cent champs (ce qui crée au moins 500 lignes de code si vous comptez les commentaires et les espaces), vous pouvez être tenté de placer ces champs dans une région, de la réduire et de les oublier. Encore une fois, vous vous trompez: avec autant de champs dans une classe, vous devriez penser à utiliser l’héritage ou découper l’objet en plusieurs objets.

  • Enfin, certaines personnes sont tentées d'utiliser des régions pour regrouper des éléments liés : un événement avec son délégué, ou une méthode liée à l'IO avec d'autres méthodes liées à l'IO, etc. Dans le premier cas, cela devient un désordre difficile à maintenir. , Lire et comprendre. Dans le second cas, la meilleure solution serait probablement de créer plusieurs classes.

Y a-t-il un bon usage pour les régions?

Non, il y avait une utilisation héritée: le code généré. Néanmoins, les outils de génération de code doivent simplement utiliser des classes partielles. Si C # est pris en charge par les régions, c'est principalement à cause de son utilisation héritée et du fait que maintenant trop de personnes utilisent des régions dans leur code, il serait impossible de les supprimer sans détruire les bases de code existantes.

Pensez-y comme à propos goto. Le fait que la langue ou l'EDI prenne en charge une fonctionnalité ne signifie pas qu'elle doit être utilisée quotidiennement. La règle StyleCop SA1124 est claire: vous ne devez pas utiliser de régions. Jamais.

Exemples

Je suis en train de réviser le code de mon collègue. La base de code contient beaucoup de régions et est en fait un exemple parfait de la manière dont il est préférable de ne pas utiliser de régions et de la raison pour laquelle les régions génèrent un code incorrect. Voici quelques exemples:

4 000 monstres LOC:

J'ai récemment lu quelque part sur Programmers.SE que lorsqu'un fichier contient trop de usings (après avoir exécuté la commande "Remove Unused Usings"), c'est un bon signe que la classe à l'intérieur de ce fichier en fait trop. La même chose s'applique à la taille du fichier lui-même.

En examinant le code, je suis tombé sur un fichier de 4 000 lettres LOC. Il est apparu que l'auteur de ce code avait simplement copié-collé la même méthode de 15 lignes des centaines de fois, en modifiant légèrement les noms des variables et de la méthode appelée. Une simple expression régulière permettait de couper le fichier de 4 000 à 500 LOC, en ajoutant simplement quelques génériques; Je suis à peu près sûr qu'avec une refactorisation plus intelligente, cette classe peut être réduite à quelques dizaines de lignes.

En utilisant des régions, l'auteur s'est encouragé à ignorer le fait que le code est impossible à maintenir et mal écrit, et à dupliquer fortement le code au lieu de le refactoriser.

Région “Do A”, Région “Do B”:

Un autre excellent exemple était une méthode d’initialisation de monstre qui consistait simplement à exécuter la tâche 1, puis la tâche 2, puis la tâche 3, etc. Il y avait cinq ou six tâches totalement indépendantes, chacune initialisant quelque chose dans une classe conteneur. Toutes ces tâches ont été regroupées dans une méthode et regroupées par régions.

Cela avait un avantage:

  • La méthode était assez claire pour comprendre en regardant les noms de région. Ceci étant dit, la même méthode une fois refactorisée serait aussi claire que l'originale.

Les problèmes, en revanche, étaient multiples:

  • Ce n'était pas évident s'il y avait des dépendances entre les régions. Espérons qu’il n’ya pas eu de réutilisation des variables; sinon, l'entretien pourrait être un cauchemar encore plus.

  • La méthode était presque impossible à tester. Comment sauriez-vous facilement si la méthode qui fait vingt choses à la fois les fait correctement?

Champs région, région des propriétés, région du constructeur:

Le code révisé contenait également de nombreuses régions regroupant tous les champs, toutes les propriétés, etc. Cela posait un problème évident: la croissance du code source.

Lorsque vous ouvrez un fichier et voyez une liste énorme de champs, vous êtes plus enclin à refactoriser la classe d'abord, puis à travailler avec du code. Avec les régions, vous prenez l'habitude de faire disparaître des choses et de les oublier.

Un autre problème est que si vous le faites partout, vous allez créer des régions d'un bloc, ce qui n'a aucun sens. C'était en fait le cas dans le code que j'ai examiné, où il y avait beaucoup de #region Constructorcontenant un constructeur.

Enfin, les champs, propriétés, constructeurs, etc. devraient déjà être en ordre . S'ils le sont et s'ils correspondent aux conventions (constantes commençant par une lettre majuscule, etc.), il est déjà clair où le type d'éléments s'arrête et où d'autres commence. Vous n'avez donc pas besoin de créer explicitement des régions pour cela.

Arseni Mourzenko
la source
13
Je pense qu’il existe au moins quelques utilisations défendables des # régions - par exemple, la réduction de clauses de garde (vérification des paramètres d’entrée) qui, si elles ne sont pas fermées, nuisent à l’essence ou à la "viande" de la méthode. Un autre exemple est la gestion des exceptions sur les limites de l'API; vous ne voulez souvent pas impacter la trace de la pile en appelant d'autres méthodes pour envelopper l'exception, de sorte que vous ayez plusieurs lignes de code pour envelopper et rediffuser. Ce code est souvent non pertinent et peut être réduit en toute sécurité.
Daniel B
9
Vérification de la réalité. J'ai vu beaucoup de régions inter-méthodes qui ont été utiles. Lorsque vous avez une méthode de plusieurs centaines de lignes avec une logique de contrôle imbriquée avec des dizaines à des centaines de lignes avec certaines d'entre elles - dieu merci, l'idiot a au moins placé des régions.
radarbob
37
@radarbob: en bref, les régions sont utiles dans un code de merde qui ne devrait pas exister en premier lieu.
Arseni Mourzenko
41
-1 (si j'avais la réputation). Même si les membres de votre type sont bien organisés et séparés, il peut y en avoir beaucoup. Les régions vous évitent de devoir faire défiler les 10 ou 12 propriétés, ainsi que les getters et les setters associés, juste pour accéder à une méthode sur laquelle vous souhaitez travailler. La seule alternative est de réduire individuellement toutes vos propriétés, ce dont je ne suis pas un fan. La fonctionnalité d'affichage / masquage à grande échelle fournie par les régions est extrêmement utile. Je suis d'accord sur les régions intra-méthode cependant.
Asad Saeeduddin
14
Je suis strictement en désaccord avec cette réponse: le code puant et la région n'ont rien à voir avec l'autre. Si votre code pue, il pue avec ou sans régions. J'utilise les régions de manière à séparer mes classes en régions. En général, je m'en tiens au même schéma: propriétés publiques, méthodes publiques, champs privés, méthodes privées. C’est la seule utilisation pour laquelle je voudrais des régions. Quoi que ce soit d'autre, vous êtes probablement en train de diviser le principal SRP dans votre code.
Alexus
113

C'est incroyable pour moi combien de personnes détestent les régions avec tant de passion!

Je suis tout à fait d’accord avec beaucoup d’objections: insuffler du code #regionpour le cacher est une mauvaise chose. Diviser une classe en #regionsdifférentes classes est clairement une erreur. Utiliser une #regionpour intégrer des informations sémantiques redondantes est, bien, redondant.

Mais aucune de ces choses signifie qu'il n'y a rien en soi de mal à utiliser les régions dans votre code! Je ne peux que supposer que les objections de la plupart des gens viennent du fait d'avoir travaillé dans des équipes où d'autres sont enclins à utiliser les fonctionnalités IDE comme celle-ci de manière incorrecte. J'ai le luxe de travailler en primaire, et j'apprécie la manière dont les régions ont aidé à organiser mon flux de travail. C'est peut-être mon trouble obsessionnel compulsif, mais je n'aime pas voir un tas de code sur mon écran à la fois, peu importe la précision avec laquelle il est écrit. Séparer les éléments en régions logiques me permet de réduire le code dont je me moque pour travailler sur le code que je réalise.se soucier de. Je n'ignore pas le code mal écrit, cela n'a pas de sens de le refactoriser plus qu'il ne l'est, et l'organisation "méta" supplémentaire est descriptive plutôt qu'inutile.

Maintenant que j'ai passé plus de temps à travailler en C ++, à programmer plus directement à l'API Windows, je me suis dit que je souhaitais que le support pour les régions soit aussi bon que pour le C #. Vous pourriez faire valoir que l'utilisation d'une bibliothèque d'interface graphique alternative rendrait mon code plus simple ou plus clair, éliminant ainsi la nécessité de supprimer le bruit de code non pertinent de l'écran, mais j'ai d'autres raisons de ne pas vouloir le faire. Je connais assez bien mon clavier et mon IDE pour développer / réduire le code subdivisé en régions, ce qui prend moins d'une fraction de seconde. Le temps que j'ai économisé en ressources intellectuelles, en essayant de limiter mon attention consciente au seul code sur lequel je travaille actuellement, en vaut largement la peine. Tout cela appartient à une seule classe / un seul fichier, mais tout n’appartient pas à mon écran en même temps.

Le fait est que l'utilisation #regionsde séparer et diviser logiquement votre code n'est pas une mauvaise chose à éviter à tout prix. Comme Ed le souligne, ce n'est pas une "odeur de code". Si votre code sent, vous pouvez être sûr qu'il ne provient pas des régions, mais du code que vous avez essayé d'enterrer dans ces régions. Si une fonctionnalité vous aide à être mieux organisé ou à écrire un meilleur code, je vous prie de l’ utiliser . Si cela devient un obstacle ou si vous vous trouvez à ne pas l'utiliser correctement, arrêtez de l' utiliser. Si le pire arrive, et que vous êtes obligé de travailler en équipe avec des personnes qui l'utilisent, mémorisez le raccourci clavier pour désactiver le code décrivant: Ctrl+ M, Ctrl+P. Et arrête de te plaindre. Parfois, j'ai l'impression que c'est une autre façon pour ceux qui veulent être perçus comme de "vrais", les programmeurs "hardcore" aiment essayer de faire leurs preuves. Vous évitez mieux d'éviter les régions que d'éviter la coloration syntaxique. Cela ne fait pas de vous un développeur plus macho.

Tout cela étant dit, les régions dans une méthode ne sont que pure absurdité. Chaque fois que vous vous trouvez vouloir faire cela, vous devriez être en train de refactoriser dans une méthode séparée. Pas d'excuses.

Cody Gray
la source
9
Bien dit. L’utilisation de régions pour l’organisation n’est pas plus préjudiciable que le basculement de l’option "view whitespace" de l’EDI. C'est une préférence personnelle.
Josh
24
Travailler sur WPF avec ViewModels qui ont 10 ou 20 propriétés qui englobent simplement les propriétés de mon modèle, j'aime les régions - je peux simplement ranger ces propriétés dans une région (elles n'ont jamais besoin d'être touchées) et garder mon œil sur le code pertinent .
Kirk Broadhurst
4
Entièrement d'accord. Dans .NET 2.0, les propriétés ont une longueur d'environ 8 à 10 lignes. Lorsque vous avez plus de 20 propriétés dans une classe, elles prennent beaucoup de place. Les régions sont parfaites pour les effondrer.
Kristof Claes
6
@ Kristof: Comme sont des propriétés dans .NET 4.0 qui font la validation d'entrée simple. Les propriétés automatiques n'ont tout simplement pas été aussi magiques à mes fins.
Cody Grey
8
Je suis prêt à parier ma balle gauche que les gens qui détestent les régions n'ont jamais développé une application WPF, ou n'ont jamais vraiment utilisé les fonctionnalités de définition de WPF telles que la liaison de données et la liaison de commande. Configurer simplement votre code pour que ces travaux prennent beaucoup de place et vous n'avez généralement pas à les revoir.
l46kok
70

Tout d'abord, je ne supporte plus le terme "odeur de code". Il est utilisé trop souvent et est souvent utilisé par des personnes qui ne pourraient pas reconnaître un bon code s'il le mordait. Quoi qu'il en soit ...

Personnellement, je n'aime pas utiliser beaucoup de régions. Il est plus difficile d’obtenir le code, et c’est ce qui m’intéresse, j’aime les régions quand j’ai un gros morceau de code qui n’a pas besoin d’être touché très souvent. En dehors de cela, ils semblent juste me gêner, et des régions comme "Private Methods", "Public Methods", etc. me rendent folle. Ils s'apparentent à des commentaires de la variété i++ //increment i.

J'ajouterais également que l'utilisation de régions ne peut pas vraiment être un "anti-motif" car ce terme est couramment utilisé pour décrire les modèles de logique / conception de programmes, et non la présentation d'un éditeur de texte. C'est subjectif. utilisez ce qui fonctionne pour vous. Vous ne vous retrouverez jamais avec un programme impossible à maintenir en raison de votre surutilisation des régions, ce qui est ce que sont les anti-modèles. :)

Ed S.
la source
2
Normalement, je vous inviterais à écrire un commentaire sur l'odeur de code, mais dans ce cas, il est tout à fait exact. Le non-code ne peut pas être une odeur de code. +2!
7
Haha, eh bien, je ne veux pas dire que le terme "odeur de code" ne peut pas être utilisé avec précision. C'est possible, mais je le vois tellement souvent que ma réaction immédiate est une gêne, surtout quand elle vient de personnes qui ne font que répéter ce qu'elles entendent sans le comprendre ni avoir un esprit critique. Des déclarations telles que "plus de 5 variables locales dans une fonction est une odeur de code" montrent simplement le peu d'expérience de cette personne.
Ed S.
13
Je ne suis pas sûr de comprendre votre commentaire sur les odeurs de code. Les odeurs de code n'indiquent pas qu'il y a un problème, il peut y en avoir un.
Craig
7
+1 pour résister à l'odeur de code de terme. J'en ai eu marre quand j'ai vu un message affirmant que les méthodes privées étaient une odeur de code. Mais dans l’ensemble, je ne partage pas votre dégoût pour les régions. Je suis facilement distrait. En fait, j'adorerais que VS ait un mode VB4 dans lequel vous ne pouvez afficher qu'une seule méthode à la fois.
Josh
7
Je voulais juste insister et dire que le mauvais usage d'une métaphore parfaitement bonne ne devrait pas dévaluer la métaphore. "Code odor" est une excellente métaphore, une compréhension immédiate, facile à retenir et à utiliser. Il existe encore de nombreux endroits où appliquer la métaphore "odeur de code" reste le meilleur moyen de faire passer un message.
Eric King
23

Oui les régions sont une odeur de code!

Je serais heureux de voir des régions complètement supprimées du compilateur. Chaque développeur propose son propre programme de toilettage inutile qui ne sera jamais utile à un autre programmeur. J'ai tout à faire avec les programmeurs qui veulent décorer et embellir leur bébé, rien à voir avec une valeur réelle.

Pouvez-vous penser à un exemple où vous pensiez "bon sang, j'aimerais que mon collègue utilise certaines régions ici!"?

Même si je peux configurer mon IDE pour qu'il étende automatiquement toutes les régions, cela reste une plaie pour les yeux et empêche de lire le code réel.

Je m'en fous vraiment si toutes mes méthodes publiques sont regroupées ou non. Félicitations, vous connaissez la différence entre une déclaration de variable et une initialisation, inutile de l'afficher dans le code!

Toilettage sans valeur!

De plus, si votre fichier a besoin d’architecture d’information grâce à l’utilisation de régions, vous voudrez peut-être lutter contre le problème principal: votre classe est bien trop grande! Le diviser en parties plus petites est beaucoup plus bénéfique et, lorsqu'il est effectué correctement, ajoute une vraie sémantique / lisibilité.

Joppe
la source
Est-ce que #regions fait partie du compilateur? Je pensais qu’il s’agissait simplement d’une directive adressée à l’EDI qui pourrait être ignorée.
Steve Rukuts
2
Le compilateur devrait les ignorer lors de l'analyse de votre code C #. S'il ne les ignore pas, cela les jettera. Je le pense de cette façon.
Joppe
1
"Pouvez-vous penser à un exemple où vous pensez" bon sang, j'aimerais que mon collègue utilise certaines régions ici! "?" Oui, vraiment. Quand j'ai un cours avec des méthodes privées et des méthodes publiques, je les divise en régions, car lors du refactoring des méthodes publiques, il n'est pas nécessaire de toucher au code privé et vice versa.
Anshul
De toute évidence, vous n'avez jamais vu de code externalisé. Trop souvent, les régions auraient été super à voir dans un code externalisé. Même si le code est nul, au moins, il aurait été beaucoup plus facile à comprendre s’il s’agissait de regrouper les choses dans un sens logique. Bien que, si leur code n'est pas logique, les régions ne le seraient pas non plus, cela aurait probablement aggravé la situation. Les régions sont excellentes si elles sont utilisées correctement.
Nickmccomb
15

Personnellement, j'utilise les régions pour regrouper différents types de méthodes ou de parties de code.

Ainsi, un fichier de code pourrait ressembler à ceci lors de son ouverture:

  • Propriétés publiques
  • Constructeurs
  • Enregistrer les méthodes
  • Modifier les méthodes
  • Méthodes d'assistance privée

Je ne mets pas les régions à l'intérieur des méthodes. IMHO qui est un signe d'odeur de code. Une fois, je suis tombé sur une méthode de plus de 1200 lignes comportant 5 régions différentes. C'était un spectacle effrayant!

Si vous l'utilisez comme moyen d'organiser votre code de manière à rendre la recherche plus rapide pour les autres développeurs, je ne pense pas que ce soit un signe de problème. Si vous l'utilisez pour masquer des lignes de code à l'intérieur d'une méthode, je dirais qu'il est temps de repenser cette méthode.

Tyanna
la source
14
Pouah. Je sais que c'est un sujet subjectif, mais je ne supporte vraiment pas ce stratagème. D'après mon expérience, le terme "organisation" n'aide pas du tout et rend la navigation dans le code très pénible. Je préfère également les méthodes de regroupement, non seulement par modificateur d'accès, mais par responsabilité logique. Pour l'interface publique, je regroupe généralement chaque méthode / propriété, mais souvent une méthode protégée peut appeler une fonction d'assistance privée. Dans ce cas, je préfère de loin la fonction d'assistance (qui peut uniquement être utilisée à cet endroit). méthode qui l'appelle.
Ed S.
3
@Ed S. - c'est pourquoi j'ai dit "pourrait ressembler". C'est très subjectif. Je ne dis pas que chaque fichier devrait ressembler à cela. Je serais surpris s'ils le faisaient. Juste un exemple sur un sujet complexe. :)
Tyanna
Oh je sais, comme je l'ai dit; c'est subjectif. Tout ce qui fonctionne pour vous / votre équipe. Je l'ai juste pour ce schéma parce que cela ne fonctionne pas (pour moi), mais je devais maintenir un projet qui faisait justement cela. Cela m'a rendu fou.
Ed S.
3
@ EdS. Alors allez dans vos options dans vs et désactivez les régions. Problème résolu.
Andy
Pourquoi vos objets ont-ils des méthodes de sauvegarde? :(
TheCatWhisperer
10

Utiliser des #regionblocs pour rendre une très grande classe lisible est généralement un signe de violation du principe de responsabilité unique. S'ils sont habitués à regrouper le comportement, il est également probable que la classe en fasse trop (une fois encore, en violation de SRP).

Les #regionblocs ne sont pas une odeur de code en eux-mêmes, mais ils sont plutôt "Febreze pour le code" dans le sens où ils essaient de masquer les odeurs. Bien que je les utilise beaucoup dans le passé, lorsque vous commencez à refactoriser, vous commencez à en voir moins car ils finissent par ne pas beaucoup se cacher.

Austin Salonen
la source
5

Le mot clé ici est "judicieux". Il est difficile d’imaginer un cas où placer une région dans une méthode est judicieux; c'est trop probable pour cacher du code et de la paresse. Cependant, il peut y avoir de bonnes raisons d'avoir quelques régions ici et là dans son code.

S'il y a beaucoup de régions, je pense que c'est une odeur de code. Les régions sont souvent un indice d'un éventuel lieu de refactorisation future. Beaucoup de régions signifient que quelqu'un ne comprend pas vraiment l'allusion.

Utilisées judicieusement, elles constituent un bon compromis entre la structure d'une classe unique comportant de nombreuses méthodes et la structure de nombreuses classes comportant chacune quelques méthodes. Ils sont plus utiles quand une classe commence à se rapprocher du point où elle devrait être refactorisée en plusieurs classes, mais elle n’en est pas encore là. En regroupant les méthodes associées, il est facile d'extraire ultérieurement un ensemble de méthodes associées dans leur propre classe si leur nombre ne cesse de croître. Par exemple, si j'ai une classe qui approche 500 lignes de code, cet ensemble de méthodes utilisant 200 lignes de code total collectées ensemble dans une région est probablement un bon élément à refactoriser - et cette autre région avec 100 lignes de code dans sa les méthodes pourraient également être une bonne cible.

Une autre façon que j'aime utiliser les régions est de réduire l'un des effets négatifs de la refactorisation d'une grande méthode: de nombreuses petites méthodes concises et facilement réutilisables qu'un lecteur doit faire défiler pour passer à une autre méthode sans rapport avec les autres. Une région peut être un bon moyen de méta-encapsuler une méthode et ses aides pour les lecteurs. Ainsi, une personne travaillant avec un aspect différent de la classe peut simplement les réduire et supprimer rapidement cette partie du code. Bien entendu, cela ne fonctionne que si vos régions sont vraiment bien organisées et servent essentiellement à documenter votre code.

En général, les régions m'aident à rester organisé, m'aident à "documenter" mon code et m'aident à localiser les lieux de refactorisation beaucoup plus tôt que si je n'utilisais pas de régions.

Ethel Evans
la source
4

J'utilise principalement des régions pour les classes de serveur CRUD afin d'organiser les différents types d'opérations. Même alors, je pourrais volontiers partir sans eux.

Si utilisé intensivement, il soulèverait un drapeau rouge. Je serais à l'affût des classes qui ont trop de responsabilités.

D'après mon expérience, une méthode avec des centaines de lignes de code est certainement une odeur.

TaylorOtwell
la source
4

Ma règle générale est la suivante: si un fichier contient plus de 5 régions, c'est une odeur de code.

Par exemple, il serait peut-être bon de définir le champ, les méthodes, les propriétés et les constructeurs, mais si vous commencez à envelopper toutes les autres méthodes dans une région qui lui est propre, quelque chose ne va vraiment pas.

Et oui, j'ai participé à de nombreux projets dans lesquels c'est le cas, souvent en raison de normes de codage médiocres, de la génération de code ou des deux. Il est vite vieux de devoir basculer tous les éléments de Visual Studio pour avoir une bonne vue d'ensemble du code.

Homde
la source
4

LES RÉGIONS SONT UTILISÉES

Je les ai utilisées personnellement pour "coder à la main" des événements d'interface auparavant pour des applications Windows Forms.

Cependant, dans mon travail, nous utilisons un générateur de code pour gérer SQL et il utilise automatiquement des régions pour trier ses types de méthodes de sélection, de mise à jour, de suppression, etc.

Ainsi, bien que je ne les utilise pas souvent, ils conviennent parfaitement à la suppression de gros morceaux de code.

Ken
la source
1
J'ai utilisé des générateurs de code similaires et préfère utiliser des classes partielles pour supprimer le code généré.
Craig
Nous faisons, les régions sont à l'intérieur du code généré pour faciliter la lecture ou le débogage (si nécessaire).
Ken
4

Si vous avez des régions dans le code IN , vous avez certainement un problème (sauf le cas du code généré). Mettre des régions dans le code signifie en gros "refactoriser ceci".

Cependant, il y a d'autres cas. Un qui me vient à l’esprit que j’ai fait il ya quelque temps: une table contenant quelques milliers d’articles précalculés. C'est une description de la géométrie, à moins d'une erreur dans la table, il n'y aura jamais l'occasion de la regarder. Bien sûr, j'aurais pu obtenir les données d'une ressource ou similaire, mais cela empêcherait l'utilisation du compilateur pour faciliter la lecture.

Loren Pechtel
la source
1
C'est un meilleur cas d'utilisation pour une classe partielle avec celle stockée dans un fichier séparé, ou peut-être un IMyDataSource injecté avec une implémentation HardcodedDataSource.
Bryan Boettcher
3

Sur un projet récent, il y avait une méthode de 1700 lignes avec plusieurs régions intégrées. Ce qui est intéressant, c’est que les régions ont démarqué des actions distinctes menées dans le cadre de la méthode. J'ai été capable de faire une méthode refactor -> extract sur chacune des régions sans impacter la fonctionnalité du code.

En général, les régions utilisées pour masquer le code de plaque de chaudière sont utiles. Je vous déconseille d'utiliser des régions pour masquer des propriétés, des champs, etc., car si elles sont trop lourdes à regarder lorsque vous travaillez dans la classe, c'est probablement un signe que la classe devrait être davantage décomposée. Mais en règle générale, si vous placez une région dans une méthode, vous feriez mieux d’extraire une autre méthode qui explique ce qui se passe plutôt que d’envelopper ce bloc dans une région.

Michael Brown
la source
3

Les régions peuvent-elles être utilisées dans un code de bonne qualité? Probablement. Je parie qu'ils le sont, dans de nombreux cas. Cependant, mon expérience personnelle me laisse très méfiant - j'ai vu des régions presque exclusivement mal utilisées. Je dirais que je suis blasé, mais toujours optimiste.

Je peux diviser grossièrement le code utilisant la région que j'ai vu jusqu'à présent en trois catégories:

  • Code mal factorisé: la plupart du code que j'ai vu utilise les régions comme un outil de factorisation pour les pauvres. Par exemple, une classe qui a pris une telle ampleur qu'il est logique de la spécialiser à des fins différentes peut être divisée en régions distinctes, une pour chaque objectif.

  • Code écrit en utilisant les mauvaises bibliothèques, et parfois le mauvais langage, pour le domaine problématique Souvent, lorsqu'un programmeur n'utilise pas le bon ensemble de bibliothèques pour le domaine problématique, le code devient incroyablement détaillé - avec de nombreuses petites fonctions d'assistance qui n'appartiennent vraiment pas (ils appartiennent probablement à leur propre bibliothèque).

  • Code écrit par les étudiants ou les récents diplômés. Certains programmes et cours semblent tenter d'inculquer aux étudiants l'utilisation de régions à des fins diverses. Vous verrez des régions jonchant le code source au point où le rapport entre les balises de région et les lignes de code se situe dans la plage de 1: 5 ou moins.

les bleuets
la source
3

Je dirais que c'est une "odeur de code".

Les anti-modèles sont généralement des problèmes structurels fondamentaux dans un logiciel, alors que les régions, en elles-mêmes, provoquent un comportement désagréable dans un éditeur. L’utilisation de régions n’est pas réellement mauvaise en soi, mais leur utilisation fréquente, en particulier pour masquer des fragments de code, peut indiquer que d’autres problèmes plus graves et indépendants se produisent ailleurs.

comment s'appelle-t-il
la source
@Andrew Grimm: ouais
whatsisname
3

J'utilise les régions pour une seule chose (du moins je ne peux pas penser aux autres endroits où je les utilise): grouper les tests unitaires pour une méthode.

J'ai généralement une classe de test par classe, puis je groupe les tests unitaires pour chaque méthode en utilisant des régions portant le nom de la méthode. Pas sûr que ce soit une odeur de code ou quoi que ce soit, mais comme l'idée de base est que les tests unitaires n'ont pas besoin de changer sauf s'ils se cassent parce qu'un élément du code a changé, il est plus facile pour moi de trouver tous les tests pour une méthode spécifique. assez rapidement.

J'ai peut-être déjà utilisé des régions pour organiser du code, mais je ne me souviens pas de la dernière fois. Je m'en tiens à mes régions dans les classes de tests unitaires.

Anne Schuessler
la source
1
Avez-vous déjà eu des tests qui testent plus d'une méthode?
Marcie
Je ne comprends pas vraiment la question ou ce que vous visez. La réponse est: non, un test unitaire est toujours ciblé sur une seule méthode ou plutôt sur un aspect de cette méthode.
Anne Schuessler
2

Je crois qu’il s’agit d’une tendance anti-politique et pense franchement qu’il faut les éliminer. Mais si vous êtes dans la situation regrettable de travailler dans un endroit standard, Visual Studio constitue un formidable outil pour minimiser le montant que vous souhaitez vomir chaque fois que vous voyez une région. Je déteste #Régions

Ce plugin va maximiser la taille de la police des régions vraiment petites. Ils seront également étendus afin que vous n'ayez pas à appuyer sur ctr + m + l pour ouvrir toutes les régions. Cela ne corrige pas cette forme de cancer du code mais cela la rend supportable.

DeadlyChambers
la source
0

J'utilise des régions pour contenir chaque combinaison de visibilité et de type de membre. Donc, toutes les réceptions privées vont dans une région, etc.

La raison pour laquelle je fais cela n'est pas pour que je puisse plier le code. C'est parce que mon éditeur est scripté pour que je puisse insérer, par exemple, une référence à un proxy:

#region "private_static_members"
 /// <summary>
 /// cache for LauncherProxy
 /// </summary>
private static LauncherProxy _launcherProxy;
#endregion

#region "protected_const_properties"
protected LauncherProxy LauncherProxy{
  get{
    if(_launcherProxy==null) {
      if (!God.Iam.HasProxy(LauncherProxy.NAME)) {
        God.Iam.RegisterProxy(new LauncherProxy());
      }
      _launcherProxy=God.Iam.Proxy(LauncherProxy.NAME) as LauncherProxy;
    }
    return _launcherProxy;
  }
}
#endregion

dans le code et que chaque partie soit soigneusement rangée dans la région appropriée.

Dans ce cas, la macro analyserait mon projet, me donnerait une liste de procurations et injecterait le code de celui que je voulais. Mon curseur ne bouge même pas.

Au début de l’apprentissage du C #, j’avais envisagé d’utiliser des régions pour maintenir les points communs, mais c’est une proposition hasardeuse, car ce n’est pas une relation un à un à tout moment. Qui veut s'inquiéter d'un membre utilisé par deux régions, ou même commencer à rompre avec ces conditions.

Le seul autre type de ségrégation concerne les méthodes. Je vais répartir les méthodes en commandes, fonctions et gestionnaires, de sorte que j'aurais une région pour les commandes publiques, privées, etc., etc.

Cela me donne une granularité, mais c'est une granularité cohérente et sans équivoque sur laquelle je peux compter.

marque
la source
-1 dès que je reçois 125 points. Vous ajoutez des lignes de code inutiles. POURQUOI POURQUOI POURQUOI POUVEZ-VOUS METTRE UNE RÉGION autour d'une propriété ... if (God.Iam.AbusingRegions () == true) myName = "Mark"
DeadlyChambers Le
1
@DeadlyChambers La raison en est expliquée dans le deuxième paragraphe - J'utilise des macros d'éditeur pour injecter des modèles de code communs dans le fichier. Les régions aident à conserver la structure du fichier afin de regrouper les éléments similaires. Je ne mets pas une région autour d'une propriété singulière, mais toutes les propriétés entrent dans une région désignée en fonction de leurs attributs "protected_const_properties". Avez-vous lu le post ??
Mark
1
Vous pouvez probablement refactoriser cela dans: protected LauncherProxy LauncherProxy => God.Iam.GetOrAddProxy <LauncherProxy> (ref _launcherProxy); et ainsi vous n’avez plus besoin de région. De plus, _launcherProxy peut être renommé en _launcherProxyCache afin que vous n'ayez pas besoin de région ni de commentaire.
aeroson
0

Les régions sont des expressions de pré-processeur - autrement dit, elles sont traitées comme des commentaires et sont fondamentalement ignorées par le compilateur. Ils sont purement un outil visuel utilisé dans Visual Studio. Par conséquent, #region n'est pas vraiment une odeur de code, car ce n'est tout simplement pas du code. L'odeur de code est plutôt la méthode 800 lignes qui inclut de nombreuses responsabilités différentes, etc. Si vous voyez 10 régions dans une méthode, elle est probablement utilisée pour masquer une odeur de code. Cela dit, je les ai vus utilisés avec une extrême efficacité pour rendre une classe plus agréable à l'oeil et plus navigable - dans une classe également très bien écrite et structurée!

BKSpurgeon
la source
0

Les régions étaient une idée organisationnelle astucieuse, mais ne tenaient pas compte de certaines tendances des développeurs à vouloir tout sous-catégoriser, et étaient généralement inutiles selon les pratiques de POO les plus modernes ... elles constituent une "odeur", dans le sens où leur utilisation indique souvent que votre classe / méthode est beaucoup trop grande et doit être refactorisée, car vous enfreignez probablement le "S" des principes SOLID ... mais comme toute odeur, cela ne signifie pas nécessairement que quelque chose va mal.

Les régions servent davantage de code fonctionnel que de code orienté objet, IMO, où vous avez de longues fonctions de données séquentielles qu'il est logique de dissocier, mais il y a eu des fois où je les ai personnellement utilisées en c #, et elles ont presque toujours concentrez-vous sur le code que vous n'avez pas besoin / envie de regarder. Pour moi, il s’agissait généralement de constantes chaînes SQL brutes dans la base de code utilisée pour NPoco ou ses variantes. À moins que vous vous inquiétiez de la façon dont les données permettent de remplir l'objet POCO via votre ORM, elles étaient totalement inutiles à regarder ... et si vous vous en souciez, hé, élargissez simplement la région et BAM! Plus de 150 lignes de requêtes SQL compliquées pour votre plus grand plaisir.

Jeremy Holovacs
la source