design patterns - Clases de nombres: ¿Cómo evitar llamar a todo un "<WhatEver> Manager"?
design-patterns oop (13)
Hace mucho tiempo, leí un artículo (creo que en una entrada de blog) que me puso en la pista "correcta" para nombrar objetos: sea muy cuidadoso al nombrar cosas en su programa.
Por ejemplo, si mi aplicación (como una aplicación de negocios típica) manejaba usuarios, compañías y direcciones, tendría una clase de dominio User
, Company
y Address
, y probablemente en algún lugar UserManager
un UserManager
, un AddressManager
y un AddressManager
que manejan esas cosas.
Entonces, ¿puedes decir qué hacen esos UserManager
, CompanyManager
y AddressManager
? No, porque Manager es un término muy genérico que se adapta a cualquier cosa que puedas hacer con tus objetos de dominio.
El artículo que leí recomienda usar nombres muy específicos. Si se UserManager
una aplicación de C ++ y el UserManager
del UserManager
consistiera en asignar y liberar a los usuarios del montón, no los manejaría, sino que protegería su nacimiento y muerte. Hmm, tal vez podríamos llamar a esto un UserShepherd
.
O tal vez el UserManager
del UserManager
es examinar los datos de cada objeto del usuario y firmarlos criptográficamente. Entonces tendríamos un UserRecordsClerk
.
Ahora que esta idea se me quedó pegada trato de aplicarla. Y encuentra esta idea simple increíblemente difícil.
Puedo describir lo que hacen las clases y (siempre y cuando no caiga en la codificación rápida y sucia) las clases que escribo hacen exactamente una cosa. Lo que me falta para pasar de esa descripción a los nombres es un tipo de catálogo de nombres, un vocabulario que asigna los conceptos a los nombres.
En última instancia, me gustaría tener en mi mente algo así como un catálogo de patrones (con frecuencia, los patrones de diseño proporcionan fácilmente los nombres de los objetos, por ejemplo, una fábrica )
- Fábrica: crea otros objetos (nombres tomados del patrón de diseño)
- Pastor: un pastor maneja la vida útil de los objetos, su creación y cierre.
- Sincronizador: copia datos entre dos o más objetos (o jerarquías de objetos)
Niñera: ayuda a que los objetos alcancen un estado "utilizable" después de la creación, por ejemplo, conectándolos a otros objetos
etcétera etcétera.
Entonces, ¿cómo manejas ese problema? ¿Tiene un vocabulario fijo, inventa nuevos nombres sobre la marcha o considera que nombrar las cosas no es tan importante o incorrecto?
PD: También me interesan los enlaces a artículos y blogs que tratan el tema. Para empezar, aquí está el artículo original que me hizo pensar en ello: nombrar clases Java sin un ''Administrador''
Actualización: resumen de respuestas
Aquí hay un pequeño resumen de lo que aprendí de esta pregunta mientras tanto.
- Intenta no crear nuevas metáforas (niñera)
- Echa un vistazo a lo que hacen otros marcos
Otros artículos / libros sobre este tema:
- ¿Qué nombres te encuentras anteponiendo / agregando a las clases regularmente?
- ¿Cuál es el mejor enfoque para nombrar clases?
- Libro: Patrones de diseño: Elementos de software orientado a objetos reutilizables (tapa dura)
- Libro: Patrones de arquitectura de aplicaciones empresariales (tapa dura)
- Libro: Patrones de Implementación (Paperback)
Y una lista actual de prefijos / sufijos de nombre que recogí (¡subjetivamente!) De las respuestas:
- Coordinador
- Constructor
- Escritor
- Lector
- Entrenador de animales
- Envase
- Protocolo
- Objetivo
- Convertidor
- Controlador
- Ver
- Fábrica
- Entidad
- Cangilón
Y un buen consejo para el camino.
No te pongas a nombrar la parálisis. Sí, los nombres son muy importantes, pero no son lo suficientemente importantes como para perder grandes cantidades de tiempo. Si no puedes inventar un buen nombre en 10 minutos, sigue adelante.
Como te interesan los artículos en esta área, te puede interesar el artículo de opinión de Steve Yegge "Ejecución en el Reino de los Nombres":
http://steve-yegge.blogspot.com/2006/03/execution-in-kingdom-of-nouns.html
Consideraría los patrones que está utilizando para su sistema, las convenciones de nomenclatura / catalogación / agrupación de clases de las tendencias a definirse por el patrón utilizado. Personalmente, me atengo a estas convenciones de nomenclatura ya que son la forma más probable para que otra persona pueda recoger mi código y ejecutarlo.
Por ejemplo, UserRecordsClerk podría explicarse mejor extendiendo una interfaz genérica de RecordsClerk que implementan UserRecordsClerk y CompanyRecordsClerk y luego se especializan en, lo que significa que uno puede mirar los métodos en la interfaz para ver para qué sirven / están generalmente sus subclases.
Vea un libro como Patrones de diseño para obtener información, es un libro excelente y podría ayudarlo a aclarar dónde pretende estar con su código, ¡si aún no lo está utilizando! ; o)
Reconozco que siempre que su patrón esté bien elegido y utilizado en la medida en que sea apropiado, ¡entonces bastan los nombres de clase bastante poco innovadores!
Creo que lo más importante a tener en cuenta es: ¿es el nombre suficientemente descriptivo? ¿Se puede decir mirando el nombre que se supone que debe hacer la Clase? El uso de palabras como "Administrador", "Servicio" o "Controlador" en sus nombres de clase puede considerarse demasiado genérico, pero dado que muchos programadores las usan, también ayuda a comprender para qué sirve la clase.
Yo mismo he estado usando mucho el patrón de fachada (al menos, creo que así es como se llama). Podría tener una clase de User
que describa solo un usuario y una clase de Users
que haga un seguimiento de mi "colección de usuarios". No llamo UserManager
la clase porque no me gustan los gerentes en la vida real y no quiero que me los recuerden :) Simplemente usar la forma plural me ayuda a entender lo que hace la clase.
Creo que lo más importante aquí es ser coherente dentro de la esfera de la visibilidad de su código, es decir, siempre que todos los que necesiten mirar / trabajar en su código entiendan su convención de nomenclatura, entonces eso debería estar bien, incluso si decide llamarlos. ''CompanyThingamabob'' y ''UserDoohickey''. La primera parada, si trabaja para una empresa, es ver si existe una convención de la empresa para nombrar. Si no existe o no trabajas para una empresa, crea tus propios términos de uso que tengan sentido para ti, repártelos con algunos colegas / amigos de confianza que al menos codifican de forma casual e incorpora cualquier comentario que tenga sentido.
Aplicar la convención de otra persona, incluso cuando es ampliamente aceptada, si no se salta de la página es un error en mi libro. En primer lugar, necesito entender mi código sin hacer referencia a otra documentación, pero al mismo tiempo debe ser lo suficientemente genérico para que no sea incomprensible para alguien más en el mismo campo en la misma industria.
Cuando me encuentro pensando en usar Manager
o Helper
en un nombre de clase, considero que es un olor de código que significa que aún no he encontrado la abstracción correcta y / o que estoy violando el principio de responsabilidad única , por lo que refactorizo y pongo más esfuerzo. El diseño a menudo hace que nombrar sea mucho más fácil.
Pero incluso las clases bien diseñadas no se nombran (siempre), y sus elecciones dependen en parte de si está creando clases de modelos de negocios o clases de infraestructura técnica.
Las clases de modelos de negocios pueden ser difíciles, porque son diferentes para cada dominio. Hay algunos términos que uso mucho, como la Policy
para las clases de estrategia dentro de un dominio (por ejemplo, LateRentalPolicy
), pero generalmente LateRentalPolicy
al tratar de crear un " lenguaje ubicuo " que puede compartir con usuarios empresariales, diseñar y nombrar clases para que Modelar ideas del mundo real, objetos, acciones y eventos.
Las clases de infraestructura técnica son un poco más fáciles, porque describen dominios que conocemos realmente bien. Prefiero incorporar nombres de patrones de diseño en los nombres de clase, como InsertUserCommand,
CustomerRepository,
o SapAdapter.
Entiendo la preocupación por comunicar la implementación en lugar de la intención, pero los patrones de diseño combinan estos dos aspectos del diseño de la clase, al menos cuando se trata de infraestructura, donde desea que el diseño de la implementación sea transparente incluso cuando oculta los detalles.
Específicamente para C #, encontré que las "Pautas de diseño de marco: convenciones, modismos y patrones para bibliotecas .NET reutilizables" tienen mucha buena información sobre la lógica de los nombres.
Sin embargo, en lo que respecta a la búsqueda de palabras más específicas, a menudo utilizo un diccionario de sinónimos y busco palabras relacionadas para intentar encontrar una buena. Sin embargo, trato de no pasar mucho tiempo con él, a medida que SuchAndSuchManager
, se me SuchAndSuchManager
mejores nombres o, a veces, me doy cuenta de que SuchAndSuchManager
realmente debería dividirse en varias clases, y luego el nombre de esa clase en desuso no se convierte en problema.
Estar al tanto de los patrones definidos por (digamos) el libro de GOF , y nombrar objetos después de estos me ayuda mucho a nombrar clases, organizarlas y comunicar la intención. La mayoría de las personas entenderán esta nomenclatura (o al menos una parte importante de ella).
Estoy a favor de los buenos nombres, y a menudo escribo sobre la importancia de tener mucho cuidado al elegir nombres para las cosas. Por esta misma razón, desconfío de las metáforas al nombrar cosas. En la pregunta original, "fábrica" y "sincronizador" parecen buenos nombres para lo que parecen significar. Sin embargo, "pastor" y "niñera" no lo son, porque se basan en metáforas . Una clase en tu código no puede ser literalmente una niñera; usted lo llama niñera porque se ocupa de otras cosas muy parecidas a una niñera de la vida real que se ocupa de bebés o niños. Eso está bien en el habla informal, pero no está bien (en mi opinión) para nombrar clases en código que tendrá que mantener quién sabe quién, quién sabe cuándo.
¿Por qué? Porque las metáforas son dependientes de la cultura y, a menudo, también dependientes del individuo. Para ti, nombrar a una clase "niñera" puede ser muy claro, pero tal vez no sea tan claro para otra persona. No debemos confiar en eso, a menos que esté escribiendo un código que sea solo para uso personal.
En cualquier caso, la convención puede hacer o deshacer una metáfora. El uso de "factory" en sí mismo se basa en una metáfora, pero que ha existido durante bastante tiempo y actualmente es bastante conocido en el mundo de la programación, por lo que diría que es seguro de usar. Sin embargo, "niñera" y "pastor" son inaceptables.
Hice una pregunta similar , pero cuando es posible trato de copiar los nombres que ya están en el marco .NET, y busco ideas en los marcos de Java y Android.
Parece que Helper
, Manager
y Util
son los nombres inevitables que se adjuntan para las clases de coordinación que no contienen ningún estado y son generalmente de procedimiento y estáticas. Una alternativa es el Coordinator
.
Podrías tener una prosay particularmente púrpura con los nombres e ir por cosas como Minder
, Overseer
, Supervisor
, Administrator
y Master
, pero como dije, prefiero mantenerlo como los nombres de marco a los que estás acostumbrado.
Algunos otros sufijos comunes (si ese es el término correcto) que también se encuentran en el marco .NET son:
-
Builder
-
Writer
-
Reader
-
Handler
-
Container
Podríamos prescindir de las xxxFactory
, xxxManager
o xxxRepository
si modelamos el mundo real correctamente:
Universe.Instance.Galaxies["Milky Way"].SolarSystems["Sol"]
.Planets["Earth"].Inhabitants.OfType<Human>().WorkingFor["Initech, USA"]
.OfType<User>().CreateNew("John Doe");
;-)
Puede echar un vistazo a source-code-wordle.de , he analizado allí los sufijos más utilizados de los nombres de clase de .NET framework y algunas otras bibliotecas.
Los 20 primeros son:
- atributo
- tipo
- ayudante
- colección
- convertidor
- entrenador de animales
- info
- proveedor
- excepción
- Servicio
- elemento
- gerente
- nodo
- opción
- fábrica
- contexto
- ít
- diseñador
- base
- editor
Si no puedo encontrar un nombre más concreto para mi clase que XyzManager, este sería un punto para que reconsiderara si esta es realmente una funcionalidad que pertenece a una clase, es decir, un "olor de código" arquitectónico.
Suena como una pendiente resbaladiza a algo que se publicaría en thedailywtf.com, "ManagerOfPeopleWhoHaveMortgages", etc.
Supongo que es correcto que una clase de administrador monolítico no sea un buen diseño, pero usar "Administrador" no es malo. En lugar de UserManager, podemos dividirlo en UserAccountManager, UserProfileManager, UserSecurityManager, etc.
"Administrador" es una buena palabra porque muestra claramente que una clase no representa una "cosa" del mundo real. ''AccountsClerk'': ¿cómo se supone que debo saber si esa es una clase que administra los datos del usuario o que representa a alguien que es un empleado de cuentas para su trabajo?