Estoy trabajando en un proyecto en el que estamos tratando de aplicar tanto el diseño basado en dominio como REST a una arquitectura orientada a servicios. No nos preocupamos por el 100% de cumplimiento de REST; probablemente sería mejor decir que estamos tratando de construir API HTTP orientadas a recursos (~ Nivel 2 del modelo de madurez REST de Richardson). Sin embargo, estamos tratando de mantenernos alejados del uso de solicitudes HTTP al estilo RPC, es decir, intentamos implementar nuestros verbos HTTP de acuerdo con RFC2616 en lugar de POST
hacerlo IsPostalAddressValid(...)
, por ejemplo.
Sin embargo, un énfasis en esto parece estar a expensas de nuestro intento de aplicar un diseño basado en dominio. Con solamente GET
, POST
, PUT
, DELETE
y algunos otros métodos de uso poco frecuente, que tienden a crear servicios sucia, sucia y los servicios tienden a tener modelos de dominio anémicos.
POST
: Reciba los datos, valídelos, vuélvalos a los datos. GET
: Recupere los datos, devuélvalos. No hay lógica de negocios real allí. También usamos mensajes (eventos) entre los servicios, y me parece que la mayor parte de la lógica de negocios termina construyéndose alrededor de eso.
¿Están REST y DDD en tensión en algún nivel? (¿O estoy malinterpretando algo aquí? ¿Tal vez estamos haciendo algo más mal?) ¿Es posible construir un modelo de dominio sólido en una arquitectura orientada a servicios mientras evito las llamadas HTTP de estilo RPC?
IsPostalAddressValid(...)
encajaría con "Proporcionar un bloque de datos, como el resultado de enviar un formulario, a un proceso de manejo de datos"?Respuestas:
Primera ley de Martin Fowler de sistemas distribuidos: "¡No distribuyas tus objetos!" Las interfaces remotas deben ser de grano grueso y las interfaces internas de grano fino. A menudo, el modelo de dominio rico solo se aplica dentro de un contexto acotado .
REST API separa dos contextos diferentes, ambos con sus propios modelos internos. Los contextos se comunican a través de la interfaz de grano grueso (REST API) utilizando objetos "anémicos" (DTO).
En su caso, parece que está tratando de extender un contexto sobre un límite que es REST API. Esto puede conducir a una interfaz remota de grano fino o un modelo anémico. Dependiendo de su proyecto, puede o no ser un problema.
fuente
POST fue diseñado deliberadamente para ser "intencionalmente vago"; El resultado de un POST es específico de la implementación. ¿Qué le impide hacer lo que hacen Twitter y otros diseñadores de API, y definir cada método POST en la parte no CRUD de su API de acuerdo con sus propios requisitos específicos? POST es el verbo general. Úselo cuando ninguno de los otros verbos encaja bien con la operación que desea realizar.
Para decirlo de otra manera, su pregunta podría plantearse igualmente como "¿Los objetos 'inteligentes' fomentan el diseño de estilo RPC?" Incluso Martin Fowler (quien acuñó el término "Modelo de dominio anémico") reconoce que los DTO desnudos tienen algunos beneficios:
Con respecto al modelo de madurez de Richardson , puede llegar al nivel 3 sin preocuparse por los "modelos de dominio anémico". Recuerde, nunca va a transferir el comportamiento al navegador (a menos que planee inyectar algún Javascript a través de sus modelos).
REST se trata principalmente de independencia de la máquina; implemente el modelo REST en la medida en que desee que sus puntos finales representen recursos, y para que los consumidores de su API puedan acceder y mantener fácilmente esos recursos de manera estándar. Si eso parece anémico, que así sea.
Ver también
Necesito más verbos
fuente
REST API es solo un tipo de capa de presentación. No tiene nada que ver con el modelo de dominio.
La pregunta que publicó proviene de su confusión de que de alguna manera necesita adaptarse el uno al otro. Usted no
Usted asigna su modelo de dominio a su API REST de la misma manera que asigna su modelo de dominio a un RDBMS a través de un ORM: tiene que haber esta capa de asignación.
Dominio ← ORM →
Dominio RDBMS ← Mapeo REST → API REST
fuente
En mi humilde opinión, no creo que tiendan a fomentar los modelos de dominio anémico (ADM), pero requieren que te tomes un tiempo y pienses bien.
En primer lugar, creo que la característica principal de los ADM es que tienen poco o ningún comportamiento en ellos. Eso no quiere decir que el sistema no tenga comportamiento, solo que generalmente está en algún tipo de clase de Servicio (consulte http://vimeo.com/43598193 ).
Y, por supuesto, si el comportamiento no existe en el ADM, ¿qué existe? La respuesta, por supuesto, son los datos. Y entonces, ¿cómo se correlaciona con REST API? Bueno, presumiblemente los datos se asignan al contenido del recurso, y el comportamiento se asigna a los verbos HTTP.
Entonces, tiene todo lo que necesita para construir un modelo de dominio rico, solo tiene que poder ver cómo los verbos HTTP se asignan a las operaciones de dominio en los datos, y luego colocar esas operaciones en las mismas clases que encapsulan sus datos.
Creo que las personas tienden a encontrarse con problemas es que les resulta difícil ver cómo los verbos HTTP se asignan a su comportamiento de dominio cuando el comportamiento está más allá del CRUD simple, es decir, cuando hay efectos secundarios en otras partes del dominio más allá del recurso modificado por la solicitud HTTP. Una forma de resolver ese problema es con los eventos de dominio ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).
fuente
Este artículo está bastante relacionado con el tema y creo que responde a su pregunta.
Un concepto central que creo que responde muy bien a su pregunta, se resume en el siguiente párrafo del artículo mencionado:
"Es muy importante distinguir entre recursos en API REST y entidades de dominio en un diseño dirigido por dominio. El diseño dirigido por dominio se aplica al lado de la implementación de las cosas (incluida la implementación API) mientras que los recursos en API REST dirigen el diseño y el contrato API. Recurso API la selección no debe depender de los detalles de implementación del dominio subyacente ".
fuente
Varias implementaciones razonablemente exitosas que he visto / construido responden a la pregunta de cómo mezclan la metáfora verbo + sustantivo utilizando métodos 'amigables para los negocios' de grano grueso que actúan sobre las entidades.
Entonces, en lugar del
getName()
método / servicio (condenado) , expongagetPerson()
, pasando cosas como identificador-tipo / ID, devolviendo toda laPerson
entidad.Dado que los comportamientos de la entidad Persona en dicho contexto no pueden transmitirse adecuadamente (ni quizás deberían estar en un contexto centrado en los datos como este), es perfectamente razonable definir un modelo de datos (versus Objeto) para los pares de solicitud / respuesta de los servicios.
Los servicios y los verbos definidos agregarán algunos comportamientos, controles e incluso reglas de transición de estado para las entidades permitidas por el dominio. Por ejemplo, habría una lógica específica de dominio sobre lo que sucede en la
transferPerson()
llamada de servicio, pero la interfaz misma solo definiría las entidades / datos de entrada / salida sin definir SUS comportamientos internos.No estaría de acuerdo con los autores que dirían, por ejemplo, que una implementación del verbo de transferencia pertenece a la clase Persona o está asociada con un servicio centrado en la Persona. De hecho, el método de transferencia para a
Person
y sus opciones (en este simple ejemplo) estaría mejor definido por aCarrier
, en el que esPerson
posible que ni siquiera sepan qué métodos de transferencia están disponibles o cómo se realiza la transferencia (quién sabe cómo funcionan los motores a reacción). de todas formas).¿Esto hace que la
Person
entidad sea anémica? No lo creo.Puede / debe haber lógica sobre cosas específicas de la Persona que son internas a la Persona, como su estado de salud, que no debe ser definida por una clase externa.
Sin embargo, dependiendo de los casos de uso, es completamente aceptable que una clase de entidad no tenga comportamientos importantes / relevantes en ciertos sistemas, como un servicio de asignación de asiento en un sistema de transporte. Tal sistema puede implementar servicios basados en REST que tratan con instancias de Persona e identificadores asociados pero nunca definen / implementan sus comportamientos internos.
fuente
¿Su problema es que está tratando de agrupar su modelo en el conjunto básico de verbos, utilizando POST tanto como sea posible?
No es necesario. Sé que para la mayoría de las personas, REST significa POST, GET, PUT y DELETE, pero el http rfc dice:
Y los sistemas como SMTP utilizan el mismo estilo de métodos basados en verbos pero con un conjunto totalmente diferente.
Por lo tanto, no hay ninguna razón por la que tenga que usar estos, puede usar cualquier conjunto de verbos que desee (sin embargo, realmente encontrará que puede hacer todo lo que necesita en los 4 básicos con un poco de reflexión). Lo que distingue a REST de los otros mecanismos es su forma sin estado y consistente de implementar estos verbos. No debe intentar implementar el sistema de paso de mensajes entre los niveles, ya que básicamente no está haciendo REST, sino que está haciendo un mecanismo de paso de mensajes, RPC o cola de mensajes que indudablemente le hará perder los beneficios de REST (es decir, el simplicidad que hace que funcione realmente bien en una conexión http).
Si desea un protocolo de mensajería complejo y con todas las funciones, compílelo (si puede hacerlo a través de la web, hay una razón por la cual REST es tan popular), pero de lo contrario intente atenerse al diseño arquitectónico de REST.
fuente