En estos días se llevo a cabo Laracon 2019, la conferencia anual de Laravel y se anunciaron excelentes noticias para la comunidad.
Una de ellas fue Laravel Vapor, un serverless para PHP que promete revolucionar la comunidad de PHP y, el anuncio más importante fue la nueva versión de Laravel, Laravel 6 🤘 que estará disponible en Agosto del 2019.
Pero ahora bien, Laravel 6 será un «Major version», por lo tanto, se espera que haya cambios muy importantes en el Framework, tal como ocurrió con la salida de Laravel 5. Y es lógico que se genere una gran incertidumbre entre la comunidad.
Los desarrolladores comenzamos a preguntarnos muchas cuestiones sobre esto, por ejemplo: si nuestras aplicaciones serán compatibles con la nueva versión, si las modificaciones que tendremos que hacer serán engorrosas y difíciles de realizar, si los paquetes de terceros que tenemos instalados funcionarán con Laravel 6, «todavía no aprendo Laravel 5.8 y ya sale otra versión?! 😭» etc, etc.
Así que, me pareció un buen momento para enseñar como podemos hacer nuestras aplicaciones totalmente desacoplatadas del Framework (¡hasta se podría hacer desacoplatada del lenguaje de programación! pero esto tal vez lo veamos en un próximo artículo).
Antes de empezar
Desde ya les comento que será un artículo largo y tal vez cueste un poco entenderlo en la primera, ya que utilizaremos elementos de la POO y los Principios SOLID, entre otras técnicas. Así que, no sería malo que tengas a mano el artículo de SOLID que tengo publicado (https://www.laraveltip.com/guia-definitiva-de-principios-solid-explicados-con-laravel/) porque los vamos a aplicar a full.
¡Pero vamos, sin miedo que tampoco es para tanto 😀!
Comenzando a desacoplar nuestra aplicación Laravel: La Arquitectura Hexagonal
Como existe la arquitectura MVC, también existe la Arquitectura Hexagonal que nos permite desarrollar y probar nuestra aplicación de forma aislada al framework, a la base de datos, a los paquetes de terceros y todos esos elementos que están al rededor de nuestra aplicación.
* Entiéndase «aplicación» como esa parte de nuestro sistema que lo hace distinto a la competencia. Es la lógica de negocio.
La idea es separar nuestra aplicación en una nueva estructura de directorios que este por afuera de la que propone Laravel.
Esta arquitectura cuanta con 3 capas: Infraestructura, Aplicación y Dominio. Cada una de ellas esta más alejada del framework y solo se pueden comunicar con su capa siguiente (nunca la capa de Infraestructura se podrá comunicar con la capa de Dominio directamente).
Aclaro que no tiene nada que ver con un Hexágono pero es uno de los nombre que se le da a esta Arquitectura. Otros la llaman Arquitectura de Puertos y Adaptadores. Yo prefiero este ultimo nombre porque le da más sentido, ya verán por que.
Describiendo las 3 capas de la Arquitectura Hexagonal
- Infraestructura: La capa de infraestructura es la más cerca al framework y es la encarga de traducir todo lo que esta por afuera de nuestra aplicación (framework, base de datos, API’s, paquetes de terceros, etc.) y lo entrega a la capa de Aplicación.
- Aplicación: En la capa de aplicación vamos a tener todas las acciones que puede hacer nuestra aplicación.
- Dominio: La capa de dominio es el núcleo de tu sistema y establece como deben comunicarse las demás capas con ella. Es la única que no tiene acoplamientos de las otras capas.
Aplicando la Arquitectura Hexagonal en Laravel
Ahora si, comencemos con un ejemplo practico de como podemos aplicar los conceptos de la Arquitectura Hexagonal en Laravel. Para esto, vamos a poner de ejemplo a Laravel Tip y como sería su publicación de artículos en el blog.
Comenzaremos a construir (o reconstruir) a Laravel Tip de afuera hacia adentro, de la infraestructura hacia el dominio.
Aplicando Arquitectura Hexagonal en un proyecto Laravel
1. Crear la estructura de directorios
Primero debemos crear la siguiente estructura de directorios en la raíz del proyecto:
Normalmente, se crear una carpeta llamada src/ y para este ejemplo sencillo, creamos una carpeta por cada capa de la arquitectura hexagonal.
Para que el sistema reconozca la carpeta src/ debemos editar el archivo composer.json de la siguiente forma:
Ahora ejecutamos el comando composer dump-autoload
y listo, ya podemos empezar a meter mano en el código.
2. Del Framework hacia nuestra aplicación – La capa de Infraestructura
Cuando se crea un artículo en Laravel Tip sabemos que se genera una request de tipo POST
hacia un controlador, el controlador envía los datos al modelo, el modelo los persiste y el controlador responde a la vista.
Pero ahora cambiaremos este flujo. El controlador seguirá siendo la puerta de entrada a nuestra aplicación, pero ahora el controlador va a preparar los datos de entrada y los enviara a la capa de Infraestructura.
Nuestro controlador quedaría así:
Esto y nada mas que esto es lo que va a tener nuestro método store
(ya les adelanto que todos nuestros controladores se verán igual).
Analicemos el código juntos y veamos que hay de nuevo. Si miramos los namespaces de las dependencias ya nos damos cuenta que los comandos viven en la capa de aplicación y el bus de comandos pertenece a la capa de infraestructura.
¿Pero qué es un comando y un bus de comandos?
- Un Comando (en nuestro ejemplo
CreateArticleCommand
), es una clase simple que se encarga de mantener los datos para ser transportados (en POO a este tipo de clases se las llama DTO). Tendremos un comando por acción y un Handler por Comando (ya veremos que es un Handler). - El Bus de Comandos es el encargado de transferir el comando a la capa de aplicación y mapearlo con su respectivo Handler.
Volviendo al código del controlador, si miramos su constructor vemos que le estamos inyectando CommandBus
. Pero desde ya les digo que CommandBus
no es una clase, si no que es una interfaz. ¿Y por qué lo hago así? Bueno, esto es la base de la Arquitectura Hexagonal y el porque también se la llama Arquitectura de Puertos y Adaptadores.
Donde la interfaz CommandBus
es el Puerto y la clase concreta SimpleCommandBus
(que la veremos a continuación) es el Adaptador.
¡Esto es la D de los Principios SOLID y la base para desacoplar nuestro código del Frameworks 😎🤘!
Veamos el código del Comando y del Bus de Comandos:
Muy simple, no? Ahora veamos el Bus de Comandos.
Como pueden ver, mi Bus de Comandos es muy simple. Su forma de mapear el comando con el handler es un poquito rudimentaria ya que, únicamente hace un reemplazo de nombres e instancia la clase.
Pero, si el día de mañana quiero cambiar el Bus de Comandos por uno más potente como Tactician (https://tactician.thephpleague.com/) o Prooph (http://getprooph.org/), puedo hacerlo sin problemas. Nada más, tendría que decirle al sistema que, cuando el controlador espere un CommandBus
en su constructor, reciba a Tactician o a Prooph o a mi SimpleCommandBus 😉.
Lo mismo esta pasando con el Container
que estoy inyectando en el SimpleCommandBus
. No inyecto una clase concreta de Container
, sino que inyecto una interfaz y luego le digo que container quiero que utilice (después veremos como es que le digo que use una clase concreta u otra).
Acá el código de al interfaz del Container y el código del Container concreto:
3. Ya estamos en la capa de Aplicación: Los Casos de uso
Como los comandos, los casos de uso (o handlers) pertenecen a la capa de Aplicación y son los encargados de ejecutar la acción, en este ejemplo, la creación de un nuevo artículo en Laravel Tip.
Los Casos de uso pueden ser manejados en una nueva clase. Pero, como este ejemplo es muy sencillo y no tiene mucha lógica, utilizare el handler como caso de uso, también es valido.
Miren el constructor de CreateArticleHendler
, ¿se acuerdan de los Repositorios? Bueno, volvieron en forma de elemento de la Arquitectura Hexagonal.
Como nos estamos desacoplando de todo, el Patrón Repositorio encaja muy bien con la arquitectura hexagonal porque nos permite «enchufar» cualquier implementación de base de datos que queramos.
Como tal vez ya habrás adivinado… lo que estamos inyectando en el constructor del hendler es una interfaz del Repositorio. De esta forma quedamos desacoplados a la forma de persistir los datos y tendremos la libertad de decidir si vamos a pasarle una clase de Eloquent, de Doctrine o de el nuevo ORM que tendrá Laravel 6 (si es que esto pasa 🤷♂️, nop… esto no paso 😕).
Por otro lado, vemos que estamos instanciando un objeto de la clase ArticleEntity.
Esta clase pertenece a la capa mas profunda, la capa de Dominio. Y como queremos que nuestro caso de uso este marcado a fuego con el dominio, usamos new
para instanciar y no una abstracción, como hacíamos con las interfaces.
Por ultimo, el repositorio se encarga de persistir un nuevo articulo.
4. La capa más profunda, la capa de Dominio.
Esta es la capa más importante, el núcleo de nuestra aplicación. Acá tenemos la lógica que hace que nuestro sistema sea distinto al resto. En la carpeta de Domain tenemos las entidades y las interfaces de los repositorios (entre otras cosas). Veamos el código de ambos.
El repositorio es muy simple. Solamente definimos los métodos que necesita un artículo. En este caso, un artículo solo se va a crear (por ahora).
A continuación, la implementación concreta del repositorio.
En este caso es un repositorio de Laravel y codifico el método de la forma que Laravel sabe guardar un artículo. Si hiciéramos un repositorio concreto de guardar artículos en un array, seguramente su método save
sería distinto. Al igual que si hiciéramos en Doctrine o en SQL plano.
5. El núcleo de nuestra aplicación: La Entidad.
Como vemos, nuestra clase ArticleEntity
no extiende ni implementa nada. Ni tampoco tiene ningún use
esto debe ser así ya que, todo lo que esta en la capa de dominio no debe tener relación con el exterior.
Por otro lado, le agregamos un poco de lógica de negocio a nuestra entidad como por ejemplo, el titulo comience con mayúscula y el contenido no tenga palabras ofensivas. También se podrían agregar las validaciones de datos, si no queremos depender de los Form Request de Laravel.
6. Seleccionando los adaptadores para los puertos
Como ya dije anteriormente, esta arquitectura de software se basa en puertos (interfaces) y adaptadores (clases concretas), pero estuve postergando como se le dice al sistema que adaptador se le debe «enchufar» a cada puerto. Ahora veremos como hacerlo.
Para seleccionar los adaptadores tenemos varias formas, podríamos utilizar un patrón de diseño como Factory Method, por Reflection, o utilizando un contenedor de inyección de dependencias (IoC), entre varias más.
Para este ejemplo vamos a utilizar un IoC. Podríamos hacer uso del IoC que viene en Laravel o podríamos descargarnos uno de terceros (como PHP-DI), todo depende de cuanto te quieras abstraer del framework. Para no explicar como se utiliza otro IoC distinto al de Laravel y el artículo se haga más largo, voy a utilizar el de Laravel.
Abrimos el archivo AppServiceProvider.php
de Laravel para hacer las conexiones necesarias entre puertos y adaptadores, dejándolo de la siguiente forma:
Eso es todo! Hemos aplicado la Arquitectura de Puertos y Adaptadores correctamente y ya podemos disfrutar de sus beneficios.
Principios SOLID aplicados
Además de aplicar la Inversión de Dependencias (la D de SOLID) cada vez que cambiamos de adaptador. También estamos aplicando dos principios más.
Por un lado, aplicamos el Principio de Responsabilidad Única (la S de SOLID) ya que cada clase tiene un responsabilidad bien definida.
Además, aplicamos el Principio de Abierto/Cerrado (la O de SOLID) porque no necesitamos tocar las clases para que el sistema siga funcionando. Por ejemplo, ¿queremos cambiar nuestro CommandBus? ok! enchufamos otra clase; ¿queremos cambiar la forma de realizar la acción «guardar articulo»? ok! creamos un nuevo comando y un nuevo hendler.
¡SOLID everywhere ✊!
Beneficios de la Arquitectura Hexagonal
Los beneficios que obtenemos en aplicar la arquitectura hexagonal son varios, algunos de ellos son:
- Independencia del framework.
- Más tolerantes al cambio.
- Independencia de la UI.
- Calidad de software: Ya que aplicamos las buenas practicas y principios SOLID.
- Independencia de la base de datos.
- Reutilización: La utilización de comandos nos provee reutilizarlos en cualquier caso, ya se, en la web, en un sistema CLI, en una API, etc.
- Mantenibilidad: Es más fácil localizar lo que esta fallando.
- Testeabilidad: La separación por capas nos brinda un sistema fácilmente testeable de forma unitaria, permitiendo mockear las dependencias.
Contras de la Arquitectura Hexagonal
Algunos de los contras que tiene esta arquitectura son:
- Mayor complejidad en el sistema.
- Los nuevos programadores deberán tener conocimientos o deberán ser capacitados en la arquitectura.
Bibliográfica
Conozco 3 libros que tratan este tema (y temas más avanzados a partir de este), que les puede ser útiles si les interesa esto de la Arquitectura de Software.
- Domain-Drive Design de Eric Evans.
- Arquitectura Limpia de Robert C. Martin (Uncle Bob), disponible en español.
- Domain-Driven Design in PHP de Carlos Buenosvinos.
Conclusión final
Como vimos pudimos separar nuestra aplicación lo máximo posible de Laravel. La parte mas importante de nuestra aplicación esta empaquetada en la carpeta src/. Si bien utilizamos cosas del framework (como las routes, los controladores y el IoC), son herramientas mínimas y totalmente fáciles de reemplazar por lo que pueda llegar a venir en Laravel 6.
Me quedaron muchas cosas en el tintero y soy consciente de que pueden surgir muchas dudas. Así que siéntanse libres de dejar sus consultas en los comentarios y, si es necesario, puedo hacer un live-coding en YouTube para resolver todas las dudas que tengan, si les parece.
Espero que les haya gustado el artículo, denle a compartir si así fue y próximamente escribiré uno de como hacer testing de todo esto. Nos vemos en la próxima 😉🤙.
Buen Artículo, excelente la explicación pero no entendí bien, pero por culpa mía no del profesor jaja me re intereso el tema pero siento que me falta leer bastante para lograr hacer algo así. Fijate que la parte de la bibliografia justo al menos yo no puedo verla
Muchas gracias Mauro! Voy a mencionar los libros en el artículo porque algunas personas también ya me han dicho que no los pueden ver.
Ciertamente cómo mencionas en el post, una de las contras de aplicar esta arquitectura es la complejidad que conlleva crearla, en lo personal me gusta usar sólo algunos de los conceptos del DDD como los objetos de valor, inmutabilidad, pero pienso que desacoplarse tanto del framework es a su vez desaprovecharlo porque se asume que dentro del diseño se debe contemplar el framework a usar, de todas formas, excelente post.
Concuerdo! Y, como siempre, todo depende del contexto en el que este tu proyecto y el nivel de abstracción que quieras manejar.
En este mismo ejemplo utilizo cosas de Laravel. Pero creo que lo importante es que tu dominio si este abstraído lo máximo posible del framework, de la base de datos, de servicios de 3ros, etc.
Muchas gracias por tu comentario :).
Excelente artículo!!!
Tu solución es mucho más simple que la que hice yo cuando empecé a aplicar DDD con Laravel (5.6)
Así que ahora me toca Refactoriar mucho!!!!
Pero no me importa 😉
Me gusta su solución!
Enhorabuena!
PD: Te comento sólo dos detalles (por empezar con algo 🙂
1. Los id los proporciona la Request en lugar de ser autogenerados por el Repository
2. La ejecucion de los comandos no devuelven nada.
Opino que la comunicacion ascendente, desde el Dominio hacia la UI, debe estar resuelto tambien por la Arq Hexagonal.
En mi caso, mis Handler sí que devuelven respuestas
En fin, hay mucho que comentar 😉
Un cordial saludo!
Muchas gracias Javier por tu comentario. Con respecto a los detalles que marcas:
1. Totalmente de acuerdo! Pero no quise extender el artículo con uuid desde el front y demás. Pero si, es correcto lo que marcas.
2. En este caso es un «si y no». Si bien puse un
return
al métodoexecute()
del bus de comandos, el handler y el repositorio no esta devolviendo nada y el controlador tampoco espera nada de él.Por otro lado, yo creo que, tanto los patrones de diseño como las arquitecturas no deben ser implementadas a raja tabla. Tiene que existir una flexibilidad dependiendo el caso y la mejor solución para cada proyecto.
Saludos bro!
Hola excelente post la verdad me sirvio muchisimo para empezar a programar mejor, aun que tengo una duda por mi ignorancia cuando creas el modelo le pasas como parametro un ArticleEntity pero tu modelo es un Article, y usas el metodo del modelo directamente? No deberia ser un Article tambien en lugar de un Entity no se si se entiende mi duda. Gracias
Hola Javier, como estas? Muchas gracias por tu comentario.
Lo que necesitas ya lo resuelve las Notifications de Laravel. Te dejo la parte de la documentación que necesitas: https://laravel.com/docs/6.0/notifications#database-notifications
Cualquier duda, volve por el blog :).
Saludos.
Buenísima la explicación. Difícil de entender en sus comienzos debido al cambio en como se deben pensar las cosas, es cuestión de releerlo varias veces e intentar llevarlo a la practica.
Tengo una consulta, es respecto al modelo. Si quiero usar las relaciones que propone laravel, donde debo hacerlo? Así no rompo con: «todo lo que esta en la capa de dominio no debe tener relación con el exterior.»
Muchas gracias por tu comentario Emilio.
Todo lo que sea manejo con la persistencia de datos (ya sea consultas, relaciones, inserciones, etc.) deberías abstraerlo con los repositorios.
Los repositorios son la capa intermedia que se comunican con los Modelos de Laravel (o con Doctrine, o con Redis, o con cualquier persistencia) y tiene lo métodos necesarios que le servirán al cliente que utilice el repositorio.
Por ejemplo y basándonos en el ejemplo del artículo, supongamos que necesitas saber el autor de un artículo, entonces en el repositorio de artículos de Eloquent (ArticleEloquentRepository.php) harías:
public function getAuthorFromArticle()
{
return $this->model->author->name;
}
Donde $this->model es una instancia del modelo Article. Y en Article.php existe la relación author().
Espero que se entienda, si no vuelve a preguntar que no es molestia.
Saludos.
Perfecto, lo entendí. Muchas gracias. Me había generado dudas esto: «Como vemos, nuestra clase ArticleEntity no extiende ni implementa nada. Ni tampoco tiene ningún use esto debe ser así ya que, todo lo que esta en la capa de dominio no debe tener relación con el exterior.»
Hola, excelente el articulo. Mi duda es saber donde incluyo validaciones propias del negocio? por ejemplo si no quiero permitir que se creen mas de 3 artículos por autor. Donde se incluye y como notificar a la capa mas alta?gracias
Hola Eduardo, todas las reglas de negocio van en la capa de dominio. O sea, en las entidades. Si no cumplen las reglas, entonces lanzan una excepción para notificar a la capa de infraestructura.
tomando una respuesta anterior. Seria valido escribir esta regla en el repositorio?
//ArticleEloquentRepository.php
public function exceeds_limit_articles() : bool
{
$limit = 3;
$author = $this->model->author;
if( $author->articles->count() >= $limit ){
return true;
}
return false;
}
public function save( ArticleEntity $article ): void
{
if ( $this->exceeds_limit_articles() ){
//..
//throw new Exception
}
$this->model->create( $article );
}
Nuevamente Gracias
No, cómo te comentaba las reglas van en la capa de dominio (para el caso que mencionas sería ArticleEntity o Article a secas). Fíjate que lo estás poniendo en ArticleEloquentRepository que es una clase concreta del repositorio que accede a la BD, por lo tanto, esta clase pertenece a la capa de infraestructura.
Por lo tanto, en el hanlder (o en una nueva clase, cómo quieras) tenés que tener el repositorio que devuelva solo la cantidad de exceeds_limit_articles. Esta cantidad la deberías pasar a un método de ArticleEntity y este método debe resolver si devuelve true/false o la excepción. Y por último gravas la entidad con el repositorio.
Buenas, me esta costando diferenciar entre el Article (model) y el ArticleEntity. Me podrias explicar este ultimo un poco mas por favor para entender la diferencia con el primero.
Hola Emilio, como estas?
A grandes rasgos, el modelo lo estamos dejando para que solo haga operaciones con la BD. Y la clase Entidad la utilizamos para que haga toda la lógica con los datos.
Tal vez te genere un poco de confusión porque algunas personas suelen poner la lógica de la aplicación en los modelos. Y eso no esta mal. Pero en la arquitectura que comento en la publicación, queremos separar lo que es la lógica del negocio de la persistencia de los datos, cosa que siempre tengamos la libertad de sacar una implementación y utilizar otra.
Si todavía tienes dudas, vuelve a comentar con más detalle para ayudarte mejor. Saludos.
Estoy implementando la arquitectura y me surgieron un par de dudas.
Primero, la clase CreateArticleHendler implemente la interface Hendler, la cual no esta definida dentro de este ejemplo, o yo no la estoy visualizando. Me podrías indicar como seria la misma?
Lo segundo seria que en el caso de uso que estoy queriendo implementar es un endpoint donde llamo a otra api. Entonces, la llamada a esta segunda api, debe estar implementada en el Handler? Para este caso no haría falta un Repo verdad?
Hola Emilio, como estás?
En este ejemplo se podría llegar a obviar la interface del Handler pero no es mala idea ponerla (aunque no tenga ningún método) para «agrupar» todos los handlers.
En este caso, el código de la interface del Handler, simplemente sería:
interface Handler
{
}
Con respecto a tu segunda pregunta, si le estas pegando a un endpoint para hacer operaciones de persistencia, entonces si, deberias implementar un repositorio como el que comento en el articulo pero en vez de ir a Eloquent, le pegue a la api.
Eso es lo bueno de los repos, te permiten abstraer los datos de su fuente (si van o vienen de una bd, de una api, de la memoria, etc. le da lo mismo al repo).
Espero que te sirva, cualquier cosa vuelve a preguntar.
Saludos.
La interface Handler iria dentro de «Application\Services\Contracts»?
Por otra parte, me quedo clara la explicacion, aunque en mi caso, el api externa no la voy a usar para persistir en la base de datos, sino para realizar tareas de negocio y seguridad, como logueo, obtención de datos, etc. Igualmente deberían estar en el repo?
Si, la interface iría ahí.
Piensa que cada comportamiento es un caso de uso único y un caso de uso puede utilizar a otro. Entonces, volviendo a tu pregunta original, si el endpoint es un comportamiento entonces si debes meterlo en un caso de uso y tu handler (tu otro caso de uso) debe utilizarlo.
Excelente Articulo! Muy bien explicado!
Una duda, si quisiera implementar Validator, donde entraria? en los Repositorios?, ademas, si quisiera ejecutar varios comandos que insertan en DB, como manejar si el segundo comando falla? se hace rollback del primer comando?
Muchas gracias por el aporte!
Hola Yako, como estás? Muchas gracias por tu comentario y por darte una vuelta por el blog.
La clase Validator pertenece al framework, por lo tanto iría en la capa de infraestructura. Por lo tanto, iría en el controlador como siempre. Pero, yo utilizaría los FormRequest.
Con respecto al segundo punto que comentas, en realidad es un comando por caso de uso. Debes disparar un solo comando y este ejecutará un o varios casos de uso. Por ejemplo, si quisieras actualizar el sexo de un usuario primero debes buscar al usuario, validar que exista y luego actualizarlo.
Entonces, el command para esto sería UpdateUserGenderCommand y esto activaría 2 casos de uso: UserFinder y UserUpdater. Si alguno de los dos casos de uso fallarían, dispararían su propia excepción que sería capturada por el controller que disparo el comando.
Resumiendo, la idea es esa, disparar un comando y que se activen los casos de uso necesarios.
Cualquier duda, no dudes en preguntar.
Saludos.
Qué buen artículo, disculpe el atrevimiento, no tiene esto público en algún repositorio. Gracias
Hola Roberto, como estas? Muchas gracias por tu comentario. Puedes ver un repo de algo parecido a lo que comente en este artículo. Te paso el link https://github.com/matiechaza/laravel-hexagonal-example
Este repo viene a raíz de un live que hice en Youtube, te dejo el link también: https://bit.ly/2T6L5Xh
Saludos.
Como va Roberto? Acá te dejo un repo mío con una implementación https://github.com/matiechaza/laravel-hexagonal-example.
El mejor artículo es español para empezar a entender la arquitectura hexagonal aplicada a Laravel. Muchas gracias!!!
Gracias a vos Alvaro por tu comentario. Saludos.
Hola matias gusto saludarte, podrias ayudarme con este cambio que le hice a la clase UserElquentReporitory para que me funcionara,
// Método obligado a desarrollar por la implementación
// de UserRepository
public function save(UserEntity $user): void
{
$this->model->create([
‘name’ => $user->getName(),
‘email’ => $user->getEmail(),
‘password’ => $user->getPassword()
]);
}
original
// Método obligado a desarrollar por la implementación
// de UserRepository
public function save(UserEntity $user): void
{
$this->model->create($user);
}
Esta bien como lo hiciste, fue un error mío.
Se pueden comunicar entre dominos??
Es decir, como en el ejemplo mencionado, si existiera un Modulo o Dominio llamado Usuarios y yo quisiera guardar quien creo el artículo dentro del Domino de artículos debo crear por ejemplo ArticuloAutorId o puedo utilizar UsuarioId del dominio de usuarios o el ArticuloAutorId se extendería de UsuarioId??
Por el ejemplo que mencionas creo que te referis a si se pueden reutilizar clases, no? Si, usa directamente UsuarioId.
Con respecto a la comunicación entre dominios, los dominios se deben que comunicar por medio de eventos (normalmente) asíncronos.
Una entidad dispara un evento cuando termino de realizar una acción y las entidades interesadas se suscriben a ese evento.
Buenas, te consulto. Estoy desacoplando una aplicación monolitica en varios microservicios y ahora tengo un caso de uso que requiere que uno de los datos lo valide mediante otro microservicio que ya he creado. La instancia de este MC para validar el dato entiendo no lo debo hacer en la clase entity. Entonces, debo resolver todo esto en el repo? Es ahí donde debo generar la instacia para llamar al metodo de validación? O la instancia la debo crear en el handler y pasársela al repo como parametro?
No se de que dato se trata, pero si la validación es una regla de negocio entonces lo tenes que validar en la entidad o en el Value Object.
Gracias mati por la respuesta. Es así el caso de uso: tengo que dar de alta un usuario que tiene una relación de integridad con una tabla que pertenece a otro microservicio. Este otro mocroservicio tiene una gerargia padre en cuanto a los datos. Por ende, para dar de alta a mi usuario, el valor que tengo que validar tiene que existir. Es una regla de negocio como vos decís. Creía que no debía ir esta validación ni en la entidad ni en el Value Object ya que, si bien es una validación de negocio, tengo que consultar un servicio externo, el cual debería estar definido en la capa de infraestructura, y tengo entendido que la capa de dominio no puede comunicarse con esta otra capa. Aun así debo ponerlo en la capa de dominio a esta validación?
¿Por qué un dato importante para crear un usuario vive en otro dominio? Cuando llegas a esa pregunta puede que la respuesta sea «porque ese otro dominio es parte del dominio de Usuarios». A lo que voy es que puede que haya funcionalidad en un microservicio que en realidad pertenezca a otro.
Pero cuesta llegar a una conclusión porque no conozco el sistema.
Pero bueno, lo que te puedo llegar a decir es que, si esa validación es responsabilidad de otro MS, entonces debería ser un caso de uso de ese MS.
Por lo tanto, el caso de uso «alta de usuario» debería ejecutar el caso de uso «validación de dato».
Hola me encanto el articulo, exlente explicacion me sirvio mucho para poder entender y realizarlo. pero tengo una duda y capaz vos ya lo tengas implemetado. como despacharias y ejecutarias los eventos?
Hola Rodolfo, muchas gracias por tu comentario.
Lo podes hacer con el dispatcher que viene en Laravel o usar un Command Bus como RabbitMQ o Kafka (una implementación conocida de estos command bus es Tactician).
OK gracias. si tenes explicado en algun lado eso pasamelo sino muchas gracias me re ayudaste 🙂
Estoy aplicando la arquitectura y resulta muy claro el código una vez que se entiende cada capa de la misma. La duda que estoy teniendo en estos momentos es en el repo, cuando devuelvo un recurso o un listado, tengo que usar un DTO de salida? Puedo usar los Api Resource de laravel? Este ultimo tengo que ponerlo en el repo? Entiendo que si los api resource los pongo en el handler y desde el repo devuelvo el modelo, estoy acoplando la implementación al uso de eloquent.
Hola Emilio, como estas? Disculpas en la demora de la respuesta.
Cuando devolves un listado de resultados, lo tenes que hacer en una Colección de DTOs o Entidades. Esto lo tiene que devolver el repositorio.
Los Api Resources son justamente esto con algunos detalles que incorpora Laravel. Y no habría problema que los implementes en los repo ya que las dos cosas viven en la capa de infraestructura.
Puedes hacer un video de yotube con este contenido ?
Como estas Hector? Dejo el video del webinar completo que hice sobre este tema:
Igualmente, en mi canal de twitch, vamos a hablar y aplicar esta arquitectura. Te dejo mi canal de twitch: https://www.twitch.tv/laraveltip
Hola! Gracias por este post hermano, gracias a uds pude comprender como es lo basico para empezar mi proyecto usando esta arquitectura, no hay nada mejor como un ejemplo practico, donde vayas del pi al pa con todo lo necesario.
Ahora lo que debo hacer es separar mi app por bounded context y aplicar tu explicacion.
Una duda me quedó: Por que pusiste el container dentro de Bus? Será que todo lo que invocas en Infra es Commands? Quiza te haga falta mandar un mail, creo que poner Container en el namespace Bus no compagina ya que la interfaz Container tuya es la que debe usarse para que la implemente nuestro LaravelMailer no? De todas maneras si lo haces asi para este ejemplo en especifico me parece muy bien igual.
Gracias por todos los tips.
Saludos desde La Habana
Muy buen artículo. Pero como sería si lo que queremos es hacer un GET a una url de una API externa? Es decir, nuestra fuente de datos sería la api, que nos devuelve la data. Pero si desde el controlador no podemos escupir el JSON desde donde lo hacemos? Y que escupimos desde el Controlador, dado que la respuesta ok o ko viene en el momento de ejecutar la consulta a la api?
Hola Jose, como estas? Gracias por tu comentario.
Como vos dijiste, la API es la fuente de datos por lo tanto vas a tener una implementación de repositorio para esa API. El repositorio de la api hará el get y si falla por algún motivo, dispararías una excepción que sería handleada en el controlador.
Espero que se entienda, cualquier cosa volve a preguntarme.
Saludos.
Hola amigo como te va..?
EL post me ha servido de gran ayuda, he visto el video web binar y note que creas carpetas por modulo es decir: src\Usuario\Application, Infrastructure, Domain y debo crear src\Blog\Application, Infrastructure, Domain
Amigo me surgió otra duda viendo los videos y comparando el post en el constructor del controller del articulo inyectas una interfaces pero en los demás ejemplo no lo haces y el que «execute» es la capa de la aplicación, no debería ser la capa de infrastructure que «exucute» la comunicacion con la capa aplicacion, otra de mis preguntas es si hay varios modulo hay que registrar cada uno en el provider, al igual que el repository..?
Hola Erick, como estas? Muchas gracias por tu comentario!
Lo ideal es inyectar por interfaz, en estos momentos no me acuerdo el ejemplo donde inyecte la clase concreta pero si tienes a mano el ejemplo avísame por favor así comento porque lo hice así.
La pregunta con respecto a «execute» creo que no la termine de entender. Me explicarías más?
Con respecto a la última pregunta, si, hay que registrar todo en el service provider.
Saludos!
Hola, cómo estás. Está excelente el artículo y también el video que subiste a youtube.
Me preguntaba si quizá podías explicarme un poco cómo creaste el commandBus, sigo sin entenderlo. Gracias de antemano
Muchas gracias Santiago. Voy a ver si hago un artículo explicando el tema del command bus que es una duda que tiene varias personas.
existe codigo fuente completo ??