design-patterns - Naming Classes-Comment éviter d'appeler tout un "<WhatEver>Manager"?




oop naming-conventions (12)

Il y a longtemps, j'ai lu un article (je crois une entrée de blog) qui m'a mis sur la bonne piste pour nommer les objets: Soyez très très scrupuleux à propos de nommer des choses dans votre programme.

Par exemple, si mon application était (en tant qu'application professionnelle typique) traitant des utilisateurs, des entreprises et des adresses, j'aurais une classe de domaine User , Company et Address - et probablement quelque part un UserManager , un CompanyManager et un AddressManager qui apparaîtraient. ces choses.

Alors pouvez-vous dire ce que ces UserManager , CompanyManager et AddressManager font? Non, car Manager est un terme très très générique qui correspond à tout ce que vous pouvez faire avec vos objets de domaine.

L'article que j'ai lu a recommandé d'utiliser des noms très spécifiques. S'il s'agissait d'une application C ++ et que le UserManager du UserManager et libérait des utilisateurs du tas, il ne gérait pas les utilisateurs mais gardait leur naissance et leur mort. Hmm, peut-être que nous pourrions appeler cela un UserShepherd .

Ou peut-être que le UserManager de UserManager consiste à examiner les données de chaque objet Utilisateur et à signer les données de manière cryptographique. Ensuite, nous aurions un UserRecordsClerk .

Maintenant que cette idée est restée avec moi, j'essaie de l'appliquer. Et trouver cette idée simple incroyablement difficile.

Je peux décrire ce que font les classes et (tant que je ne glisse pas dans le codage rapide et sale) les cours que j'écris font exactement une chose. Ce qui me manque pour passer de cette description aux noms est une sorte de catalogue de noms, un vocabulaire qui fait correspondre les concepts aux noms.

En fin de compte j'aimerais avoir quelque chose comme un catalogue de modèle dans mon esprit (fréquemment les modèles de conception fournissent facilement les noms d'objet, par exemple une usine )

  • Factory - Crée d'autres objets (nommage pris dans le motif de conception)
  • Shepherd - Un berger gère la vie des objets, leur création et leur fermeture
  • Synchronizer - Copie des données entre deux ou plusieurs objets (ou hiérarchies d'objets)
  • Nanny - Aide les objets à atteindre un état "utilisable" après la création - par exemple en câblant vers d'autres objets

  • etc.

Alors, comment gérez-vous ce problème? Avez-vous un vocabulaire fixe, inventez-vous de nouveaux noms à la volée ou pensez-vous nommer des choses pas si importantes ou fausses?

PS: Je suis également intéressé par des liens vers des articles et des blogs traitant de la question. Pour commencer, voici l'article original qui m'a fait réfléchir: Nommer des classes Java sans un 'Manager'

Mise à jour: Résumé des réponses

Voici un petit résumé de ce que j'ai appris de cette question en attendant.

  • Essayez de ne pas créer de nouvelles métaphores (Nanny)
  • Jetez un oeil à ce que d'autres cadres font

D'autres articles / livres sur ce sujet:

Et une liste actuelle des préfixes / suffixes de noms que j'ai collectés (subjectivement!) À partir des réponses:

  • Coordinateur
  • Constructeur
  • Écrivain
  • Lecteur
  • Gestionnaire
  • Récipient
  • Protocole
  • Cible
  • Convertisseur
  • Manette
  • Vue
  • Usine
  • Entité
  • Seau

Et un bon conseil pour la route:

Ne pas nommer la paralysie. Oui, les noms sont très importants mais ils ne sont pas assez importants pour perdre énormément de temps. Si vous ne pouvez pas trouver un bon nom en 10 minutes, passez à autre chose.


Answers

Puisque vous êtes intéressé par des articles dans ce domaine, vous pourriez être intéressé par l'article d'opinion de Steve Yegge "Execution in the Kingdom of Nouns":

http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html


Vous pouvez jeter un oeil à source-code-wordle.de , j'ai analysé là les suffixes les plus fréquemment utilisés des noms de classe de l'infrastructure .NET et d'autres bibliothèques.

Les 20 premiers sont:

  • attribut
  • type
  • assistant
  • collection
  • convertisseur
  • gestionnaire
  • Info
  • fournisseur
  • exception
  • un service
  • élément
  • directeur
  • nœud
  • option
  • usine
  • le contexte
  • article
  • designer
  • base
  • éditeur

Je suis tout à fait pour de bons noms, et j'écris souvent sur l'importance de prendre grand soin en choisissant des noms pour des choses. Pour cette même raison, je me méfie des métaphores lorsque je nomme des choses. Dans la question initiale, "usine" et "synchroniseur" ressemblent à de bons noms pour ce qu'ils semblent signifier. Cependant, "berger" et "nounou" ne le sont pas, car ils sont basés sur des métaphores . Une classe dans votre code ne peut pas être littéralement une nounou; vous l'appelez une nounou parce qu'il s'occupe d'autres choses comme une vraie nounou s'occupe des bébés ou des enfants. C'est OK dans un discours informel, mais pas OK (à mon avis) pour nommer les classes dans le code qui devra être maintenu par qui sait qui sait quand.

Pourquoi? Parce que les métaphores dépendent de la culture et dépendent souvent aussi de l'individu. Pour vous, nommer une classe «nounou» peut être très clair, mais peut-être que ce n'est pas clair pour quelqu'un d'autre. Nous ne devrions pas compter sur cela, sauf si vous écrivez du code uniquement pour un usage personnel.

En tout cas, la convention peut faire ou défaire une métaphore. L'utilisation de "factory" lui-même est basée sur une métaphore, mais celle qui existe depuis un certain temps et est actuellement assez bien connue dans le monde de la programmation, donc je dirais que c'est sûr à utiliser. Cependant, "nounou" et "berger" sont inacceptables.


Cela ressemble à une pente glissante vers quelque chose qui serait posté sur thedailywtf.com, "ManagerOfPeopleWhoHaveMortgages", etc.

Je suppose que c'est juste qu'une classe Manager monolithique n'est pas bonne, mais utiliser 'Manager' n'est pas mauvais. Au lieu de UserManager, nous pouvons le décomposer en UserAccountManager, UserProfileManager, UserSecurityManager, etc.

«Manager» est un bon mot car il montre clairement qu'une classe ne représente pas une «chose» dans le monde réel. 'AccountsClerk' - comment suis-je censé dire si c'est une classe qui gère les données d'utilisateur, ou représente quelqu'un qui est un commis aux comptes pour leur travail?


Je pense que la chose la plus importante à garder à l'esprit est: le nom est-il assez descriptif? Pouvez-vous dire en regardant le nom que la classe est censée faire? L'utilisation de mots tels que "Manager", "Service" ou "Handler" dans vos noms de classe peut être considérée comme trop générique, mais étant donné que beaucoup de programmeurs les utilisent, cela aide aussi à comprendre ce qu'est la classe.

J'ai moi-même beaucoup utilisé le motif de façade (du moins, je pense que c'est comme ça qu'on l'appelle). Je pourrais avoir une classe User qui ne décrit qu'un seul utilisateur, et une classe Users qui garde la trace de ma "collection d'utilisateurs". Je n'appelle pas la classe un UserManager parce que je n'aime pas les managers dans la vie réelle et je ne veux pas qu'on me les rappelle :) Simplement utiliser le pluriel aide à comprendre ce que fait la classe.


Être au fait des modèles tels que définis par (disons) le livre GOF , et nommer les objets après ceux-ci m'apporte un long chemin en nommant les classes, en les organisant et en communiquant l'intention. La plupart des gens comprendront cette nomenclature (ou au moins une partie importante).


Nous pourrions nous passer de toute xxxFactory , xxxManager ou xxxRepository si nous xxxRepository correctement le monde réel:

Universe.Instance.Galaxies["Milky Way"].SolarSystems["Sol"]
        .Planets["Earth"].Inhabitants.OfType<Human>().WorkingFor["Initech, USA"]
        .OfType<User>().CreateNew("John Doe");

;-)


Je considérerais les modèles que vous utilisez pour votre système, les conventions de nommage / catalogage / regroupement des classes de tendent à être définies par le modèle utilisé. Personnellement, je m'en tiens à ces conventions de nommage car elles sont le moyen le plus probable pour une autre personne de pouvoir récupérer mon code et de courir avec elle.

Par exemple, UserRecordsClerk pourrait être mieux expliqué en développant une interface RecordsClerk générique que UserRecordsClerk et CompanyRecordsClerk implémenter puis se spécialiser, ce qui signifie que l'on peut regarder les méthodes dans l'interface pour voir ce que les sous-classes font généralement.

Voir un livre comme Design Patterns pour info, c'est un excellent livre et pourrait vous aider à éclaircir où vous visez être avec votre code - si vous ne l'utilisez pas déjà! o)

Je pense que tant que votre modèle est bien choisi et utilisé autant que nécessaire, alors des noms de classe assez simples et non-inventifs devraient suffire!


J'ai posé une question similaire , mais si possible, j'essaie de copier les noms déjà dans le framework .NET, et je cherche des idées dans les frameworks Java et Android.

Il semble que Helper , Manager et Util sont les noms incontournables que vous attachez aux classes de coordination qui ne contiennent aucun état et qui sont généralement procédurales et statiques. Une alternative est le Coordinator .

Vous pourriez obtenir une prononciation particulièrement violette avec les noms et aller pour des choses comme Minder , Overseer , Supervisor , Administrator , et Master , mais comme je l'ai dit, je préfère le garder comme les noms de cadre auxquels vous êtes habitué.

Certains autres suffixes communs (si c'est le bon terme) que vous trouverez également dans le framework .NET sont:

  • Builder
  • Writer
  • Reader
  • Handler
  • Container

Quand je pense à utiliser Manager ou Helper dans un nom de classe, je considère que c'est une odeur de code qui signifie que je n'ai pas encore trouvé la bonne abstraction et / ou que je suis en train de violer le principe de responsabilité unique. dans la conception rend souvent le nommage beaucoup plus facile.

Mais même les classes bien conçues ne se nomment pas (toujours), et vos choix dépendent en partie de la création de classes de modèle métier ou de classes d'infrastructure technique.

Les classes de modèles métier peuvent être difficiles, car elles sont différentes pour chaque domaine. Il y a quelques termes que j'utilise beaucoup, comme Policy pour les classes de stratégie dans un domaine (par exemple, LateRentalPolicy ), mais ceux-ci découlent généralement de la création d'un " langage omniprésent " que vous pouvez partager avec les utilisateurs professionnels. modélisez des idées, des objets, des actions et des événements du monde réel.

Les classes d'infrastructure technique sont un peu plus faciles, car elles décrivent des domaines que nous connaissons très bien. Je préfère incorporer des noms de modèle de conception dans les noms de classe, comme InsertUserCommand, CustomerRepository, ou SapAdapter. Je comprends la préoccupation de communiquer la mise en œuvre plutôt que l'intention, mais les modèles de conception marient ces deux aspects de la conception de classe - du moins quand vous traitez avec l'infrastructure, où vous voulez que la conception soit transparente même lorsque vous cachez les détails.


Je crois que la chose critique ici est d'être cohérent dans la sphère de la visibilité de votre code, c'est-à-dire que tout le monde qui doit regarder / travailler sur votre code comprend votre convention de nommage alors ça devrait aller, même si vous décidez de les appeler 'CompanyThingamabob' et 'UserDoohickey'. Le premier arrêt, si vous travaillez pour une entreprise, est de voir s'il existe une convention d'entreprise pour la dénomination. Si tel n'est pas le cas ou si vous ne travaillez pas pour une entreprise, créez les vôtres en utilisant des termes qui vous conviennent, faites-le circuler parmi quelques collègues / amis de confiance qui, au moins, codent avec désinvolture et incorporez tout commentaire pertinent.

Appliquer la convention de quelqu'un d'autre, même si elle est largement acceptée, si elle ne saute pas la page à vous est une erreur dans mon livre. Tout d'abord, j'ai besoin de comprendre mon code sans référence à d'autres documents, mais en même temps, il doit être assez générique pour que ce ne soit pas incompréhensible pour quelqu'un d'autre dans le même domaine dans la même industrie.


Abstract factory crée une classe de base avec des méthodes abstraites définissant des méthodes pour les objets qui doivent être créés. Chaque classe d'usine qui dérive la classe de base peut créer sa propre implémentation de chaque type d'objet.

La méthode d'usine est simplement une méthode simple utilisée pour créer des objets dans une classe. Il est généralement ajouté dans la racine agrégée (la classe Order a une méthode appelée CreateOrderLine )

Usine abstraite

Dans l'exemple ci-dessous, nous concevons une interface permettant de découpler la création de file d'attente d'un système de messagerie et de créer ainsi des implémentations pour différents systèmes de files d'attente sans avoir à modifier la base de code.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

Méthode d'usine

Le problème dans les serveurs HTTP est que nous avons toujours besoin d'une réponse à chaque requête.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Sans la méthode d'usine, les utilisateurs du serveur HTTP (c'est-à-dire les programmeurs) seraient forcés d'utiliser des classes spécifiques à l'implémentation qui IHttpRequest l' IHttpRequest l'objectif de l'interface IHttpRequest .

Par conséquent, nous introduisons la méthode usine de sorte que la création de la classe de réponse est également abstraite.

Résumé

La différence est que l' objectif de la classe contenant une méthode usine n'est pas de créer des objets , alors qu'une fabrique abstraite ne doit être utilisée que pour créer des objets.

Il faut faire attention lorsqu'on utilise des méthodes d'usine car il est facile de casser le LSP ( principe de substitution de Liskov ) lors de la création d'objets.







design-patterns oop naming-conventions naming