Me he encontrado con algún código (C # si es importante) que tiene clases que tienen el mismo nombre, pero difieren en sus espacios de nombres. Todos tienden a representar la misma cosa lógica, pero a menudo son diferentes "vistas" del mismo objeto. Los diferentes espacios de nombres son a veces parte de la misma solución, e incluso el mismo dll.
Tengo mis pensamientos, pero no pude encontrar nada definitivo sobre esta práctica para considerar un uso inteligente de las herramientas disponibles o un patrón para evitar.
Esta pregunta sobre los nombres de los pitufos toca esto, pero desde la otra dirección. La desambiguación de los nombres probablemente requeriría un prefijo arbitrario y omnipresente, que esa pregunta quería eliminar.
¿Cuáles son las pautas en torno a esta práctica?
FooAdapter
,FooViewer
,FooCalculator
, etc, pero ciertamente no es el nombre del mismo. Sin embargo, sin más información sobre las clases específicas de las que está hablando, es difícil dar una respuesta.Employee
como ejemplo. Hay un empleado que es para otros empleados, uno para RRHH y otro para exposición externa. Todos se llaman "empleado" y todos tienen variedades de ayudantes (EmployeeRepository, EmployeeView, etc.). Todos están en el mismo dll, y aunque comparten algunas propiedades comunes (nombre, título), todos difieren (número de teléfono, salario).Employee
varias veces, parece que necesita un modelo con la unión de todos los atributos e incluye un atributotype
odepartment
. De lo contrario, hay una duplicación innecesaria de código.Respuestas:
Intentaré dar una respuesta contra tal uso, después de haber visto y trabajado en esto también en uno de mis proyectos.
Legibilidad de código
En primer lugar, considere que la legibilidad del código es importante y esta práctica es contraria a eso. Alguien lee un fragmento de código y digamos que tiene una función
doSomething(Employee e)
. Esto ya no es legible, porque debido a las 10Employee
clases diferentes que existen en diferentes paquetes, primero tendrá que recurrir a la declaración de importación para averiguar cuál es realmente su entrada.Sin embargo, esta es una vista de alto nivel y, a menudo, tenemos enfrentamientos de nombres aparentemente aleatorios, que a nadie le importan o incluso encuentran, porque el significado se puede derivar del código restante y en qué paquete está. Así que uno podría incluso discutir que, localmente, no hay problema, porque, por supuesto, si ve
Employee
dentro de unhr
paquete, debe saber que estamos hablando de una vista de recursos humanos del empleado.Sin embargo, las cosas se rompen tan pronto como dejas estos paquetes. Una vez que está trabajando en un módulo / paquete / etc. diferente y necesita trabajar con un empleado, ya está sacrificando la legibilidad si no califica completamente su tipo. Además, tener 10
Employee
clases diferentes significa que la finalización automática de su IDE ya no funcionará y tendrá que elegir manualmente el tipo de empleado.Duplicación de código
Debido a que la naturaleza de cada una de estas clases está relacionada entre sí, su código se deteriorará debido a una gran cantidad de duplicaciones. En la mayoría de los casos, tendrá algo como el nombre de un empleado o algún número de identificación, que cada una de las clases tiene que implementar. A pesar de que cada clase agrega su propio tipo de vista, si no comparten los datos subyacentes de los empleados, terminará con enormes cantidades de código inútil, pero costoso.
Complejidad de código
¿Qué puede ser tan complejo que puedas preguntar? Después de todo, cada una de las clases puede mantenerlo tan simple como quiera. Lo que realmente se convierte en un problema es cómo propaga los cambios. En un software razonablemente rico en funciones, puede cambiar los datos de los empleados, y desea reflejar eso en todas partes. Digamos que una mujer se acaba de casar y hay que cambiarle el nombre de
X
aY
debido a eso. Lo suficientemente difícil como para hacer esto bien en todo el lugar, pero aún más difícil cuando tienes todas estas clases distintas. Dependiendo de sus otras opciones de diseño, esto puede significar fácilmente que cada una de las clases tiene que implementar su propio tipo de oyente para recibir notificaciones de cambios, lo que básicamente se traduce en un factor que se aplica a la cantidad de clases con las que tiene que lidiar. . Y más duplicación de código, por supuesto, y menos legibilidad de código ... Factores como este pueden ser ignorables en el análisis de complejidad, pero seguramente son molestos cuando se aplican al tamaño de su base de código.Código de comunicación
Además de los problemas anteriores con la complejidad del código, que también están relacionados con las opciones de diseño, también está reduciendo su claridad de diseño de nivel superior y pierde la capacidad de comunicarse adecuadamente con expertos en dominios. Cuando habla de arquitectura, diseños o requisitos, ya no es libre de hacer declaraciones simples como
given an employee, you can do ...
. Un desarrollador ya no sabrá lo queemployee
realmente significa en ese momento. Aunque un experto en dominios lo sabrá, por supuesto. Todos lo hacemos. algo así como. Pero en términos del software ya no es tan fácil comunicarse.¿Cómo deshacerse del problema?
Después de darse cuenta de esto y si su equipo está de acuerdo en que es un problema lo suficientemente grande como para abordarlo, entonces tendrá que encontrar una manera de lidiar con eso. Por lo general, no puede pedirle a su gerente que le dé a todo el equipo una semana libre para que puedan sacar la basura. Entonces, en esencia, tendrá que encontrar una manera de eliminar parcialmente estas clases, una a la vez. La parte más importante de esto es decidir, con todo el equipo, qué
Employee
es realmente. No , no integrar todos los atributos individuales en un dios-empleado. Piense más en un empleado principal y, lo más importante, decida dóndeEmployee
residirá esa clase.Si realiza revisiones de código, es particularmente fácil asegurarse de que el problema al menos no crezca más, es decir, detenga a todos en su camino cuando quieran agregar otro
Employee
nuevamente. También tenga cuidado de que los nuevos subsistemas se adhieran a lo acordadoEmployee
y no se les permita acceder a las versiones anteriores.Dependiendo de su lenguaje de programación, es posible que también desee marcar las clases que eventualmente se eliminarán con algo como
@Deprecated
ayudar a su equipo a darse cuenta de inmediato de que están trabajando con algo que tendrá que ser cambiado.En cuanto a deshacerse de las clases obsoletas de los empleados, puede decidir para cada caso individual cómo se elimina mejor, o simplemente acordar un patrón común. Puede pegar el nombre de la clase y envolverlo con el empleado real, puede usar patrones (viene a la mente decorador o adaptador), o, o o.
En pocas palabras: esta "práctica" es técnicamente sólida, pero está llena de costos ocultos que solo ocurrirán más adelante. Si bien es posible que no pueda deshacerse inmediatamente del problema, puede comenzar de inmediato con contener sus efectos nocivos.
fuente
El Scala Collection Framework es un buen ejemplo de esto. Hay colecciones mutables e inmutables, así como colecciones seriales y paralelas (y en el futuro tal vez también distribuidas). Entonces, hay, por ejemplo, cuatro
Map
rasgos:más tres
ParMap
s:Aún más interesante:
Entonces,
ParMap
seParMap
extiende se extiendeMap
yMap
seMap
extiende se extiendeMap
.Pero, seamos sinceros: ¿qué otra cosa sería que llamarlos? Esto tiene mucho sentido. ¡Para eso están los espacios de nombres!
fuente
Esta es una pregunta realmente interesante donde las dos respuestas esencialmente opuestas son correctas. Aquí hay un ejemplo del mundo real de esta discusión que estamos teniendo sobre un proyecto mío.
Creo que hasta ahora hay dos consideraciones muy importantes que te harían querer ir en una dirección u otra, basándose en las dos respuestas de @Jorg y @Frank:
hr.Employee
pero al mismo tiempo necesita ver los permisos a través desecurity.Employee
, se volverá molesto muy rápido.Map
clases implementan la misma interfaz o son subclases entre sí. En este caso, podría decirse que la ambigüedad o "confusión" puede considerarse buena, porque el usuario puede tratar correctamente todas las implementaciones de la clase o interfaz ... que es el punto de las interfaces y subclases.fuente