TDD se trata de diseñar código, guiado por pruebas.
Por lo tanto, las capas típicas no suelen construirse por adelantado; deberían aparecer ligeramente a través de pasos de refactorización.
El diseño impulsado por el dominio implica muchos patrones técnicos, que definen capas bien establecidas como la capa de aplicación, la capa de infraestructura, la capa de dominio y la capa de persistencia.
Para comenzar la parte de codificación de un proyecto DDD desde cero, ¿cómo comportarse?
¿Debo dejar estrictamente que el diseño surja de las pruebas, lo que significa que no hay separación de preocupaciones (sin capas) y refactorización para que se ajusten a los patrones técnicos DDD?
¿O debería crear esas capas vacías (aplicación, entidades / servicios de dominio, infraestructura) y dejar que TDD encaje en cada una de ellas de forma independiente (usando simulacros para aislar entre capas)?
Respuestas:
Asegúrese de revisar los comentarios recientes del tío Bob sobre el papel del diseño en TDD .
Udi Dahan: "Dios, cómo odio las capas". Pasa algo de tiempo discutiéndolo en su charla CQRS, pero diferente (la estratificación comienza a las 18m30s)
Deletrearía tu oración de manera ligeramente diferente; "DDD reconoce que hay una serie de preocupaciones comunes a la mayoría de las aplicaciones comerciales y que las soluciones a esas preocupaciones tienen vidas diferentes" .
Por ejemplo, las preocupaciones de dominio, por regla general, deben ser flexibles, especialmente cuando está personalizando una solución para un negocio en particular. Después de todo, el dominio se refiere a cómo la empresa hace negocios, es decir, cómo la empresa gana dinero y poder ofrecer mejoras comerciales rápidamente es un ingreso gratuito.
Por otro lado, probablemente no necesite cambiar el componente de persistencia con frecuencia. La solución de base de datos que funcionó la última versión probablemente también funcionará en esta versión.
Las preocupaciones de la aplicación están en algún punto intermedio; tienden a ser estables para que los usuarios no necesiten aprender una nueva aplicación con cada lanzamiento.
Además, puede haber múltiples implementaciones para resolver cualquier problema. Por ejemplo, la aplicación puede necesitar solo una instantánea de su estado actual; basta con guardar un archivo en el disco. Y en sus primeras iteraciones, eso puede ser todo lo que el dominio necesita también. Pero eventualmente llega una historia que requiere soporte de consultas ad-hoc, y usted reconoce que configurar una base de datos relacional será mucho más fácil que implementar una desde cero. Y luego está esta característica que funcionaría mejor en una base de datos gráfica.
Mientras tanto, el CTO quiere una versión de la aplicación que se ejecute en su teléfono; el CEO acaba de escuchar de un tipo que publicar una API es lo más importante.
Además, el equipo de ventas utiliza un modelo diferente, por lo tanto, dénos la misma aplicación, con un modelo diferente. Oh, pero estamos viajando mucho, por lo que nuestra versión debe funcionar cuando estamos desconectados y sincronizarnos más tarde ...
En otras palabras, aplica los patrones tácticos de ddd no implementando marcadores de posición vacíos y suponiendo que se completarán más tarde, sino que al reconocer cuándo está cruzando las corrientes "Oye, ese es el código de persistencia en mi modelo de dominio, no debo ser hecho refactorización todavía ".
fuente
Test Driven Development (TDD) no es un diseño. Es un requisito que impacta su diseño. Al igual que si fuera necesario ser seguro para subprocesos, eso no es un diseño. Nuevamente, es un requisito que impacta su diseño.
Si ignora alegremente todas las demás preocupaciones de diseño y respeta religiosamente las reglas de TDD, no culpe a TDD cuando su código se convierte en basura. Será basura comprobable pero será basura.
Una cosa buena de la basura comprobable es que es una basura refactible, por lo que para algunas personas es lo suficientemente buena. Nos pondremos elegantes solo cuando sea necesario. Otros odian esto y culpan a TDD por ello. No. Esto es cosa tuya.
El diseño controlado por dominio (DDD) es algo que hace antes del ciclo de refactorización verde rojo de TDD.
DDD es el esfuerzo por crear y preservar un espacio en el código donde un experto en dominios, que en gran medida ignora los detalles del sistema, puede entender cómo controlar el sistema. Esto se realiza mediante abstracción y modelado de un dominio problemático de una manera familiar.
Un sistema DDD puede tener una arquitectura similar a esta:
Esta arquitectura DDD tiene muchos nombres: Clean , Onion , Hexagonal , etc.
Aquí está la desconexión que veo que muchas personas tienen cuando miran este diseño. Esto no es concreto. Puedo seguir este diseño y nunca he escrito nada de lo que ves diagramado aquí. Veo que otros insisten en que debe haber un objeto de caso de uso o una clase de entidades. Estas son un conjunto de reglas que le indican con quién puede hablar y cómo.
Eso es. Siga las reglas de este diseño y puede TDD su pequeño corazón. A TDD no le importa con quién hables. Le importa que todo lo que hace algo pueda demostrarse que funciona o no con solo hacer clic en un botón. No, algo en alguna parte está roto. Te dice exactamente lo que está roto.
¿Todavía vago? Mire el diagrama
Controler
-Use Case Interactor
-Presenter
en la esquina inferior derecha. Aquí hay tres cosas concretas que se comunican entre sí. Claro que esto es DDD, pero ¿cómo agrega TDD aquí? Solo burlarse de las cosas concretas. El presentador debe estar recibiendo información. UnaPresenterMock
clase sería una buena manera de comprobar que está obteniendo lo que esperaba. Repartir laUse Case Interactor
delPresenterMock
e impulsar elUse Case Interactor
como si fuera elController
y tienes una buena manera de probar la unidad delUse Case Interactor
puesto que la maqueta le dirá si tiene lo que se espera que va a obtener.Pues mira eso. TDD satisfecho y no tuvimos que seguir con nuestro diseño DDD. ¿Cómo pasó eso? Comenzamos con un diseño bien desacoplado.
Si usa TDD para impulsar el diseño (no simplemente D evelopment), obtiene un diseño que refleja el esfuerzo que le dedicó. Si eso es lo que quieres bien. Pero eso nunca fue para lo que estaba destinado TDD. Lo que esto termina por carecer ciertamente no es culpa de TDD.
TDD no se trata de diseño. Si tiene que hacer cambios de diseño para usar TDD, tiene mayores problemas que las pruebas.
fuente
TDD asegura que su código tiene todos los casos de prueba necesarios escritos en paralelo al desarrollo. Esto no debería afectar el diseño de alto nivel. Piénselo más en el trabajo de las trincheras.
DDD tiene que ver con diseños de alto nivel, lenguaje entre expertos e ingenieros de dominio, mapeo de contexto, etc. Este debería ser el impulsor del diseño de alto nivel de la aplicación.
Ambas son explicaciones superficiales de dos poderosas metodologías de programación. Pero al final del día realmente logran dos cosas muy diferentes.
Comience con el lenguaje DDD y el mapeo de contexto y luego, cuando vaya a escribir el código, comience la práctica de TDD. Pero la práctica de TDD no debería afectar el diseño de alto nivel, pero debería asegurar que las cosas se puedan probar. Hay una pequeña advertencia aquí.
Creo que puede ser importante tener en cuenta: solo debe practicar DDD si la aplicación es lo suficientemente compleja.
fuente
DDD es sobre diseño de software.
TDD es sobre diseño de código.
En DDD, el "modelo" representa la abstracción del dominio, todo el conocimiento del dominio experto.
Podríamos usar TDD para el modelo de diseño de software de código inicial. El dominio tiene reglas de negocio y modelos de dominio que la prueba escrita (primero) debe ser verde.
En efecto, podemos codificar las pruebas, después de diseñar un modelo controlado por dominio.
Este libro "Growing Object-Oriented Software, Guided by Tests" link-for-buy
Tome este enfoque, con un esqueleto ambulante , arquitectura hexagonal y TDD.
Fuente de: DDD rápidamente - InfoQ
fuente
No. (impulsado por el dominio) El diseño por definición debe surgir de los requisitos del dominio. Es una mala idea dejar que cualquier otra cosa conduzca su diseño, ya sea un conjunto de pruebas, un esquema de base de datos o ... (continuará)
(continuación) ... o algunas capas canónicas de clases / jerarquías de clases en su idioma favorito de OO, incluso si es muy maduro y popular (después de todo, "millones de moscas no pueden estar equivocadas", ¿verdad?) .
Cuando se trata de DDD, OOP no cumple con los requisitos de expresión en forma legible para humanos, es decir, algo que sería más o menos claro para un no programador. Los lenguajes FP estrictamente escritos hacen un mejor trabajo. Recomiendo leer un libro sobre DDD usando la programación funcional "Modelado de dominio hecho funcional" por Scott Wlaschin
https://pragprog.com/book/swdddf/domain-modeling-made-functional
No tiene que usar el lenguaje FP para tomar prestadas algunas de las ideas de allí (no todas desafortunadamente), pero si realmente lo lee, entonces probablemente quiera usar un lenguaje funcional.
También responderá a su pregunta sobre cómo encaja TDD en la imagen DDD. En pocas palabras, cuando los requisitos están codificados en un estilo funcional, elimina la necesidad de una gran cantidad de pruebas unitarias, ya que hace que la mayoría de los estados y escenarios no válidos sean irrepresentables / imposibles de compilar. Por supuesto, todavía hay lugar para las pruebas automatizadas en el proyecto FP, pero de ninguna manera las pruebas impulsarán las decisiones de diseño más importantes.
Para hacer un círculo completo volvamos a la pregunta del título, es decir, "¿Cómo combinar TDD estricto y DDD?". La respuesta es sencilla: no hay nada que combinar / no hay conflicto de intereses. Diseñe de acuerdo con los requisitos, desarrolle de acuerdo con el diseño (escribiendo pruebas primero si realmente desea hacer TDD)
fuente