Los problemas para evitar las clases de nombres de pitufos con espacios de nombres

39

Saqué el término pitufo de aquí (número 21). Para salvar a cualquiera que no esté familiarizado con el problema, el nombramiento de pitufos es el acto de prefijar un grupo de clases relacionadas, variables, etc. con un prefijo común para que termines con "a SmurfAccountViewpasa a SmurfAccountDTOa SmurfAccountController", etc.

La solución que generalmente he escuchado es crear un espacio de nombres de pitufo y soltar los prefijos de pitufo. En general, esto me ha servido bien, pero me encuentro con dos problemas.

  1. Estoy trabajando con una biblioteca con una Configurationclase. Podría haberse llamado WartmongerConfigurationpero está en el espacio de nombres de Wartmonger, por lo que simplemente se llama Configuration. También tengo una Configurationclase que podría llamarse SmurfConfiguration, pero está en el espacio de nombres de Smurf, por lo que sería redundante. Hay lugares en mi código donde Smurf.Configurationaparece junto Wartmonger.Configurationy escribir nombres completos es torpe y hace que el código sea menos legible. Sería mejor tratar con una SmurfConfigurationy (si fuera mi código y no una biblioteca) WartmongerConfiguration.

  2. Tengo una clase llamada Serviceen mi espacio de nombres Pitufo que podría haberse llamado SmurfService. Servicees una fachada en la parte superior de una compleja biblioteca de pitufos que ejecuta trabajos de pitufos. SmurfServiceparece un nombre mejor porque Servicesin el prefijo Smurf es increíblemente genérico. Puedo aceptar que SmurfServiceya era un nombre genérico e inútil y eliminar el pitufo simplemente lo hizo más evidente. Pero podría haber sido nombrado Runner, Launcheretc. y todavía me "sentiría mejor" SmurfLauncherporque no sé qué Launcherhace, pero sé qué SmurfLauncherhace. Se podría argumentar que lo que Smurf.Launcherhace debe ser tan evidente como unSmurf.SmurfLauncher, pero pude ver que `Smurf.Launcher es algún tipo de clase relacionada con la configuración en lugar de una clase que lanza pitufos.

Si hay una manera abierta y cerrada de lidiar con cualquiera de estos, sería genial. Si no, ¿cuáles son algunas prácticas comunes para mitigar su molestia?

Daniel Koverman
fuente
3
¿ Smurf.LauncherLanza pitufos o lanza SmurfJobs? Quizás podría llamarse Smurf.JobLauncher?
Blorgbeard
2
Es un olor a código nombrar un XService de clase, XManager, etc. Esto no significa nada. Es como una Util. Si está hojeando los nombres de archivo, podría haber algo allí o faltar desde allí. No hay forma de saberlo a menos que mires dentro. Lo cambiaría de nombre de SmurfService a algo completamente diferente.
Daniel Kaplan
1
Realmente SmurfJobejecuta s, o técnicamente los ejecuta para que sean consistentes con el lenguaje de la documentación de Smurf. A la luz de eso y las otras respuestas, voy a cambiar el nombre SmurfServicea SmurfJobRunner. Parece que el número 1 no tiene una mejor resolución agnóstica de lenguaje como esperaba. Puedo ver casos donde ir con SmurfConfigurationsería la decisión correcta, pero en mi caso creo que Configurationes mejor incluso con la molestia de Wartmonger.Configuration.
Daniel Koverman
66
Estoy tratando de comprender por qué tienes una sola clase que se preocupa por configurar tanto a Wartmongers como a Smurfs.
Donal Fellows
¿Por qué hacer Smurf.Configurationy SmurfConfigurationsentirse diferente? Seguramente no es el char extra, ¿verdad? (Reduzca a Configsi la longitud es el problema). ¿ Smurf.ConfigurationTiene algún problema que SmurfConfigurationno tenga ?
Pablo H

Respuestas:

16

Subes algunos buenos puntos.

  1. Con respecto a tener clases duplicadas, puede alias clases en C #. Use por ejemplo using ColorScheme = The.Fully.Qualified.Namespace.Outlook2007ColorScheme;Vea esta publicación en StackOverflow . No ha indicado su lenguaje de programación, pero lo he inferido de lo que ha escrito. Entonces, cuando se trata de dos proyectos diferentes, puede asignarles un alias SmurfConfigurationy WartmongerConfigurationliberar la ambigüedad al consumir ambas clases.

  2. Como un servicio está expuesto a aplicaciones externas, no veo ningún problema en marcar el servicio con el nombre de su aplicación, por lo que en este caso SmurfServicesería válido, ya que realmente desambiguaría grupos de servicios en la aplicación consumidora.

Creo que los espacios de nombres deberían usarse para evitar este estilo de denominación. Hace que sea más difícil asimilar el código y ver al pie de la letra qué es una clase sin leer MyCompanyMyProductMyAreaClassName. El uso de la técnica de alias le permite reducir la ambigüedad donde sea necesario. La única vez que creo que deberías introducir complejidad en tu nomenclatura es, como he señalado en el n. ° 2, cuando las personas consumirán un servicio. Aquí es donde tiene mucho sentido tener este estilo de denominación porque si el consumidor tiene una variedad de servicios, está consumiendo la ambigüedad que podría ser confusa.

Sam
fuente
55
los alias simplemente confunden las cosas. En lugar de Smurf.Service ahora tiene SmurfService = Smurf.Service. Por lo tanto, bien podría haber tenido SmurfService como el nombre de la cosa en primer lugar. Tienen un lugar, pero no para este tema en particular. Sin embargo, es probablemente la mejor respuesta a un problema que no tiene respuesta :)
gbjbaanb
. El C # en mí salió en mi pregunta, pero actualmente estoy lidiando con Java y org.apache.smurfville.wartmonger.configuration. Desafortunadamente, esto descarta los alias. 2 es un punto sólido, así que voy a mantener la marca Smurf para el Servicio.
Daniel Koverman
25

El objetivo de los espacios de nombres es que puede tener clases del mismo nombre de diferentes bibliotecas sin que colisionen. Cuando necesite usar la misma clase con nombre de ambos, debe eliminar la ambigüedad al anteponer uno o ambos con su ámbito de espacio de nombres.

Dicho esto, no es tan malo tener un montón de clases de Pitufo si Pitufo te dice algo específico sobre la clase. Los nombres de las clases deben ser lo suficientemente descriptivos como para brindarle información sobre lo que hace la clase.

      Session
       ^   ^
      /     \
DBSession   HttpSession

Del mismo modo, un DBSessionpodría tomar un DBRequestobjeto que devuelve un DBResponseobjeto. El HttpSessionpoder también opera en HttpRequesty HttpResponseobjetos.

Estas son clases de pitufos con un propósito.

Podrían vivir en el MyCompanyespacio de nombres, pero MyCompanyHttpSessiony MyCompanyDBSessionno le da más información que la que tenía antes. En este caso, suelte el Pitufo y conviértalo en un espacio de nombres.

MyCompany.HttpSession
Dave Rager
fuente
3

Me he encontrado con este mismo punto de confusión antes y generalmente es realmente una cuestión de si incluimos el tipo de cosas como parte de su nombre.

Usted menciona SmurfConfigurationy WartmongerConfigurationcomo posibles tipos de configuraciones. Indicas que eliminaste el adjetivo (su tipo) a su espacio de nombres para que lo que te queda sea solo la vainilla Configuration. Evitaría hacer eso.

Es como decidir que el helado de fresa es solo helado en el espacio de nombres de fresa e igualmente con chocolate, pero lo que sucedió es que te has divorciado del adjetivo que le da su identidad de la cosa misma. No es helado en la categoría de fresas. Es helado de fresa, una especie de helado.

Imaginemos que en su aplicación, importa la Strawberry.IceCreamclase y luego comienza a crear instancias directamente desde IceCream.

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

Esto puede parecer bien, hasta el momento en que terminas importando otra IceCreamclase. Ahora vuelve al problema original de tener que distinguir de alguna manera entre ellos, lo cual es problemático. Lo que siempre quisiste fue:

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

Es mejor dejar espacios de nombres para evitar posibles conflictos entre terceros que podrían representar los mismos conceptos en sus bibliotecas. Sin embargo, cuando un desarrollador crea una biblioteca o proyecto, debe nombrar cada concepto de manera única y usar espacios de nombres como carpetas solo para la organización. A menudo, el nombre de la carpeta se encuentra en el nombre de los conceptos que organiza y está bien.

Mario T. Lanza
fuente
2

Definitivamente es una buena regla general que si tienes un prefijo común en un grupo de clases, entonces probablemente merezcan ir a su propio espacio de nombres. Para lidiar con el problema, cuando necesite usar clases con nombres similares de dos espacios de nombres:

1) Alias ​​los espacios de nombres, aunque lo haría corto y al grano, cualquier abreviatura natural, tal vez incluso solo 1 letra:

using Sm = Smurf;
using W = Wartmonger;

Luego, prefije siempre que se use y nombre las instancias adecuadamente:

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

2) Alias ​​la clase, como se sugiere en otra respuesta.

using SmConf = Smurf.Configuration;

3) Cualquier biblioteca sobre la que tenga control, considere no usar el término 'Configuración'. Utilice el diccionario de sinónimos: por ejemplo, 'Configuración', 'Modelo', 'Parámetros'. De todos modos, podría ser más significativo para el contexto: por ejemplo, si Smurf fuera algún tipo de módulo de análisis numérico que hubiera escrito, tal vez 'Parámetros' sería mejor para su configuración. Use el vocabulario particular asociado con el contexto de un módulo para su ventaja para encontrar nombres únicos que tengan unicidad incluso cuando se mezclan con otros espacios de nombres. Creo que esto podría ser una especie de respuesta a la pregunta OP 2.

4) Refactorice el código para que no tenga que mezclar el uso de la configuración desde dos lugares diferentes. Los detalles de eso dependen de usted.

5) Combina las dos configuraciones en una antes de pasarla a tu clase. Use una clase conf combinada para representar:

struct Conf {
    SmurfConfiguration smurf;
    WartmongerConfiguation wart;
}

Los nombres cortos de las variables miembro ahora están logrando lo mismo que el alias de la clase / espacio de nombres.

Benedicto
fuente
0

Parece extraño que agregar un punto al nombre te moleste.

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

// vs

WartmongerConfiguration configuration = WartmongerConfiguration.new();

Si ambas Smurfy las Wartmongerconfiguraciones se usan juntas en un lugar, pero por separado se usan en varios lugares, entonces el espacio de nombres es definitivamente un buen enfoque.

Tener espacio de nombres dará posibilidad de utilizar nombres "limpias" en código interno, donde con prefijos que terminan usando SmurfConfigurationel interior SmurfService's código interno, que puede llegar a ser molesto cada vez que se abrirá ese código.

Fabio
fuente