Les problèmes avec Eviter les classes de Schtroumpfs nommant avec des espaces de noms

39

J'ai tiré le terme nommant Schtroumpf d' ici (numéro 21). Pour sauver ceux qui ne connaissent pas le problème, nommer un Schtroumpf consiste à préfixer un groupe de classes, variables, etc., avec un préfixe commun, de sorte que vous obtenez "a SmurfAccountViewpasse a SmurfAccountDTOà SmurfAccountController", etc.

La solution que j'ai généralement entendue est de créer un espace de noms smurf et de supprimer les préfixes de smurf. Cela m'a généralement bien servi, mais je rencontre deux problèmes.

  1. Je travaille avec une bibliothèque avec une Configurationclasse. Il aurait pu être appelé, WartmongerConfigurationmais il se trouve dans l'espace de noms Wartmonger Configuration. De même, j'ai une Configurationclasse qui pourrait être appelée SmurfConfiguration, mais c'est dans l'espace de noms du Schtroumpf, donc ce serait redondant. Il y a des endroits dans mon code où Smurf.Configurationapparaît à côté Wartmonger.Configurationet où taper des noms complets est maladroit et rend le code moins lisible. Il serait plus agréable de traiter avec a SmurfConfigurationet (si c’était mon code et non une bibliothèque) WartmongerConfiguration.

  2. J'ai une classe appelée Servicedans mon espace de noms Schtroumpf qui aurait pu s'appeler SmurfService. Serviceest une façade située au-dessus d’une bibliothèque de schtroumpfs complexe exécutant des tâches Schtroumpf. SmurfServicesemble être un meilleur nom car Servicesans le préfixe de Schtroumpf, il est incroyablement générique. Je peux accepter que SmurfServicec’était déjà un nom générique, inutile, et enlever le schtroumpf ne faisait que rendre cela plus évident. Mais il aurait pu être nommé Runner, Launcheretc., et cela me "sentirait encore" mieux SmurfLaunchercar je ne sais pas ce que Launcherfait un , mais je sais ce que SmurfLauncherfait un . On pourrait faire valoir que ce qu’un Smurf.Launcherfait devrait être aussi apparent queSmurf.SmurfLauncher`Smurf.Launcher est en quelque sorte une classe liée à l’installation plutôt qu’une classe qui lance des schtroumpfs.

S'il existe un moyen ouvert et fermé de traiter l'un ou l'autre de ces problèmes, ce serait formidable. Si non, quelles sont les pratiques courantes pour atténuer leur contrariété?

Daniel Koverman
la source
3
Lance-t-il Smurf.Launcherdes Schtroumpfs ou lance-t-il SmurfJob? Peut-être pourrait-il s'appeler Smurf.JobLauncher?
Blorgbeard
2
C’est une odeur de code pour nommer une classe XService, XManager, etc. Cela ne veut rien dire. C'est comme un util. Si vous parcourez les noms de fichiers, il se peut qu’il manque quelque chose. Il n'y a aucun moyen de savoir à moins de regarder à l'intérieur. Je renommerais SmurfService en quelque chose de complètement différent.
Daniel Kaplan
1
En fait, il lance SmurfJobs ou les exécute techniquement pour être cohérent avec le langage de la documentation Smurf. À la lumière de cela et les autres réponses, je vais renommer SmurfServiceà SmurfJobRunner. Il semble que le numéro 1 n’ait pas la meilleure résolution agnostique que prévu. Je peux voir des cas où aller avec SmurfConfigurationserait le bon appel, mais dans mon cas, je pense que Configurationc'est mieux, même avec les tracas de Wartmonger.Configuration.
Daniel Koverman
6
J'essaie de comprendre pourquoi vous avez une seule classe qui se préoccupe de configurer les Wartmongers et les Schtroumpfs.
Donal Fellows
Pourquoi faire Smurf.Configurationet se SmurfConfigurationsentir différent? Ce n'est sûrement pas le personnage supplémentaire, n'est-ce pas? (Raccourcissez Configsi la longueur est le problème.) Avez- Smurf.Configurationvous des problèmes qui SmurfConfigurationne le font pas?
Pablo H

Réponses:

16

Vous soulevez de bons points.

  1. En ce qui concerne les classes en double, vous pouvez créer un alias sur les classes en C #. Utiliser par exemple using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;Voir ce post sur StackOverflow . Vous n'avez pas indiqué votre langage de programmation, mais je l'ai déduit de ce que vous avez écrit. Ainsi, lorsque vous traitez avec deux projets différents, vous pouvez les aliaser en tant que SmurfConfigurationet WartmongerConfigurationce qui libérerait une ambiguïté lors de la consommation des deux classes.

  2. En tant que service est exposé à une ou plusieurs applications externes, je ne vois aucun problème à lui attribuer le nom de votre application. Par conséquent, dans ce cas, il SmurfServiceserait valide car il dissiperait toute ambiguïté des groupes de services dans l'application consommatrice.

Je pense que les espaces de noms devraient être utilisés pour éviter ce style de nommage. Il est plus difficile de coder le code et de voir à quoi ressemble une classe sans lire MyCompanyMyProductMyAreaClassName. L'utilisation de la technique de crénelage vous permet de réduire les ambiguïtés là où vous en avez besoin. La seule fois où je pense que vous devriez introduire de la complexité dans la dénomination, c’est, comme je l’ai indiqué au paragraphe 2, que les gens vont utiliser un service. C’est ici qu’il est parfaitement logique d’avoir ce style de nom car, si le consommateur dispose de nombreux services, il consomme une ambiguïté qui pourrait prêter à confusion.

Sam
la source
5
les alias ne font que compliquer les choses. Au lieu de Smurf.Service, vous avez maintenant SmurfService = Smurf.Service. Donc, vous pourriez aussi bien avoir SmurfService comme nom de la chose en premier lieu. Ils ont leur place, mais pas pour ce problème particulier. Cependant, c'est probablement la meilleure réponse à un problème qui n'a pas de réponse :)
gbjbaanb
Le C # en moi est sorti dans ma question, mais je travaille actuellement avec java et org.apache.smurfville.wartmonger.configuration. Cela exclut malheureusement les alias. 2 est un point solide, je vais donc garder la marque Smurf pour le service.
Daniel Koverman
25

Le but des espaces de noms est que vous puissiez avoir des classes du même nom de différentes bibliothèques sans les heurter. Lorsque vous devez utiliser la même classe nommée des deux, vous devez supprimer l'ambiguïté en préfixant l'une ou les deux de sa portée d'espace de noms.

Cela dit, ce n’est pas vraiment mauvais d’avoir plusieurs classes de Schtroumpfs si Schtroumpf vous dit quelque chose de spécifique à propos de la classe. Les noms de classe doivent être suffisamment descriptifs pour vous donner quelques informations sur ce que fait la classe.

      Session
       ^   ^
      /     \
DBSession   HttpSession

De même, un DBSessionpeut prendre un DBRequestobjet qui retourne un DBResponseobjet. Le HttpSessionpourrait également opérer sur HttpRequestet HttpResponseobjets.

Ce sont des cours de Schtroumpf avec un but.

Ils pourraient vivre dans l' MyCompanyespace de noms , mais MyCompanyHttpSessionet MyCompanyDBSessionne vous donne pas plus d' informations que vous aviez avant. Dans ce cas, déposez le Schtroumpf et faites-en un espace de noms.

MyCompany.HttpSession
Dave Rager
la source
3

Je me suis déjà heurté à ce même point de confusion et il s’agit généralement de savoir si nous incluons ce genre de chose dans son nom.

Vous mentionnez SmurfConfigurationet WartmongerConfigurationcomme types potentiels de configurations. Vous indiquez que vous avez supprimé l'adjectif (son type) de son espace de noms afin que ce qu'il vous reste ne soit que la vanille Configuration. J'éviterais de faire ça.

C'est comme si on décidait que la glace à la fraise n'est que de la glace dans l'espace de noms fraise et de la même manière avec le chocolat, mais ce qui est arrivé, c'est que vous avez divorcé de l'adjectif qui lui donne son identité de la chose elle-même. Ce n'est pas de la crème glacée dans la catégorie des fraises. C'est de la glace à la fraise, une sorte de glace.

Imaginons que dans votre application, vous importez la Strawberry.IceCreamclasse, puis vous instanciez directement à partir de IceCream.

var ic = new IceCream(); //actually I'm strawberry ice cream

Cela peut sembler très utile jusqu'au moment où vous importez une autre IceCreamclasse. Vous revenez maintenant au problème initial de devoir faire la distinction entre eux, ce qui est problématique. Ce que tu voulais tout le temps était:

var sic = new StrawberryIceCream();
var cic = new ChocolateIceCream();

Il est préférable de laisser les espaces de noms pour éviter des conflits potentiels entre des tiers qui pourraient incidemment représenter les mêmes concepts dans leurs bibliothèques. Lorsqu'un développeur crée une bibliothèque ou un projet, il doit toutefois nommer chaque concept de manière unique et utiliser les espaces de noms en tant que dossiers d'organisation uniquement. Souvent, le nom du dossier se trouve dans le nom des concepts qu’il organise et c’est acceptable.

Mario T. Lanza
la source
2

En règle générale, si vous avez un préfixe commun sur un groupe de classes, elles méritent probablement d'aller dans leur propre espace de noms. Pour résoudre le problème, vous devez utiliser des classes portant le même nom à partir de deux espaces de nom:

1) Alias ​​les espaces de noms, bien que ce soit bref et précis, toute abréviation naturelle, peut-être même une lettre:

using Sm = Smurf;
using W = Wartmonger;

Puis préfixez toujours où que vous soyez et nommez les instances de manière appropriée:

Sm::Configuration smConf; 
W::Configuration wConf;

2) alias la classe, comme suggéré dans une autre réponse.

using SmConf = Smurf.Configuration;

3) Toute bibliothèque sur laquelle vous avez le contrôle, envisagez de ne pas utiliser le terme 'Configuration'. Utilisez le dictionnaire des synonymes: par exemple, "Paramètres", "Modèle", "Paramètres". Cela pourrait de toute façon avoir plus de sens pour le contexte: par exemple, si Smurf était une sorte de module d’analyse numérique, vous auriez écrit «Parameters» conviendrait mieux pour sa configuration. Utilisez le vocabulaire particulier associé au contexte d'un module à votre avantage pour trouver des noms uniques qui conservent l'unicité, même lorsqu'ils sont mélangés dans d'autres espaces de noms. Je pense que cela pourrait être une sorte de réponse à la question 2 du PO.

4) code du refactor afin que vous n'ayez pas à mélanger l'utilisation de la configuration à partir de deux endroits différents. Les détails de ce sont à vous.

5) Combinez les deux configurations en une avant de la transmettre à votre classe. Utilisez une classe de configuration combinée pour représenter:

struct Conf {
    SmurfConfiguration smurf;
    WartmongerConfiguation wart;
}

Les noms de variable de membre abrégés sont maintenant en quelque sorte la même chose que l'aliasing de la classe / de l'espace de noms.

Benoît
la source
0

Cela semble étrange d’ajouter un point au nom qui vous dérange.

Wartmonger.Configuration configuration = Wartmonger.Configuration .new();

// vs

WartmongerConfiguration configuration = WartmongerConfiguration.new();

Si les deux configurations Smurfet Wartmongerutilisées ensemble au même endroit, mais séparément, sont utilisées à plusieurs endroits, l’espace de nommage est définitivement une bonne approche.

Namespace ayant donnera la possibilité d'utiliser les noms « propres » dans le code interne, où les préfixes vous finissez à l' aide à l' SmurfConfigurationintérieur du SmurfServicecode interne », ce qui peut devenir ennuyeux à chaque fois que vous ouvrirez ce code.

Fabio
la source