¿Por qué necesitamos tantas clases de patrones de diseño?

209

Soy desarrollador junior entre personas mayores y estoy luchando mucho para comprender su pensamiento y razonamiento.

Estoy leyendo Diseño controlado por dominio (DDD) y no puedo entender por qué necesitamos crear tantas clases. Si seguimos ese método de diseño de software, terminamos con 20-30 clases que pueden reemplazarse como máximo con dos archivos y 3-4 funciones. Sí, esto podría ser complicado, pero es mucho más fácil de mantener y leer.

Cada vez que quiero ver qué hace algún tipo EntityTransformationServiceImpl, necesito seguir muchas clases, interfaces, sus llamadas a funciones, constructores, su creación, etc.

Matemática simple:

  • 60 líneas de código ficticio frente a 10 clases X 10 (supongamos que tenemos lógicas totalmente diferentes) = 600 líneas de código desordenado frente a 100 clases + algunas más para envolverlas y administrarlas; No olvides agregar la inyección de dependencia.
  • Lectura de 600 líneas de código desordenado = un día
  • 100 clases = una semana, todavía olvida cuál hace qué, cuándo

Todos dicen que es fácil de mantener, pero ¿para qué? Cada vez que agrega una nueva funcionalidad, agrega cinco clases más con fábricas, entidades, servicios y valores. Siento que este tipo de código se mueve mucho más lento que el código desordenado.

Digamos que si escribe un código desordenado de 50K LOC en un mes, la cosa DDD requiere muchas revisiones y cambios (no me importan las pruebas en ambos casos). Una simple adición puede llevar una semana, si no más.

En un año, escribe un montón de código desordenado e incluso puede reescribirlo varias veces, pero con el estilo DDD, aún no tiene suficientes funciones para competir con el código desordenado.

Por favor explique. ¿Por qué necesitamos este estilo DDD y muchos patrones?

UPD 1 : Recibí muchas respuestas geniales, ¿pueden agregar algún comentario o editar su respuesta con el enlace para leer la lista (no estoy seguro de dónde comenzar, DDD, Patrones de diseño, UML, Código completo, Refactorización, Pragmática, etc.). .. tantos buenos libros), por supuesto con secuencia, para que yo también pueda comenzar a entender y llegar a ser mayor como algunos de ustedes.

usuario1318496
fuente
81
Creo que hay una buena pregunta aquí, pero se esconde detrás de la hipérbole y la frustración. @ user1318496, podría beneficiarse al reformular un poco su pregunta.
MetaFight
48
A riesgo de pisar los pies, porque su idioma apesta. No tome eso por más de lo que es: un lenguaje malicioso es a menudo la elección técnica correcta por una variedad de razones, pero eso no lo hace no malicioso. En cuanto a su pregunta real, la corrección es más importante que la legibilidad. O para decirlo de manera ligeramente diferente: la legibilidad importa en la medida en que permite razonar sobre la corrección. Entonces, ¿cuál es más fácil de probar, tus 100 clases o tu clase de dios monolítico? Estoy apostando 100 clases simples.
Jared Smith
87
"Sí, esto podría ser complicado, pero es mucho más fácil de mantener y leer". Si es complicado, ¿cómo puede ser legible y mantenible?
Polygnome
37
@Polygnome: estaba a punto de escribir exactamente el mismo comentario. Otro comentario característico de los desarrolladores junior es "Siento que este tipo de código se mueve mucho más lento que el código desordenado". ¡No es bueno correr tan rápido como puedas si pasas la mitad de tu tiempo corriendo contra las paredes! Ir lento es ir suave, ir suave es ir rápido.
Eric Lippert
40
No, a menos que estés haciendo Java. Cuando todo lo que tienes es Java, todo parece una clase.
hobbs

Respuestas:

336

Este es un problema de optimización

Un buen ingeniero entiende que un problema de optimización no tiene sentido sin un objetivo. No puedes simplemente optimizar, tienes que optimizar para algo. Por ejemplo, las opciones del compilador incluyen la optimización de la velocidad y la optimización del tamaño del código; Estos son a veces objetivos opuestos.

Me gusta decirle a mi esposa que mi escritorio está optimizado para agregar anuncios. Es solo una pila, y es muy fácil agregar cosas. Mi esposa preferiría que yo optimizara la recuperación, es decir, organizara mis cosas un poco para poder encontrar cosas. Esto hace que sea más difícil, por supuesto, agregar.

El software es de la misma manera. Sin duda, puede optimizar para la creación de productos: generar una tonelada de código monolítico lo más rápido posible, sin preocuparse por organizarlo. Como ya has notado, esto puede ser muy, muy rápido. La alternativa es optimizar el mantenimiento: hacer que la creación sea un poco más difícil, pero hacer que las modificaciones sean más fáciles o menos riesgosas. Ese es el propósito del código estructurado.

Sugeriría que un producto de software exitoso solo se creará una vez, pero se modificará muchas, muchas veces. Los ingenieros experimentados han visto cómo las bases de código no estructuradas cobran vida propia y se convierten en productos, creciendo en tamaño y complejidad, hasta que incluso los pequeños cambios son muy difíciles de realizar sin introducir un gran riesgo. Si el código fuera estructurado, el riesgo puede ser contenido. Por eso nos vamos a todos estos problemas.

La complejidad proviene de las relaciones, no de los elementos.

Noto en su análisis que está buscando cantidades: cantidad de código, número de clases, etc. Si bien estos son algo interesantes, el impacto real proviene de las relaciones entre elementos, que explotan combinatoriamente. Por ejemplo, si tiene 10 funciones y no tiene idea de qué depende, tiene 90 posibles relaciones (dependencias) de las que debe preocuparse: cada una de las diez funciones puede depender de cualquiera de las otras nueve funciones, y 9 x 10 = 90. Es posible que no tenga idea de qué funciones modifican qué variables o cómo se transmiten los datos, por lo que los codificadores tienen un montón de cosas de qué preocuparse al resolver cualquier problema en particular. Por el contrario, si tiene 30 clases pero están organizadas de manera inteligente, pueden tener tan solo 29 relaciones, por ejemplo, si están en capas o dispuestas en una pila.

¿Cómo afecta esto el rendimiento de su equipo? Bueno, hay menos dependencias, el problema es mucho más manejable; los programadores no tienen que hacer malabarismos con un millón de cosas en su cabeza cada vez que hacen un cambio. Por lo tanto, minimizar las dependencias puede ser un gran impulso para su capacidad de razonar sobre un problema de manera competente. Es por eso que dividimos las cosas en clases o módulos, y las variables de alcance lo más estrictamente posible, y utilizamos principios SOLIDOS .

John Wu
fuente
103
Sin embargo, me gustaría señalar que un exceso de clases e indirección NO ayuda a comprender el mantenimiento NOR. Y tampoco fluye un control complicado (también conocido como infierno de devolución de llamada).
Matthieu M.
99
@ JohnWu, esta explicación es la mejor y más fácil de entender que he leído.
Adriano Repetti
13
Bien escrito, pero ¿puede faltar por qué es importante "creado una vez pero modificado muchas, muchas veces"? (Si todo el código está incluido EntityTransformationServiceImpl, se ve obligado a aprender cómo funciona todo antes de poder solucionarlo, pero si, por ejemplo, algo está mal con el formato y una Formatterclase lo maneja, solo necesita aprender cómo funciona esa parte . Además leer su propio código después de ~ 3 meses es como leer el código de un extraño.) Siento que la mayoría de nosotros inconscientemente pensamos en esto, pero eso podría deberse a la experiencia. No estoy 100% seguro de esto.
R. Schmitz
17
Iría por el 10 × 10 = 100 completo para el combinatorio: esas funciones bien podrían ser recursivas, y en un código particularmente pobre, no necesariamente necesariamente así.
KRyan
32
"La alternativa es optimizar el mantenimiento: hacer que la creación sea un poco más difícil, pero hacer que las modificaciones sean más fáciles o menos riesgosas. Ese es el propósito del código estructurado". Estoy en desacuerdo con la noción implícita de que más clases = más mantenibilidad. En particular, la lógica de dispersión en muchas clases a menudo hace que sea difícil encontrar los conceptos lógicos generales en el código (especialmente sin un ojo muy intencional para garantizar que los conceptos sean muy visibles), lo que degrada enormemente la capacidad de mantenimiento.
jpmc26
67

Bueno, en primer lugar, la legibilidad y la facilidad de mantenimiento suelen estar en el ojo del espectador.

Lo que es legible para usted puede no serlo para su vecino.

La mantenibilidad a menudo se reduce a la capacidad de descubrimiento (con qué facilidad se descubre un comportamiento o concepto en la base de código) y la capacidad de descubrimiento es otra cosa subjetiva.

DDD

Una de las formas en que DDD ayuda a los equipos de desarrolladores es sugiriendo una forma específica (pero aún subjetiva) de organizar los conceptos y comportamientos de su código. Esta convención hace que sea más fácil descubrir cosas y, por lo tanto, más fácil de mantener la aplicación.

  • Los conceptos de dominio están codificados como entidades y agregados
  • El comportamiento del dominio reside en entidades o servicios de dominio
  • La coherencia está garantizada por las raíces agregadas
  • Las preocupaciones de persistencia son manejadas por los repositorios

Esta disposición no es objetivamente más fácil de mantener. Es, sin embargo, mensurable más fácil de mantener cuando todo el mundo entiende que están operando en un contexto DDD.

Clases

Las clases ayudan con el mantenimiento, la legibilidad, la capacidad de descubrimiento, etc. porque son una convención bien conocida .

En la configuración orientada a objetos, las clases se usan generalmente para agrupar comportamientos estrechamente relacionados y encapsular el estado que debe controlarse cuidadosamente.

Sé que suena muy abstracto, pero puedes pensarlo de esta manera:

Con las clases, no necesariamente necesita saber cómo funciona el código en ellas. Solo necesita saber de qué es responsable la clase.

Las clases le permiten razonar sobre su aplicación en términos de interacciones entre componentes bien definidos .

Esto reduce la carga cognitiva al razonar sobre cómo funciona su aplicación. En lugar de tener que recordar lo que logran 600 líneas de código , puede pensar en cómo interactúan 30 componentes .

Y, teniendo en cuenta que esos 30 componentes probablemente abarcan 3 capas de su aplicación, probablemente solo tenga que razonar aproximadamente 10 componentes a la vez.

Eso parece bastante manejable.

Resumen

Esencialmente, lo que estás viendo hacer a los desarrolladores senior es esto:

Están desglosando la aplicación en fácil de razonar sobre las clases.

Luego los organizan en capas fáciles de razonar .

Lo están haciendo porque saben que, a medida que la aplicación crece, cada vez es más difícil razonar sobre ello en su conjunto. Desglosarlo en capas y clases significa que nunca tienen que razonar sobre la aplicación completa. Solo necesitan razonar sobre un pequeño subconjunto.

MetaFight
fuente
55
Además las clases más pequeñas son más fáciles de reemplazar / refactorizar.
Zalomon
12
La sobreingeniería no proporciona un código más fácil de mantener o comprensible, todo lo contrario, a pesar de lo que usted afirma. ¿Quién necesita un AddressServiceRepositoryProxyInjectorResolvercuando puedes resolver el problema con más elegancia? Los patrones de diseño en aras de los patrones de diseño solo conducen a una complejidad y verbosidad innecesarias.
vikingsteve
27
Sí, la ingeniería excesiva es mala. Así está matando cachorros. Nadie aquí está abogando por ninguno de los dos. logicallyfallacious.com/tools/lp/Bo/LogicalFallacies/169/…
MetaFight
55
Además, la "elegancia" en el contexto de la ingeniería de software es a menudo una palabra de comadreja. en.wikipedia.org/wiki/Weasel_word
MetaFight
11
Lo mismo podría decirse de cualquier enfoque para organizar el código. Todo depende de que el equipo de mantenimiento comprenda por qué el código está organizado tal como está. Ese es el punto de usar convenciones bien establecidas y entendidas.
MetaFight
29

Por favor explícame, ¿por qué necesitamos este estilo DDD, muchos patrones?

Primero, una nota: la parte importante de DDD no son los patrones , sino la alineación del esfuerzo de desarrollo con el negocio. Greg Young comentó que los capítulos del libro azul están en el orden incorrecto .

Pero a su pregunta específica: tiende a haber muchas más clases de las que cabría esperar, (a) porque se está haciendo un esfuerzo para distinguir el comportamiento del dominio de la tubería y (b) porque se está haciendo un esfuerzo adicional para garantizar que los conceptos en el modelo de dominio se expresan explícitamente.

Sin rodeos, si tiene dos conceptos diferentes en el dominio, entonces deben ser distintos en el modelo, incluso si comparten la misma representación de memoria .

En efecto, está creando un lenguaje específico de dominio que describe su modelo en el idioma de la empresa, de modo que un experto en dominios debería poder verlo y detectar errores.

Además, observa que se presta un poco más de atención a la separación de preocupaciones; y la noción de aislar a los consumidores de alguna capacidad de los detalles de implementación. Ver DL Parnas . Los límites claros le permiten cambiar o ampliar la implementación sin que los efectos se extiendan por toda su solución.

La motivación aquí: para una aplicación que es parte de la competencia central de una empresa (es decir, un lugar donde obtiene una ventaja competitiva), querrá poder reemplazar de manera fácil y económica un comportamiento de dominio con una mejor variación. En efecto, tiene partes del programa que desea evolucionar rápidamente (cómo evoluciona el estado con el tiempo) y otras partes que desea cambiar lentamente (cómo se almacena el estado); Las capas adicionales de abstracción ayudan a evitar el acoplamiento inadvertido entre sí.

Para ser justos: algunos de ellos también son daños cerebrales orientados a objetos. Los patrones descritos originalmente por Evans se basan en proyectos Java en los que participó hace más de 15 años; el estado y el comportamiento están estrechamente vinculados en ese estilo, lo que conduce a complicaciones que quizás prefieras evitar; ver Percepción y acción de Stuart Halloway, o Código de línea de John Carmack.

No importa en qué idioma trabaje, la programación en un estilo funcional proporciona beneficios. Debe hacerlo siempre que sea conveniente, y debe pensar detenidamente sobre la decisión cuando no sea conveniente. Carmack, 2012

VoiceOfUnreason
fuente
2
Iba a agregar mi propia respuesta hasta que leyera esto. Destacaría el primer párrafo, que el objetivo es modelar conceptos de negocio en software para alinear el software con los requisitos de negocio. Para ser justos, el analista que dirige el proyecto también debe expresar la cantidad de tiempo del conductor para la entrega, y la calidad o integridad del código / prueba debe ajustarse en consecuencia.
Centinela
1
John Carmack es un gran ejemplo de IMO, ya que es conocido por escribir código que es limpio y fácil de entender, a la vez que tiene un buen rendimiento. Esto es especialmente visible a medida que realiza un seguimiento de su código con tecnologías avanzadas: con mejores CPU y memoria, puede ver muchas cosas empujadas de "esto debe ser realmente conciso" a "esto debe ser realmente claro / aislado / ... ". Uno de los programadores más pragmáticos que conozco :)
Luaan
Creo que esta es la mejor respuesta aquí. Si bien de ninguna manera estoy vendido en DDD, esta respuesta ciertamente al menos explica lo que realmente es y una motivación real para ello, en lugar de apelar a tópicos comunes que no significan nada.
jpmc26
29

Hay muchos puntos buenos en las otras respuestas, pero creo que fallan o no enfatizan un error conceptual importante que cometes:

Estás comparando el esfuerzo para comprender el programa completo.

Esta no es una tarea realista con la mayoría de los programas. Incluso los programas simples consisten en tanto código que es simplemente imposible administrarlo todo en la cabeza en un momento dado. Su única oportunidad es encontrar la parte de un programa que sea relevante para la tarea en cuestión (corregir un error, implementar una nueva característica) y trabajar con eso.

Si su programa consta de funciones / métodos / clases enormes, esto es casi imposible. Tendrá que comprender cientos de líneas de código solo para decidir si este fragmento de código es relevante para su problema. Con las estimaciones que dio, es fácil pasar una semana solo para encontrar el código en el que necesita trabajar.

Compare eso con una base de código con pequeñas funciones / métodos / clases nombrados y organizados en paquetes / espacios de nombres que hacen obvio dónde encontrar / poner una determinada pieza de lógica. Cuando se hace correctamente en muchos casos, puede saltar directamente al lugar correcto para resolver su problema, o al menos a un lugar desde donde encender su depurador lo llevará al lugar correcto en un par de saltos.

He trabajado en ambos tipos de sistemas. La diferencia puede ser fácilmente dos órdenes de magnitud en rendimiento para tareas comparables y tamaño de sistema comparable.

El efecto que esto tiene en otras actividades:

  • la prueba se vuelve mucho más fácil con unidades más pequeñas
  • menos conflictos de fusión porque las posibilidades de que dos desarrolladores trabajen en el mismo código son menores.
  • menos duplicación porque es más fácil reutilizar piezas (y encontrar las piezas en primer lugar).
Jens Schauder
fuente
19

Porque probar código es más difícil que escribir código

Muchas respuestas han dado un buen razonamiento desde la perspectiva de un desarrollador: que el mantenimiento puede reducirse, a costa de hacer que el código sea más agotador para escribir en primer lugar.

Sin embargo, hay otro aspecto a tener en cuenta: las pruebas solo pueden definirse como su código original.

Si escribe todo en un monolito, la única prueba efectiva que puede escribir es "dadas estas entradas, ¿es correcta la salida?". Esto significa que cualquier error encontrado se encuentra en "algún lugar en ese montón gigante de código".

Por supuesto, puede hacer que un desarrollador se siente con un depurador y encuentre exactamente dónde comenzó el problema y trabaje en una solución. Esto requiere muchos recursos y es un mal uso del tiempo de un desarrollador. Imagine que cualquier error menor que tenga, hace que un desarrollador necesite depurar todo el programa nuevamente.

La solución: muchas pruebas más pequeñas que identifican una falla potencial específica cada una.

Estas pequeñas pruebas (por ejemplo, Pruebas unitarias) tienen la ventaja de verificar un área específica de la base de código y ayudar a encontrar errores dentro de un alcance limitado. Esto no solo acelera la depuración cuando falla una prueba, sino que también significa que si fallan todas sus pruebas pequeñas, puede encontrar más fácilmente la falla en sus pruebas más grandes (es decir, si no está en una función probada específica, debe estar en la interacción entre ellos).

Como debe quedar claro, hacer pruebas más pequeñas significa que su base de código debe dividirse en trozos comprobables más pequeños. La forma de hacerlo, en una gran base de código comercial, a menudo da como resultado un código similar al que está trabajando.

Solo como una nota al margen: esto no quiere decir que las personas no lleven las cosas "demasiado lejos". Pero hay una razón legítima para separar las bases de código en partes más pequeñas / menos conectadas, si se hace con sensatez.

Bilkokuya
fuente
55
Si bien su respuesta aborda solo las pruebas y la capacidad de prueba, ese es el problema más importante que algunas de las otras respuestas ignoraron por completo, por lo que +1.
skomisa
17

Por favor explícame, ¿por qué necesitamos este estilo DDD, muchos patrones?

Muchos (la mayoría ...) de nosotros realmente no los necesitamos . Los teóricos y los programadores muy avanzados y experimentados escriben libros sobre teorías y metodologías como resultado de muchas investigaciones y su profunda experiencia, eso no significa que todo lo que escriben sea aplicable a cada programador en su práctica diaria.

Como desarrollador junior, es bueno leer libros como el que mencionaste para ampliar tus perspectivas y hacerte consciente de ciertos problemas. También evitará que se sienta avergonzado y desconcertado cuando sus colegas superiores usen terminología con la que no esté familiarizado. Si encuentra algo muy difícil y no parece tener sentido o parece útil, no se suicide por eso, simplemente archívelo en la cabeza de que existe tal concepto o enfoque.

En su desarrollo diario, a menos que sea un académico, su trabajo es encontrar soluciones viables y mantenibles. Si las ideas que encuentra en un libro no lo ayudan a lograr ese objetivo, no se preocupe por eso ahora, siempre y cuando su trabajo se considere satisfactorio.

Puede llegar un momento en que descubras que puedes usar algo de lo que lees sobre lo que no "entendiste" al principio, o tal vez no.

Vector
fuente
12
Si bien en un nivel puro esto es correcto, parece que DDD y otros patrones son solo teoría. No lo son Son herramientas importantes para lograr un código legible y mantenible.
Jens Schauder
99
@PeteKirkham, el dilema de los OP es el uso excesivo de patrones de diseño. ¿Realmente necesita un AccountServiceFacadeInjectResolver(ejemplo real que acabo de encontrar en un sistema en el trabajo) - la respuesta es probablemente no.
vikingsteve
44
@vikingsteve OP no es un gurú de la programación que comenta sobre el uso excesivo general de los patrones de diseño. OP es un aprendiz y cree que se usan en exceso en su tienda . Sé que los principiantes habrían pensado lo mismo sobre el código que escribo hoy en día, pero los principiantes tuvieron muchos proyectos personales fallidos porque terminaron siendo demasiado complicados.
R. Schmitz
3
@ R.Schmitz Dicho esto, los principiantes tuvieron muchos proyectos personales fallidos porque intentaron demasiado hacer que las cosas estuvieran bien diseñadas, organizadas, estructuradas, OOP ... Todas estas son herramientas. Deben entenderse y usarse adecuadamente, y casi no se puede culpar al martillo por ser pobre en atornillar. Sorprendentemente, parece que se necesita mucha información y experiencia para comprender esta cosa simple :)
Luaan
3
@Luaan Si ya te importaba un OOP bien diseñado, organizado y estructurado, difícilmente llamaría a ese principiante, pero sí, el uso excesivo es malo. Sin embargo, la pregunta es más sobre cómo OP realmente no entiende qué problemas resuelven esas cosas. Si no conoce la razón, parece que no hay razón, pero en realidad, todavía no la conoce.
R. Schmitz
8

Como su pregunta está cubriendo mucho terreno, con muchos supuestos, destacaré el tema de su pregunta:

¿Por qué necesitamos tantas clases de patrones de diseño?

Nosotros no. No existe una regla generalmente aceptada que diga que debe haber muchas clases en los patrones de diseño.

Hay dos guías clave para decidir dónde colocar el código y cómo cortar sus tareas en diferentes unidades de código:

  • Cohesión: cualquier unidad de código (ya sea un paquete, un archivo, una clase o un método) debe estar unida . Es decir, cualquier método específico debe tener una tarea y hacerla bien. Cualquier clase debe ser responsable de un tema más amplio (sea lo que sea). Queremos alta cohesión.
  • Acoplamiento: dos unidades de código deben depender lo menos posible entre sí, especialmente no debe haber dependencias circulares. Queremos bajo acoplamiento.

¿Por qué deberían ser importantes esos dos?

  • Cohesión: un método que hace muchas cosas (por ejemplo, un script CGI antiguo que hace GUI, lógica, acceso a bases de datos, etc., todo en un largo lío de código) se vuelve difícil de manejar. Al momento de escribir, es tentador simplemente poner su tren de pensamiento en un método largo. Esto funciona, es fácil de presentar y tal, y se puede hacer con él. El problema surge más tarde: después de unos meses, puede olvidar lo que hizo. Una línea de código en la parte superior puede estar a unas pocas pantallas de una línea en la parte inferior; Es fácil olvidar todos los detalles. Cualquier cambio en cualquier parte del método puede romper cualquier cantidad de comportamientos de lo complejo. Será bastante engorroso refactorizar o reutilizar partes del método. Y así.
  • Acoplamiento: cada vez que cambia una unidad de código, puede romper todas las demás unidades que dependen de él. En lenguajes estrictos como Java, puede obtener sugerencias durante el tiempo de compilación (es decir, sobre parámetros, excepciones declaradas, etc.). Pero muchos cambios no están desencadenando tales (es decir, cambios de comportamiento), y otros lenguajes más dinámicos no tienen tales posibilidades. Cuanto más alto sea el acoplamiento, más difícil será cambiar cualquier cosa, y podría detenerse, donde es necesaria una reescritura completa para lograr algún objetivo.

Estos dos aspectos son los "impulsores" básicos para cualquier elección de "dónde colocar qué" en cualquier lenguaje de programación y cualquier paradigma (no solo OO). No todo el mundo los conoce explícitamente, y lleva tiempo, a menudo años, tener una sensación realmente arraigada y automática de cómo estos influyen en el software.

Obviamente, estos dos conceptos no dicen nada acerca de lo que realmente hacerlo . Algunas personas se equivocan demasiado, otras demasiado poco. Algunos lenguajes (mirándote aquí, Java) tienden a favorecer muchas clases debido a la naturaleza extremadamente estática y pedante del lenguaje en sí (esto no es una declaración de valor, pero es lo que es). Esto se vuelve especialmente notable cuando lo compara con lenguajes dinámicos y más expresivos, por ejemplo, Ruby.

Otro aspecto es que algunas personas se suscriben al enfoque ágil de escribir solo código que es necesario en este momento y refactorizar mucho más tarde, cuando sea necesario. En este estilo de desarrollo, no crearía una interfacecuando solo tiene una clase de implementación. Simplemente implementaría la clase concreta. Si, más tarde, necesita una segunda clase, refactorizaría.

Algunas personas simplemente no trabajan de esa manera. Crean interfaces (o, más generalmente, clases base abstractas) para cualquier cosa que alguna vez pueda usarse de manera más general; Esto lleva a una explosión de clase rápidamente.

Una vez más, hay argumentos a favor y en contra, y no importa cuál yo o usted prefiera. En su vida como desarrollador de software, se encontrará con todos los extremos, desde largos métodos de espagueti, pasando por diseños de clase ilustrados y lo suficientemente grandes, hasta esquemas de clase increíblemente desarrollados que están muy diseñados. A medida que tenga más experiencia, crecerá más en roles "arquitectónicos", y puede comenzar a influir en esto en la dirección que desee. Encontrarás un medio dorado para ti, y aún encontrarás que muchas personas estarán en desacuerdo contigo, hagas lo que hagas.

Por lo tanto, mantener una mente abierta es lo más importante aquí, y ese sería mi consejo principal para usted, ya que parece que le duele mucho el tema, a juzgar por el resto de su pregunta ...

AnoE
fuente
7

Los codificadores experimentados han aprendido:

  • Porque esos pequeños programas y clases comienzan a crecer, especialmente los exitosos. Que los patrones simples que funcionaron a un nivel simple no escalan.
  • Debido a que puede parecer oneroso tener que agregar / cambiar varios artefactos por cada adición / cambio, pero usted sabe qué agregar y es fácil hacerlo. 3 minutos de escritura supera 3 horas de codificación inteligente.
  • Muchas clases pequeñas no son "desordenadas" solo porque no entiendes por qué los gastos generales son realmente una buena idea
  • Sin el conocimiento de dominio agregado, el código 'obvio para mí' es a menudo misterioso para mis compañeros de equipo ... más el futuro para mí.
  • El conocimiento tribal puede hacer que los proyectos sean increíblemente difíciles de agregar a los miembros del equipo de manera fácil y difícil para que sean productivos rápidamente.
  • Nombrar es uno de los dos problemas difíciles en la computación que aún es cierto y muchas clases y métodos son a menudo un ejercicio intenso de nomenclatura que muchos consideran un gran beneficio.
Michael Durrant
fuente
55
¿Pero es necesaria la sobrecarga? En muchos casos que veo, los patrones de diseño se usan en exceso. El resultado de la sobrecomplejidad es una mayor dificultad para comprender, mantener, probar y depurar el código. Cuando tiene 12 clases y 4 módulos Maven alrededor de una clase de servicio simple (un ejemplo real que acabo de ver), rápidamente se vuelve menos manejable de lo que podría pensar.
vikingsteve
44
@vikingsteve Sigues refiriéndote a un solo ejemplo de una implementación defectuosa con la esperanza de que demuestre que el código estructurado, en general, es una mala idea. Eso simplemente no sigue.
MetaFight
2
@MetaFight OP no está hablando del código de estructura. Está hablando de lo que ve, demasiadas abstracciones. Sostengo que si tienes demasiadas abstracciones, rápidamente obtienes un código muy desestructurado y muchas piezas casi idénticas, simplemente porque las personas no pueden lidiar con la cantidad de cosas con las que tienen que lidiar.
Más claro
44
@Clearer Estoy bastante seguro de que todos aquí están de acuerdo en que la hipotética aplicación incorrecta del código estructurado es algo malo. El OP dice que son Junior. Es por eso que la gente asume que él / ella no está familiarizado con los beneficios del código estructurado y los reitera.
MetaFight
2

Las respuestas hasta ahora, todas son buenas, habiendo comenzado con la suposición razonable de que al autor de la pregunta le falta algo, lo que también reconoce. También es posible que el autor de la pregunta tenga razón, y vale la pena discutir cómo puede surgir esta situación.

La experiencia y la práctica son poderosas, y si los adultos mayores adquirieron su experiencia en proyectos grandes y complejos donde la única forma de mantener las cosas bajo control es con muchos EntityTransformationServiceImpl, entonces se vuelven rápidos y cómodos con patrones de diseño y una estrecha adhesión al DDD. Serían mucho menos efectivos utilizando un enfoque liviano, incluso para programas pequeños. Como extraño, debes adaptarte y será una gran experiencia de aprendizaje.

Sin embargo, mientras se adapta, debe tomarlo como una lección en el equilibrio entre aprender un enfoque único en profundidad, hasta el punto de que puede hacer que funcione en cualquier lugar, en lugar de mantenerse versátil y saber qué herramientas están disponibles sin ser necesariamente un experto en ninguna de ellas. Hay ventajas para ambos y ambos son necesarios en el mundo.

Josh Rumbut
fuente
-4

Hacer más clases y funciones según el uso será un gran enfoque para resolver problemas de una manera específica que ayudará en el futuro a resolver cualquier problema.

Varias clases ayudan a identificarse como su trabajo básico y se puede llamar a cualquier clase en cualquier momento.

Sin embargo, si tiene muchas clases y funciones por su nombre getable, es fácil llamarlas y administrarlas. Esto se llama un código limpio.

Sanjeev Chauhan
fuente
99
Lo siento, pero que estas diciendo?
Deduplicador
@Deduplicator tomemos un ejemplo en java si diseñamos usamos hilos y clases jframes para su herencia. De una sola clase no podemos usar algunas obras de Java para el diseño, por lo que necesitamos hacer más clases
Sanjeev Chauhan
2
Esta respuesta debe presentar la (s) idea (s) que pretende presentar en un inglés más claro. Parece que la idea central en la respuesta es que las clases más pequeñas, cada una con una funcionalidad bien definida, es una buena idea, pero la terrible gramática hace que sea casi imposible de entender. Además, por sí misma, esta afirmación puede no ser suficiente.
talonx