¿Cuál es una forma práctica de modelar tablas de búsqueda en Diseño impulsado por dominio (DDD)?

StackOverflow https://stackoverflow.com/questions/808481

  •  03-07-2019
  •  | 
  •  

Pregunta

Simplemente estoy aprendiendo DDD (el libro de Eric Evans está abierto frente a mí) y encontré un problema para el que no puedo encontrar una respuesta. ¿Qué hace en DDD cuando solo intenta obtener una lista simple de registros de búsqueda?

Ej.

EmployeeID: 123
Nombre del empleado: John Doe
Estado: Alaska (desplegable)
Condado: Wasilla (desplegable: se filtrará según el estado).

Por ejemplo, supongamos que tiene un objeto de dominio Employee, una interfaz IEmployeeRepository y una clase EmployeeRepository. Esto será utilizado por una UI para mostrar una lista de empleados y detalles individuales. En la UI, desea utilizar un menú desplegable para el estado y el condado donde vive el empleado. Los condados disponibles se filtrarán según el estado elegido.

Lamentablemente, las tablas de la base de datos y la interfaz de usuario se ven muy diferentes. En tblEmployees, contiene el código del estado = AK y el código del condado = 02130, no los nombres del estado y del condado.

La forma antigua (antes de comenzar esta búsqueda de DDD) sería bastante sencilla, solo crea 2 consultas y usa un DataReader para completar los menús desplegables. Debajo de la pantalla en los menús desplegables se encuentra el valor, que se utiliza automáticamente en las publicaciones de formularios.

Sin embargo, con DDD, no estoy seguro de cómo se supone que debes hacer esto. Comencé por crear objetos estatales y del condado, así como repositorios e interfaces para los repositorios. Sin embargo, escribir 4 clases + 2 interfaces y la plomería en los archivos hbm.xml + Employee Business objetos parece una exageración para solo 2 consultas para 2 menús desplegables. Tiene que haber una mejor manera, ¿no es así? No voy a cambiar los registros en las mesas del Estado o del Condado en ningún momento e incluso si lo hiciera, no sería a través de esta aplicación. Así que realmente no quiero crear objetos de negocios para el estado y el condado si no tengo que hacerlo.

La solución más sencilla que veo es simplemente crear una clase auxiliar con métodos que devuelvan diccionarios, como GetStatesAll (), GetState () y GetCounties () y GetCounty (), pero eso simplemente se siente mal desde la perspectiva de DDD.

Por favor ayuda. ¿Cómo puedo usar DDD sin sobrepasar en ingeniería solo un par de búsquedas simples?

Solución final Creo que finalmente encontré mi respuesta a través de la experiencia, que consistía en poner el método GetStates () en su propia clase de acceso a datos, aunque no en una clase de repositorio. Como solo estaba haciendo acceso de solo lectura, lo lancé a una estructura DTO. Como la base de datos era pequeña, los agrupé en una sola clase, como Todd describe a continuación.

Mis conclusiones:

  1. Las tablas de búsqueda NUNCA son objetos de valor, porque las tablas de búsqueda SIEMPRE tienen una identidad. Si no tuvieran una identidad, tendrías duplicados, lo cual no tendría mucho sentido.
  2. La tabla de búsqueda de solo lectura puede tener un repositorio, pero probablemente no lo necesite. El objetivo de un repositorio es reducir la complejidad al forzar el acceso solo a través del agregado. Ir a través del agregado le proporciona una manera de garantizar que las reglas comerciales se puedan hacer cumplir, como no agregar llantas si no tiene un automóvil.
  3. Si permite el mantenimiento de CRUD en la tabla de búsqueda, entonces tiene sentido que la tabla de búsqueda tenga su propio repositorio.
  4. El hecho de que terminé almacenando los códigos como estructuras no hace que los "tipos de valor" se conviertan en. Fowler dice en POEAA que una estructura es un tipo de valor. Es cierto, las estructuras son inmutables, por lo que Fowler dice que son "tipos de valor", sin embargo, las estaba usando de manera diferente. Estaba usando structs como una forma liviana de pasar los DTO que nunca planeé cambiar después de su creación inicial. En verdad, las estructuras que utilicé tenían, de hecho, identidades, pero como eran de solo lectura, funcionaban como estructuras.
  5. Un patrón que he estado usando y que no veo mucho en otra parte es hacer que los campos de la clave principal sean inmutables. Los establece el constructor, pero son de solo lectura (no son accesores privados) y no se pueden cambiar una vez que se crea el objeto.
¿Fue útil?

Solución

Es posible que desee ver el concepto de Separación de consulta de comando . No me preocuparía por los repositorios escritos para los valores de búsqueda, pero aún así probablemente usaría clases de tipo DTO sobre conjuntos de datos, etc ...

Es posible que desee pasar algún tiempo leyendo los blogs de Greg Young a partir de éste al presente. No habla de llenar los datos de búsqueda específicamente, pero a menudo habla de no manejar la funcionalidad de lectura / informe de su aplicación a través de métodos escritos en un repositorio.

Otros consejos

Al usar DDD tengo algo similar con lo siguiente:

interface IAddressService
{
  IList<Country> GetCountries ();
  IList<State> GetStatesByCountry (string country);
  IList<City> GetCitiesByState (string state);
  // snip
}

País, estado y ciudad son objetos de valor que provienen de una tabla de búsqueda en la base de datos.

Bueno, leí un artículo de Mathias Verraes hace algún tiempo hablando de esto here . Habla sobre Separar objetos de valor en el modelo de conceptos que sirven a la IU.

Cotización del artículo cuando se le pregunta si debe modelar los países como entidades u objetos de valor:

  

No hay nada intrínsecamente malo en modelar países como   Entidades y almacenamiento en la base de datos. Pero en la mayoría de los casos, eso   Complicar las cosas. Los países no cambian a menudo. Cuando un   el nombre del país cambia, es de hecho, para todos los propósitos prácticos, un   nuevo país. Si un país ya no existe un día, no puede   simplemente cambia todas las direcciones, porque posiblemente el país estaba dividido   en dos países.

Sugirió un enfoque diferente para introducir un nuevo concepto llamado AvailableCountry :

  

Estos países disponibles pueden ser entidades en una base de datos, registros en una   JSON, o incluso simplemente una lista codificada en su código. (Eso depende de   si la empresa quiere acceder fácilmente a ellos a través de una interfaz de usuario).

<?php

final class Country
{
    private $countryCode;

    public function __construct($countryCode)
    {
        $this->countryCode = $countryCode;
    }

    public function __toString()
    {
        return $this->countryCode;
    }
}

final class AvailableCountry
{
    private $country;
    private $name;

    public function __construct(Country $country, $name)
    {
        $this->country = $country;
        $this->name = $name;
    }

    /** @return Country */
    public function getCountry()
    {
        return $this->country;
    }

    public function getName()
    {
        return $this->name;
    }

}

final class AvailableCountryRepository
{
    /** @return AvailableCountry[] */
    public function findAll()
    {
        return [
            'BE' => new AvailableCountry(new Country('BE'), 'Belgium'),
            'FR' => new AvailableCountry(new Country('FR'), 'France'),
            //...
        ];
    }

    /** @return AvailableCountry */
    public function findByCountry(Country $country)
    {
        return $this->findAll()[(string) $country];
    }
}

Parece que hay una tercera solución que consiste en modelar tablas de consulta como objetos de valor y entidades.

Por cierto, asegúrese de verificar la sección de comentarios para algunas discusiones serias sobre el artículo.

El estado y el condado no son entidades, sino objetos de valor. No son el tema de su sistema. La forma en que dijiste que trataste esto anteriormente está bien. ¿Cuándo cambiará los registros del estado o condado en su base de datos, en función de los cambios en el estado de su modelo de dominio? No, por lo que estos no necesitarán un repositorio.

Estás leyendo el libro equivocado si quieres aprender cómo hacer DDD sin complicarlo más. :-)

La solución más simple que está proponiendo está bien si satisface sus necesidades. La encapsulación de datos de direcciones en objetos comerciales puede ser tan simple o tan complicada como lo requiera su aplicación. Por ejemplo, el objeto del estado tiene una relación de uno a muchos con el condado, por lo que el empleado realmente solo necesita hacer referencia a un condado si decide modelarlo de esa manera. Solo introduciría ese tipo de complejidad si fuera necesario.

Además, no creo que haya mucho que ganar al definir interfaces para sus repositorios a menos que haya una posibilidad real de que tenga múltiples repositorios para sus objetos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top