quickly - DDD, PHP. Objeto de dominio y lógica de negocios
domain driven design quickly (3)
He estado muy ocupado intentando comprender los conceptos de ddd y Model layer últimamente. Lea toneladas de artículos, ejemplos, Q y A, pasó muchas horas en él. Y todavía no estoy seguro de si tengo algunos principios correctos.
Una de ellas es la respuesta a la pregunta: ¿cuánta lógica comercial debería existir en los objetos de dominio? Algunas fuentes dicen que los Objetos de Dominio deberían estar conectados con toda la lógica de negocios, por otro lado, encontré artículos donde asumí que deberían ser lo más pequeños posible y solo representar sus valores. Me hace realmente confundido.
En mi comprensión, los objetos de dominio son clases, que representan entidades en el dominio.
Así que, por ejemplo, vamos con la entidad Factura. Cada factura consta de sus artículos. Para calcular el valor de la factura, debemos sumar todos los valores de los elementos (es un ejemplo muy simple, en el mundo real habría casos como agregar impuestos, calcular el valor pagado, etc.)
class Invoice
{
public $id;
public $items = [];
public $status;
const STATUS_PAID = ''paid'';
const STATUS_NOT_PAID = ''not_paid'';
public function isPaid()
{
return $this->status == self::STATUS_PAID;
}
public function getInvoiceValue()
{
$sum = 0;
foreach($this->items as $item) {
$sum += $item->value;
}
return $sum;
}
}
Según entiendo, el método isPaid () está en el lugar correcto. Se refiere a sus propios datos. Pero no estoy seguro acerca de getInvoiceValue (). Operamos aquí en otros objetos de dominio.
Tal vez deberíamos usar objetos de dominio solo para representar datos solamente, pero ¿usamos algunos decoradores para realizar tareas más avanzadas?
Gracias por adelantado.
¿Cuánta lógica comercial debería existir en los objetos de dominio? [...] encontré artículos en los que asumí que deberían ser lo más pequeños posible y solo representan sus valores.
Tenga cuidado con el modelo de dominio anémico que consiste casi exclusivamente en datos y carece de comportamiento. DDD se trata de crear un modelo de dominio rico en comportamiento. Por lo tanto, está bien agregar lógica en las clases de dominio.
DDD enfatiza el buen diseño orientado a objetos, juntando métodos e información, promoviendo sistemas altamente cohesivos .
No estoy seguro de si hay una respuesta correcta para este tipo de preguntas, porque la aplicación de DDD realmente depende del dominio particular al que lo está aplicando. Hay lugares donde su implementación podría ser perfectamente válida, si satisface las necesidades del negocio. En otros, como mencionó con impuestos y similares, no lo haría. Así que diría que debe seguir haciendo preguntas sobre su dominio para comprender completamente cuáles son sus necesidades antes de traducirlas a código.
Una vez dicho esto, si tiene un escenario más complejo que requiera algún conocimiento adicional del mundo externo para obtener el valor de una factura, una opción sería representarlo explícitamente en su dominio. En su ejemplo, podría ser un Facturador, que podría tener una firma como:
class InvoiceProducer {
public function __construct(TaxProvider $taxProvider) {
$this->taxProvider = $taxProvider;
}
public function invoiceFor(array $items) {
new Invoice($items, $this->calculateValue($items));
}
private function calculateValue(array $items) {
$sum = array_reduce($items, function($acc, $item){
$acc += $item->value;
}
return $this->taxProvider->applyTaxTo($sum);
}
}
Otra opción sería utilizar algún tipo de patrón de Estrategia, lo que dejaría su implementación muy similar a la forma en que es ahora, pero pasaría con su llamada de la forma que desee que se calculen los impuestos:
public function getInvoiceValue(TaxProvider $taxProvider)
{
$sum = 0;
foreach($this->items as $item) {
$sum += $item->value;
}
return $taxProvider->applyTaxFor($sum);
}
Una vez más, realmente depende de cómo funciona su dominio específico, pero, como puede ver, la implementación no debería ser tan grande. Es más acerca de cómo encaja todo dentro de su dominio.
¿Cuánta lógica comercial debería existir en los objetos de dominio?
Todo eso (si es posible). El objetivo de DDD es capturar la lógica de su negocio en su dominio: los diversos patrones tácticos se pueden usar aquí para ayudar (Agregados, Entidades, Objetos de valor, Servicios de dominio, etc.).
Los objetos de dominio son clases, que representan entidades en el dominio.
Las clases en su dominio pueden representar más que solo Entidades. Los agregados, las entidades, los objetos de valor, los servicios de dominio, etc. pueden estar representados por clases en su dominio.
Pero no estoy seguro acerca de getInvoiceValue (). Operamos aquí en otros objetos de dominio.
El ejemplo que da de Factura es un ejemplo clásico de un Agregado: la Factura contendría Facturas. getInvoiceValue () está bien aquí.
En nuestro caso, la factura es un agregado. La raíz agregada es la factura en sí misma, pero también es una entidad, ¿verdad? Sin embargo, tiene su propia identidad (el número de factura es único).
sí correcto
¿Qué son los Artículos de Factura entonces? ¿Puedo buscarlos directamente desde el repositorio de InvoiceItem (si debo crearlos), o siempre tengo que operar solo en Agregado?
Depende de tu caso de uso. Ayuda a separar los modelos de escritura y lectura (CQRS). Si está hablando del lado de lectura (es decir, informes), omite el modelo de dominio y tiene objetos que representan su modelo de lectura. Esto podría ser solo una consulta de base de datos. Si está hablando de su lado de escritura (es decir, comandos, dominio), entonces normalmente tendría un repositorio por raíz agregada. Cuáles son sus raíces agregadas es una pregunta de modelado. Desea crearlos de tal forma que apliquen todas las reglas de su negocio; en su ejemplo, si una Factura necesita cargar FacturasItems para hacer cumplir las reglas ("no más de 5 ítems por factura", por ejemplo) entonces sí, deben ser cargado a través de la raíz agregada