¿Es la capacidad de descubrimiento para los desarrolladores un problema cuando se utilizan principios SOLIDOS?

10

Hago aplicaciones de línea de negocios donde todos los demás desarrolladores están acostumbrados a hacer aplicaciones CRUD básicas o se centran únicamente en hacer interfaces bonitas / funcionales y obtengo mucho de lo siguiente.

"Con la forma en que solíamos hacerlo, el Empleado tendría todas las cosas que podrías hacer con un empleado". Y fue verdad. Esa "Clase" tenía miles de líneas de código y cualquier cosa que pudieras hacer con un empleado estaba allí. O, peor aún, había una tabla de datos de los empleados y cada desarrollador descubrió cómo hacer lo que querían hacer en el controlador de eventos.

Todas las cosas malas de ese enfoque eran ciertas, pero al menos el desarrollador que usaba al empleado podría, sin consultar otros documentos, descubrir cómo inscribir al empleado en un plan de salud, dar un aumento de sueldo, despedir, contratar, transferir, etc. para Manager y todas las demás ideas principales. O, si usaran al empleado otras tablas de datos necesarias, simplemente podrían hacer lo que quisieran.

Sí, había mucho código duplicado. Sí, era un código muy frágil. Sí, probarlo fue mucho más difícil de lo necesario. Sí, el cambio de funcionalidad era inductor de miedo y Copy Paste era algo natural debido al enfoque.

Pero al menos podían descubrir lo que estaba disponible creando una clase o podían hacer lo que tenían que hacer sin tener que entender la diferencia entre interfaces, clases abstractas, clases concretas, etc. Y no tenían que buscar nada más que Los métodos devueltos por Intellisense o conocer las tablas donde residían los datos.

Busqué en google / binged e incluso yahoo! D pero no encontré ningún reconocimiento de este problema.

Entonces tal vez no haya un problema y solo me falta algo. Me he estrujado el cerebro tratando de encontrar una solución en la que los desarrolladores que no funcionan con el comportamiento / diseño real puedan descubrir fácilmente cómo hacer algo sin tener que hacer referencia a ningún documento externo o escanear los nombres de las clases en los diversos componentes / proyectos para encontrar el que parece que funcionará.

Lo único que he podido encontrar es tener estos, por falta de un nombre mejor, "Tabla de clase de contenido" que no hace nada más que devuelva las clases reales (y realmente la mayoría de ellas son interfaces pero no saber la diferencia o incluso preocuparse) que otros desarrolladores pueden usar para realizar las tareas reales deseadas. Todavía terminan con clases realmente grandes, pero casi no hay comportamiento en ellas.

¿Existe una mejor manera que no requiera un conocimiento íntimo del nivel medio donde se lleva a cabo la implementación real de SOLID?

Básicamente, lo que pregunto es si hay una manera de permitir que los desarrolladores de tipo CRUD sigan siendo desarrolladores CRUD en un sistema muy complejo

ElGringoGrande
fuente
8
Tal vez sus desarrolladores no dependan completamente de IntelliSense (o equivalente) para la capacidad de detección. Nombra bien las cosas. Documente bien las cosas. Este es un problema de comunicación, no un problema técnico.
Rein Henrichs
Hmmm Un poco Cuanto más lo pienso, más creo que hay una oportunidad de negocio al acecho.
ElGringoGrande
2
@ReinHenrichs: si el desarrollador necesita leer la documentación, les llevará tiempo y la productividad se verá afectada. Por lo tanto, es importante que descubran rápidamente lo que necesitan para una tarea determinada. No tiene que depender de intellisense, pero es mejor que sea fácil. Hacerlo fácil es ciertamente un problema técnico.
Jan Hudec
@ JanHudec: No, no es un problema técnico sino organizativo el uso de convenciones adecuadas para nombrar, diseñar y espacios en blanco. Sin las convenciones de nombres, no sabría qué buscar. Sin un nombre consistente, no lo encontraría todo y / o le sería mucho más difícil rastrear todo. Sin un diseño consistente y el uso de espacios en blanco (especialmente en las declaraciones de tipo) no encontraría la mitad de las instancias que necesita. Sí, una mejor expresión regular podría ayudar, pero no quiero aprender expresiones regulares solo para encontrar dónde se usa una clase.
Marjan Venema
@ JanHudec No es un "si" sino un "cuando". Los desarrolladores deberán leer la documentación. Si desea que "descubran rápidamente lo que necesitan para una tarea determinada", su mejor opción es concentrarse en hacer efectiva la documentación. No intente resolver un problema de personas (como la comunicación) con una solución técnica. Eso. Hace. No. Trabajo.
Rein Henrichs

Respuestas:

4

Parece que lo que ha descrito (es decir, la clase de empleado con TODO el código posible que podría hacer con un empleado) es un patrón extremadamente común que personalmente he visto bastante. Parte de ese código lo escribí yo mismo antes de que supiera algo mejor.

Lo que comienza como una clase que se supone que representa una entidad única con un conjunto manejable de métodos, se transforma en algo que es una pesadilla para mantener porque cada característica y cada versión siguen agregando más y más a la misma clase. Esto va en contra de los principios SÓLIDOS que dicen que debe escribir una clase una vez y resistir el impulso de modificarla una y otra vez.

Hace un tiempo (antes de descubrir patrones de diseño o SOLID según lo promovido por otros), decidí que mi próximo proyecto cambiara un poco las cosas. Estaba trabajando en un servidor que servía como interfaz entre dos plataformas muy grandes. Al principio, solo se requería la sincronización de la configuración, pero pude ver que este sería un lugar lógico para muchas otras características.

Entonces, en lugar de escribir una clase que exponga métodos, escribí clases que representaban métodos (resultó ser el patrón "Comando" de GoF). En lugar de hacer el trabajo para el cliente, todas mis clases de aplicaciones principales se convirtieron en titulares de estado persistentes y se hicieron mucho más cortas en longitud. Cada vez que tenía que agregar un nuevo método de interfaz al servicio en sí, simplemente creaba una nueva clase que tenía el método Execute () que iniciaba todo. Si varios comandos tenían algo en común, derivaban de la clase base común. Finalmente, la cosa tenía más de 70 clases de comando diferentes y todo el proyecto aún era muy manejable y en realidad fue un placer trabajar en él.

Su "clase TOC" no está muy lejos de lo que hice. Tenía una fábrica abstracta (GoF) que se encargaba de crear instancias de comandos. Dentro de la clase de fábrica, escondí la mayoría de los detalles detrás de la clase base y las macros de estilo ATL, por lo que cuando un programador tuvo que agregar o buscar una solicitud, entraron y todo lo que vieron fue:

BEGIN_COMMAND_MAP()
    COMMAND_ENTRY( CChangeDeviceState )
    COMMAND_ENTRY( CSetConfiguration )
    ....
END_COMMAND_MAP()

Alternativamente (o además de), puede colocar todas sus clases de comandos reales en un espacio de nombres separado para que cuando las personas estén codificando y necesiten ejecutar algo, simplemente escriban el nombre del espacio de nombres e Intellisense enumera todos los comandos que ha definido. Luego, cada comando incluye todos los métodos get get / set que determinan exactamente qué parámetros de entrada y salida.

También puede explorar el uso del patrón Fachada (GoF). En lugar de exponer más de 1000 clases a sus ingenieros de CRUD. Escóndelos todos detrás de una sola clase que expone solo lo que se necesita. Todavía me apegaría a que cada "acción" sea su propia clase, pero su clase Fachada puede tener métodos que instanciarían cada una de sus acciones y nuevamente, con Intellisense verían de inmediato lo que está disponible. O haga que Facade tenga métodos reales, pero internamente hágales instanciar comandos, agrúpelos y espere respuestas. Luego regrese como si se hiciera una llamada al método regular.

(*) No quería entrar en demasiados detalles, pero en realidad tenía el conjunto de clases "Command" y "CommandHandler". Esto separó la responsabilidad de administrar / poner en cola / serializar los parámetros de entrada / salida de las clases que realmente "manejaban" esos comandos.

DXM
fuente
Si. Hoy me di cuenta de que hemos terminado con un patrón de Fachada mal implementado. No creo que haya nada más que hacer aparte de romper la gran fachada en otras más pequeñas. Me gusta tu idea de incorporar algunas clases de comando detrás de escena.
ElGringoGrande
0

Puede ser un problema Particularmente si nombras mal las cosas. Pero hay una serie de soluciones sin recurrir a clases complejas. Diablos, una clase con demasiados métodos puede ser igualmente difícil de navegar con Intellisense.

Intente usar espacios de nombres (C #) o paquetes (Java), o cualquier concepto similar que tenga su lenguaje (me referiré a todos como espacios de nombres), para simplificar el problema.

Comience con el nombre de su empresa. Eso limita Intellisense a solo espacios de nombres escritos por ustedes mismos. Luego, si tiene varias aplicaciones, use la segunda parte del espacio de nombres para dividirlas. Incluya un espacio de nombres Core, para cosas que existen en todas las aplicaciones. A continuación, divida las cosas en tipos de funcionalidad. Y así.

Si haces esto bien, terminarás con artículos muy reconocibles.

Para tomar su ejemplo, si quiero la validación del usuario, escribo "MyCo". y me da una lista de espacios de nombres de aplicaciones. Sé que la base de datos de usuario se usa en todas nuestras aplicaciones, así que escribo "Core". entonces obtengo una lista de tipos de funcionalidad. Una de ellas es la "Validación", por lo que parece una opción obvia. Y allí, dentro de Validación, se encuentra "UserValidator" con toda su funcionalidad.

Resulta que, para cosas que uso mucho, recordaré rápidamente los nombres, o al menos las convenciones. Debido a que realizo muchos cambios en las reglas de validación, sabré que todas mis clases de validación se llaman FooValidator, donde Foo es el nombre de la tabla. Así que en realidad no necesitaré atravesar los espacios de nombres. Simplemente escribiré UserValidator y dejaré que el IDE haga el resto del trabajo.

Pero para cosas que no recuerdo, todavía es bastante fácil encontrarlas. Y cuando lo hago, puedo eliminar el prefijo del espacio de nombres.

pdr
fuente
Es, en parte, un mal nombre por mí. Los nombres no son horribles, pero a menudo pienso en un mejor mes después del hecho. Pero incluso con buenos nombres si tiene miles de clases, los nombres no siempre son fáciles de descubrir. Estoy tratando de superar esto. Solo pensé que podría haber una forma conocida.
ElGringoGrande
0

Como los refieres básicamente como desarrolladores "CRUD", asumiremos que no crees que sean muy buenos. No sabemos si esto significa que tampoco entienden su dominio comercial. Si entienden el dominio, las clases deberían tener sentido para ellos. Sabiendo que se han construido varias clases, primero deberían echar un vistazo, preguntar en segundo lugar, considerar construir desde cero como una tercera opción.

En cuanto a saber cómo saber automáticamente cómo usar / reutilizar una clase con solo mirarla, no debería esperarse la primera vez. Tendrá que documentar y posiblemente proporcionar una explicación adicional, ya sea a través de la capacitación o posiblemente durante la revisión del código.

Muchos proyectos de API y de código abierto proporcionan documentación, ejemplos de código y otras explicaciones. Es posible que el suyo no sea tan fácil de usar, pero no hay forma de evitarlo. Enséñales bien.

JeffO
fuente
No. CRUD no significa que no sean buenos. Son desarrolladores que siempre se han ocupado de las aplicaciones de datos básicos. CRUD = crear, leer, actualizar y eliminar. No veo cómo eso los convierte en malos programadores.
ElGringoGrande
En argot inglés británico, "crud" == "mierda".
Michael Shaw