jorge07 / symfony-6-es-cqrs-boilerplate

Symfony 6 DDD ES CQRS backend boilerplate.
MIT License
1.07k stars 187 forks source link

Arquitectura del proyecto #154

Closed bareser closed 4 years ago

bareser commented 4 years ago

Hola, esta plantilla ¿Qué arquitectura sigue? Hexagonal? No me queda muy claro o no estoy seguro si estoy identificando correctamente.

Gracias.

jorge07 commented 4 years ago

Hey @bareser

Esto es algo que no está en la doc y que podría ser interesante.

La arquitectura del repo es hexagonal siguiendo Domain Driven Design. Basada en capas, esta arquitectura tiene el foco en el Business de la aplicación y dejando las implementaciones para luego.

La estrucura de carpetas es la siguiente:

src/
     Application/
            {BoundedContext} <- Use cases
     Domain/
            {BoundedContext} <- Domain Logic
     Infrastructure/
            {BoundedContext} <- Implementation
     UI/
        console
        http                             <- User Interface {web,api,cli....}
        ....

Aunque en aplicaciones más complejas y con multiples equipos es recomendable darle la vuelta a esto:

src/
      {BoundedContext}
               Application/      <- Use cases
               Domain/            <- Domain Logic
               Infrastructure/  <- Implementation
     UI/
        console
        http                             <- User Interface {web,api,cli....}
        ....

Pero como siempre, it depends.

Así con esto te quedaría una feature con el siguiente workflow

UI::Controller { 
     Use Application/{BoundedContext}/Command|Query 
     Use Command|Query Bus
     bus->handle|ask(command|query) -> Application/{BoundedContext}/.../*Handler { 
              Process the Command|Query accessing to Domain and/or Infrastructure 
     } -> Domain/{BoundedContext}/XXX { 
              Domain manages the Business logic without enter in the implementation, Example: UserRepository::save(AggregateRoot $user); 
     } -> Infrastructure/{BoundedContext}/YYY { 
              Implementations of our Domain. Example: MysqlUserRepository::save(AggregateRoot $user) implements UserRepository 
     }
}

Si necesitas más detalles feel free de abrir una issue o PR para mejorar la documentacion

bareser commented 4 years ago

Muchas gracias @jorge07 por tu explicación, me viene genial. ¡Qué gran valor aportas!

bareser commented 4 years ago

Hola Jorge, ¿Qué tal? espero que todo bien. Te escribo porque estoy empezando a empezar un proyecto personal sobre tu plantilla y llevo varios días con un error que no consigo entender ni resolver, a ver si me puede ayudar. He creado un boundedContext nuevo que se llama "ProductCategory" y a la hora de compilar me da el siguiente error:

Cannot autowire service "App\Application\Command\Product\CreateCategory\CreateCategoryHandler": argument "$productcategoryrepository" of method "__construct()" references interface "App\Domain\Product\ProductCategory\Repository\ProductCategoryRepositoryInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "App\Infrastructure\Product\ProductCategory\Query\Mysql\MysqlProductCategoryReadModelRepository", "App\Infrastructure\Product\ProductCategory\Repository\ProductCategoryStore".

No logro entender el motivo, he buscado información y el tema dicen que es sobre el fichero services.yml pero no entiendo porque estoy siguiendo tu BoundedContext "User" y no entiendo que no hay nada que añadir a este fichero services. ¿Puedes ayudarme?

También si me puede resolver otra duda, ¿Porque hay dos ficheros services? services.yaml y services_test.yaml

Aprovecho de nuevo para darte las gracias por tu aportación con este repositorio, es de gran ayuda para gente como yo, que quiere aprender. Muchas gracias.

El mié., 13 may. 2020 a las 11:19, Jorge Arco (notifications@github.com) escribió:

Hey @bareser https://github.com/bareser

Esto es algo que no está en la doc y que podría ser interesante.

La arquitectura del repo es hexagonal siguiendo Domain Driven Design. Basada en capas, esta arquitectura tiene el foco en el Business de la aplicación y dejando las implementaciones para luego.

La estrucura de carpetas es la siguiente:

src/

 Application/

        {BoundedContext} <- Use cases

 Domain/

        {BoundedContext} <- Domain Logic

 Infrastructure/

        {BoundedContext} <- Implementation

 UI/

    console

    http                             <- User Interface {web,api,cli....}

    ....

Aunque en aplicaciones más complejas y con multiples equipos es recomendable darle la vuelta a esto:

src/

  {BoundedContext}

           Application/      <- Use cases

           Domain/            <- Domain Logic

           Infrastructure/  <- Implementation

 UI/

    console

    http                             <- User Interface {web,api,cli....}

    ....

Pero como siempre, it depends.

Así con esto te quedaría una feature con el siguiente workflow

UI::Controller {

 Use Application/{BoundedContext}/Command|Query

 Use Command|Query Bus

 bus->handle|ask(command|query) -> Application/{BoundedContext}/.../*Handler {

          Process the Command|Query accessing to Domain and/or Infrastructure

 } -> Domain/{BoundedContext}/XXX {

          Domain manages the Business logic without enter in the implementation, Example: UserRepository::save(AggregateRoot $user);

 } -> Infrastructure/{BoundedContext}/YYY {

          Implementations of our Domain. Example: MysqlUserRepository::save(AggregateRoot $user) implements UserRepository

 }

}

Si necesitas más detalles feel free de abrir una issue o PR para mejorar la documentacion

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jorge07/symfony-5-es-cqrs-boilerplate/issues/154#issuecomment-627861496, or unsubscribe https://github.com/notifications/unsubscribe-auth/AF3FKPLLZPSNITULIH64XOTRRJQ3XANCNFSM4M55SC4Q .

jorge07 commented 4 years ago

Aquí tienes la clave

You should maybe alias this interface to one of
these existing services:
"App\Infrastructure\Product\ProductCategory\Query\Mysql\MysqlProductCategoryReadModelRepository",
"App\Infrastructure\Product\ProductCategory\Repository\ProductCategoryStore".*

Tienes dos clases que implementan ProductCategoryRepositoryInterface por lo que symfony no sabe cual ha de inyectar

bareser commented 4 years ago

Muchas gracias Jorge, eres un crack! ahora entiendo porque Users tiene varias interfaces. Disculpa mi ignorancia.

El mié., 29 jul. 2020 a las 22:00, Jorge Arco (notifications@github.com) escribió:

Aquí tienes la clave

You should maybe alias this interface to one of

these existing services:

"App\Infrastructure\Product\ProductCategory\Query\Mysql\MysqlProductCategoryReadModelRepository",

"App\Infrastructure\Product\ProductCategory\Repository\ProductCategoryStore".*

Tienes dos clases que implementan ProductCategoryRepositoryInterface por lo que symfony no sabe cual ha de inyectar

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/jorge07/symfony-5-es-cqrs-boilerplate/issues/154#issuecomment-665882928, or unsubscribe https://github.com/notifications/unsubscribe-auth/AF3FKPP6WNOW7ENHNGCU3ELR6B5WZANCNFSM4M55SC4Q .