6. Entendiendo los dominios
6.1. Diferencia conceptual entre dominios
En nuestro framework, existen dos tipos principales de dominios que es importante distinguir:
Dominios generales de Quartup
Los dominios generales se encuentran en src/ApiLayer/Domains/ y representan entidades o funcionalidades centrales del negocio que son comunes a toda la aplicación. Estos dominios:
- Implementan la funcionalidad básica y reutilizable para toda la aplicación
- Gestionan entidades fundamentales del negocio (Productos, Clientes, Facturas, etc.)
- Proporcionan una API estándar para operaciones CRUD y lógica de negocio común
- Son accesibles desde cualquier parte de la aplicación
- Están diseñados para ser extensibles
Dominios específicos de módulo
Los dominios específicos de módulo se encuentran en src/ApiLayer/Modules/{NombreModulo}/Domains/ y pueden ser de dos tipos:
-
Dominios exclusivos del módulo: Implementan funcionalidad que solo tiene sentido en el contexto de ese módulo específico.
-
Dominios que extienden dominios generales: Adaptan y especializan un dominio general para un contexto específico.
6.2. ¿Cuándo crear un dominio general de Quartup?
Debes crear un dominio general cuando:
- La funcionalidad representa una entidad o concepto central del negocio
- La funcionalidad será utilizada por múltiples módulos o partes de la aplicación
- Implementa operaciones estándar que siguen un patrón común (CRUD, filtrado, etc.)
- Quieres establecer una base común que se pueda extender para casos específicos
Ejemplos de dominios generales adecuados:
- Productos (catálogo general de productos)
- Clientes (gestión general de clientes)
- Facturación (sistema base de facturación)
- Usuarios (gestión de usuarios del sistema)
6.3. ¿Cuándo crear un dominio específico de módulo?
Para dominios exclusivos del módulo:
Debes crear un dominio exclusivo de módulo cuando:
- La funcionalidad solo tiene sentido dentro del contexto específico del módulo
- La entidad o concepto no aplica a otras áreas del negocio
- La lógica de negocio es altamente especializada para ese módulo
Ejemplos de dominios exclusivos de módulo:
Carts(Carritos) dentro del móduloTPV- Los carritos solo tienen sentido en el contexto de un punto de ventaAppointments(Citas) dentro de un móduloScheduling- Las citas son específicas de un sistema de programaciónPermutRequests(Solicitudes de permuta) dentro del móduloPermut- Las solicitudes de permuta son exclusivas del sistema de permutas
Para dominios que extienden dominios generales:
Debes crear una extensión de un dominio general cuando:
- Necesitas adaptar o especializar la funcionalidad general para un contexto específico
- Quieres añadir reglas de negocio adicionales específicas del módulo
- Necesitas personalizar el comportamiento de las operaciones estándar
- Requieres nuevos endpoints relacionados con el dominio pero específicos del módulo
Ejemplos de extensiones de dominios generales:
Productsdentro del móduloTPV- Extiende el dominio general de Productos para añadir funcionalidad específica del punto de venta, como verificación de stock o lecturas de código de barrasCustomersdentro del móduloCRM- Extiende el dominio general de Clientes para añadir funcionalidad de seguimiento, contactos, etc.Productsdentro del móduloPermut- Adapta los productos generales para el contexto de intercambios y permutas
6.4. Relación entre dominios generales y específicos
La relación entre dominios generales y específicos de módulo sigue estos principios:
-
Herencia: Los dominios específicos pueden extender los dominios generales, heredando su funcionalidad base y añadiendo o modificando el comportamiento.
-
Especialización: Los dominios específicos adaptan la funcionalidad general para un caso de uso concreto.
-
Segregación: Cada módulo puede tener su propia versión especializada de un dominio general, adaptada a sus necesidades particulares.
-
Coherencia: Aunque los dominios pueden estar especializados, mantienen una coherencia en la estructura y convenciones.
6.5. Estructura de rutas y nomenclatura
Es importante entender cómo se refleja esta organización en las rutas de la API:
-
Dominios generales: Las rutas comienzan con el nombre del dominio
/products/...
/customers/... -
Dominios específicos de módulo: Las rutas comienzan con el nombre del módulo seguido del dominio
/tpv/products/... (Extensión del dominio Products en el módulo TPV)
/tpv/carts/... (Dominio exclusivo del módulo TPV)
/permut/products/... (Extensión del dominio Products en el módulo Permut)
Esta nomenclatura permite:
- Separar claramente el ámbito de cada funcionalidad
- Evitar colisiones entre rutas
- Facilitar la comprensión del propósito de cada endpoint
6.6. Consideraciones para decidir entre dominios generales y específicos
Para dominios generales:
- Reusabilidad: ¿La funcionalidad se utilizará en múltiples contextos?
- Estabilidad: ¿La entidad o concepto es estable y bien definido?
- Centralización: ¿El concepto debe estar centralizado para mantener coherencia?
Para dominios específicos (exclusivos):
- Especialización: ¿La funcionalidad solo tiene sentido en un contexto específico?
- Aislamiento: ¿La lógica no debería afectar a otras partes del sistema?
- Complejidad: ¿La implementación tiene reglas de negocio muy particulares?
Para dominios específicos (extensiones):
- Personalización: ¿Necesitas adaptar un concepto general para un caso particular?
- Extensión: ¿Quieres añadir funcionalidad adicional sin modificar el dominio general?
- Variación: ¿Necesitas que ciertos aspectos funcionen de manera distinta en un módulo específico?
6.7. Ejemplo práctico: Creando un dominio de módulo
Vamos a ver un ejemplo paso a paso de cómo crear un dominio específico de módulo que extienda un dominio general existente, utilizando nuestro comando artesano.
Paso 1: Crear el dominio base en el módulo
Primero, utilizamos el comando create-domain para generar la estructura básica del dominio en el módulo:
php artesano create-domain Products p-maes_MaesartiProductos TPV
Este comando creará la estructura completa del dominio Products dentro del módulo TPV, incluyendo:
src/ApiLayer/Modules/TPV/Domains/Products/ProductsController.phpsrc/ApiLayer/Modules/TPV/Domains/Products/ProductsService.phpsrc/ApiLayer/Modules/TPV/Domains/Products/ProductsRoutes.phpsrc/ApiLayer/Modules/TPV/Domains/Products/DTOs/ReqMaesartiProductosDTO.phpsrc/ApiLayer/Modules/TPV/Domains/Products/DTOs/ResMaesartiProductosDTO.php
Paso 2: Modificar el controlador para extender el dominio general
Ahora, debemos modificar el controlador para que extienda del controlador del dominio existente:
- Abre el archivo
src/ApiLayer/Modules/TPV/Domains/Products/ProductsController.php - Modifica el contenido para que extienda el controlador del dominio existente:
<?php
namespace ApiLayer\Modules\TPV\Domains\Products;
// Cambiar esto:
// use App\Base\DomainController;
// Por esto:
use ApiLayer\Domains\Products\ProductsController as DomainProductsController;
// class ProductsController extends DomainController
class ProductsController extends DomainProductsController
{
public function __construct(ProductsService $service)
{
parent::__construct($service);
// Aquí puedes personalizar validaciones u otras propiedades si es necesario
}
// Ahora puedes añadir métodos específicos del módulo TPV
}
Paso 3: Modificar el servicio para extender el servicio existente
De manera similar, modificamos el servicio:
- Abre el archivo
src/ApiLayer/Modules/TPV/Domains/Products/ProductsService.php - Modifica el contenido para que extienda el servicio existente:
<?php
namespace ApiLayer\Modules\TPV\Domains\Products;
// Cambiar esto:
// use App\Base\DomainService;
// Por esto:
use ApiLayer\Domains\Products\ProductsService as DomainProductsService;
use Infrastructures\Legacy\PMaes\MaesartiProductos\MaesartiProductosRepository;
use App\Dtos\Contracts\InterfaceReqDto;
use App\Dtos\Contracts\InterfaceResDto;
// class ProductsService extends DomainService
class ProductsService extends DomainProductsService
{
public function __construct(
MaesartiProductosRepository $MaesartiProductosRepository,
InterfaceReqDto $CreateMaesartiProductosDTO,
InterfaceResDto $MaesartiProductosDTO
) {
parent::__construct(
$MaesartiProductosRepository,
$CreateMaesartiProductosDTO,
$MaesartiProductosDTO
);
}
// Ahora puedes añadir métodos específicos del módulo TPV
}
Paso 4: Añadir funcionalidad específica del módulo
Ahora puedes añadir funcionalidad específica para el módulo TPV. Por ejemplo, añadamos un método para obtener productos disponibles para venta en el TPV:
- En el controlador (
ProductsController.php), añade el nuevo método:
public function getAvailableForSale(Request $request)
{
ValidaRequest::make($request)
->validateHeaders([
'x-tienda' => 'required|numeric',
])
->validateBody([
'min_stock' => 'numeric',
])
->action('store')
->handle();
$products = $this->service->getAvailableForSale($request->all());
return response()->json($products, 200);
}
- En el servicio (
ProductsService.php), implementa el método correspondiente:
public function getAvailableForSale(array $request)
{
$minStock = $request['min_stock'] ?? 1;
$filters = [
'$and' => [
['stock_actual' => ['>=' => $minStock]],
['posart_sw_bloqueado' => ['=' => 0]]
]
];
$requestData = [
'page' => $request['page'] ?? 1,
'itemsPerPage' => $request['itemsPerPage'] ?? 20,
'filters' => json_encode($filters)
];
$products = $this->MaesartiProductosRepository->collection($requestData);
$products['collection'] = $this->mapToDTO($products['collection'], $this->MaesartiProductosDTO);
return $products;
}
- Añade la nueva ruta en
ProductsRoutes.php:
// Añadir nueva ruta específica del TPV
Route::get('tpv/products/available', 'getAvailableForSale', $middlewares);
Con este enfoque, has extendido el dominio general de Products para adaptarlo a las necesidades específicas del módulo TPV, reutilizando toda la funcionalidad base y añadiendo solo lo específico del módulo.
6.8. Beneficios de esta arquitectura
Esta arquitectura de dominios generales y específicos proporciona varios beneficios:
-
Separación de responsabilidades: Cada dominio tiene un propósito claro y definido.
-
Reutilización de código: Los dominios generales proporcionan una base común que puede ser extendida.
-
Flexibilidad: Los módulos pueden adaptar la funcionalidad general a sus necesidades específicas.
-
Mantenibilidad: Los cambios en un módulo no afectan a otros módulos o al sistema general.
-
Escalabilidad: Es fácil añadir nuevos módulos o extender la funcionalidad existente.
-
Claridad conceptual: La estructura del código refleja los conceptos del dominio de negocio.
6.9. Resumen
En resumen, la elección entre crear un dominio general o específico de módulo depende de la naturaleza de la funcionalidad que estás implementando:
- Dominio general: Para conceptos fundamentales del negocio que se utilizan en múltiples contextos.
- Dominio exclusivo de módulo: Para funcionalidad que solo tiene sentido dentro de un módulo específico.
- Extensión de dominio general: Para adaptar un concepto general a las necesidades específicas de un módulo.
Comprender esta distinción te ayudará a estructurar tu aplicación de manera coherente, mantenible y escalable, facilitando el desarrollo de nuevas funcionalidades y la adaptación a requisitos cambiantes.