Skip to main content

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:

  1. Dominios exclusivos del módulo: Implementan funcionalidad que solo tiene sentido en el contexto de ese módulo específico.

  2. 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ódulo TPV - Los carritos solo tienen sentido en el contexto de un punto de venta
  • Appointments (Citas) dentro de un módulo Scheduling - Las citas son específicas de un sistema de programación
  • PermutRequests (Solicitudes de permuta) dentro del módulo Permut - 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:

  • Products dentro del módulo TPV - 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 barras
  • Customers dentro del módulo CRM - Extiende el dominio general de Clientes para añadir funcionalidad de seguimiento, contactos, etc.
  • Products dentro del módulo Permut - 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:

  1. Herencia: Los dominios específicos pueden extender los dominios generales, heredando su funcionalidad base y añadiendo o modificando el comportamiento.

  2. Especialización: Los dominios específicos adaptan la funcionalidad general para un caso de uso concreto.

  3. Segregación: Cada módulo puede tener su propia versión especializada de un dominio general, adaptada a sus necesidades particulares.

  4. 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.php
  • src/ApiLayer/Modules/TPV/Domains/Products/ProductsService.php
  • src/ApiLayer/Modules/TPV/Domains/Products/ProductsRoutes.php
  • src/ApiLayer/Modules/TPV/Domains/Products/DTOs/ReqMaesartiProductosDTO.php
  • src/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:

  1. Abre el archivo src/ApiLayer/Modules/TPV/Domains/Products/ProductsController.php
  2. 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:

  1. Abre el archivo src/ApiLayer/Modules/TPV/Domains/Products/ProductsService.php
  2. 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:

  1. 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);
}
  1. 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;
}
  1. 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:

  1. Separación de responsabilidades: Cada dominio tiene un propósito claro y definido.

  2. Reutilización de código: Los dominios generales proporcionan una base común que puede ser extendida.

  3. Flexibilidad: Los módulos pueden adaptar la funcionalidad general a sus necesidades específicas.

  4. Mantenibilidad: Los cambios en un módulo no afectan a otros módulos o al sistema general.

  5. Escalabilidad: Es fácil añadir nuevos módulos o extender la funcionalidad existente.

  6. 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.