Estou trabalhando em um projeto no qual estamos tentando aplicar o design controlado por domínio e o REST a uma arquitetura orientada a serviços. Não estamos preocupados com 100% de conformidade com REST; provavelmente seria melhor dizer que estamos tentando criar APIs HTTP orientadas a recursos (~ Nível 2 do modelo de maturidade REST de Richardson). No entanto, estamos tentando ficar longe do uso de estilo RPC de pedidos HTTP, ou seja, nós tentativa de implementar a nossa HTTP verbos de acordo com RFC2616 em vez de usar POST
a fazer IsPostalAddressValid(...)
, por exemplo.
No entanto, uma ênfase nisso parece estar à custa de nossa tentativa de aplicar o design orientado a domínio. Com apenas GET
, POST
, PUT
, DELETE
e alguns outros métodos usados raramente, tendemos a criar serviços fétido e serviços fétido tendem a ter modelos de domínio anêmicos.
POST
: Receba os dados, valide-os e despeje-os nos dados. GET
: Recupere os dados, devolva-os. Nenhuma lógica de negócios real lá. Também usamos mensagens (eventos) entre os serviços, e me parece que a maior parte da lógica de negócios acaba sendo construída em torno disso.
REST e DDD estão em tensão em algum nível? (Ou estou entendendo errado algo aqui? Talvez esteja fazendo algo errado?) É possível criar um modelo de domínio forte em uma arquitetura orientada a serviços, evitando chamadas HTTP no estilo RPC?
IsPostalAddressValid(...)
isso se encaixaria em "Fornecer um bloco de dados, como o resultado do envio de um formulário, para um processo de manipulação de dados"?Respostas:
Primeira lei de sistemas distribuídos de Martin Fowler: "Não distribua seus objetos!" As interfaces remotas devem ter granulação grossa e as internas, com granulação fina. Geralmente, o modelo de domínio avançado se aplica apenas a um contexto limitado .
A API REST separa dois contextos diferentes, ambos com seus próprios modelos internos. Os contextos se comunicam por meio de interface de granulação grossa (API REST) usando objetos "anêmicos" (DTO).
No seu caso, parece que você está tentando espalhar um contexto por um limite que é a API REST. Isso pode levar a interface remota refinada ou modelo anêmico. Dependendo do seu projeto, pode ou não ser um problema.
fonte
O POST foi deliberadamente projetado para ser "intencionalmente vago"; o resultado de um POST é específico da implementação. O que impede você de fazer o que o Twitter e outros designers de API fazem e define cada método POST na parte não-CRUD da sua API de acordo com seus próprios requisitos específicos? POST é o verbo catchall. Use-o quando nenhum dos outros verbos for adequado para a operação que você deseja executar.
Em outras palavras, sua pergunta pode ser igualmente colocada como "Os objetos 'inteligentes' incentivam o design no estilo RPC?" Até Martin Fowler (que cunhou o termo "Modelo de Domínio Anêmico") reconhece que os DTOs nus têm alguns benefícios:
Com relação ao Modelo de Maturidade de Richardson , você pode chegar ao nível 3 sem se preocupar com "Modelos de Domínio Anêmicos". Lembre-se de que você nunca transferirá o comportamento para o navegador (a menos que planeje injetar algum Javascript nos seus modelos).
REST é principalmente sobre independência de máquina; implemente o modelo REST na medida em que você deseja que seus terminais representem recursos e para que os consumidores de sua API possam acessar e manter esses recursos facilmente de maneira padrão. Se isso parece anêmico, que assim seja.
Veja também
Preciso de mais verbos
fonte
A API REST é apenas um tipo de camada de apresentação. Não tem nada a ver com o modelo de domínio.
A pergunta que você postou vem da sua confusão de que, de alguma forma, você precisa se adaptar um ao outro. Você não
Você mapeia seu modelo de domínio para sua API REST da mesma maneira que mapeia seu modelo de domínio para um RDBMS por meio de um ORM - deve haver essa camada de mapeamento.
Domínio ← ORM →
Domínio RDBMS ← Mapeamento REST → API REST
fonte
IMHO Eu não acho que eles tendem a incentivar modelos de domínio anêmico (ADMs), mas exigem que você reserve um tempo e pense sobre as coisas.
Antes de tudo, acho que a principal característica dos ADMs é que eles têm pouco ou nenhum comportamento neles. Isso não quer dizer que o sistema não tenha comportamento, apenas que ele geralmente está em algum tipo de classe de serviço (consulte http://vimeo.com/43598193 ).
E, claro, se o comportamento não existe na ADM, o que existe? A resposta, é claro, são os dados. E como isso é mapeado para a API REST? Presumivelmente, os dados são mapeados para o conteúdo do recurso e o comportamento é mapeado para os verbos HTTP.
Portanto, você tem tudo o que precisa para criar um modelo de domínio avançado, apenas precisa ver como os verbos HTTP são mapeados para as operações de domínio nos dados e depois colocar essas operações nas mesmas classes que encapsulam seus dados.
Acho que onde as pessoas tendem a ter problemas é que elas têm dificuldade em ver como os verbos HTTP são mapeados para o comportamento de seu domínio quando o comportamento está além do simples CRUD, ou seja, quando há efeitos colaterais em outras partes do domínio além do recurso sendo modificado pela solicitação HTTP. Uma maneira de resolver esse problema é com eventos de domínio ( http://www.udidahan.com/2009/06/14/domain-events-salvation/ ).
fonte
Este artigo está bastante relacionado ao assunto e acredito que responde à sua pergunta.
Um conceito central que acho que responde muito bem à sua pergunta está resumido no parágrafo a seguir do artigo mencionado:
"É muito importante distinguir entre recursos na API REST e entidades de domínio em um design controlado por domínio. O design controlado por domínio se aplica ao lado da implementação (incluindo a implementação da API), enquanto os recursos na API REST conduzem o design e o contrato da API. Recurso da API a seleção não deve depender dos detalhes de implementação do domínio subjacente ".
fonte
Várias implementações razoavelmente bem-sucedidas que eu já vi / construíram respondem à pergunta de como elas misturam a metáfora verbo + substantivo usando métodos grosseiros 'amigáveis aos negócios' que atuam nas entidades.
Portanto, em vez do
getName()
método / serviço (condenado) , exponhagetPerson()
, passando coisas como ID / tipo identificador, retornando aPerson
entidade inteira .Como os comportamentos da entidade Pessoa em tal contexto não podem ser transmitidos adequadamente (nem talvez devam estar em um contexto centrado em dados como esse), é perfeitamente razoável definir um modelo de dados (versus Objeto) para os pares de solicitação / resposta de os serviços.
Os próprios serviços e verbos definidos adicionarão alguns comportamentos, controles e até regras de transição de estado permitidos para o domínio para as entidades. Por exemplo, haveria uma lógica específica do domínio sobre o que acontece na
transferPerson()
chamada de serviço, mas a própria interface definiria apenas as entradas / entidades / dados de saída sem definir SEUS comportamentos internos.Eu discordaria dos autores que diriam, por exemplo, que uma implementação de verbo de transferência pertence à classe Person ou associada a um serviço centrado em Person. De fato, o método de transferência para
Person
ae suas opções (neste exemplo simples) seria melhor definido por aCarrier
, em que o usuárioPerson
pode não ter conhecimento nem de quais métodos de transferência estão disponíveis ou como a transferência ocorre (quem sabe como os motores a jato funcionam de qualquer forma).Isso torna a
Person
entidade anêmica? Acho que não.Pode / deve haver lógica sobre coisas específicas da Pessoa que são internas à Pessoa, como seu estado de saúde, que não deve ser definido por uma classe externa.
No entanto, dependendo dos casos de uso, é inteiramente aceitável que uma classe de entidade não tenha comportamentos importantes / relevantes em certos sistemas, como um serviço de atribuição de assento em um sistema de transporte. Esse sistema pode implementar serviços baseados em REST que lidam com instâncias de Pessoa e identificadores associados, mas nunca definem / implementam seus comportamentos internos.
fonte
Seu problema é que você está tentando incluir seu modelo no conjunto básico de verbos, usando o POST o máximo possível?
Não é necessário - eu sei que para a maioria das pessoas REST significa POST, GET, PUT e DELETE, mas o http rfc diz:
E sistemas como o SMTP usam o mesmo estilo de métodos baseados em verbos, mas com um conjunto totalmente diferente.
Portanto, não há razão para você usá-los; você pode usar qualquer conjunto de verbos que desejar (no entanto, na verdade, você descobrirá que pode fazer tudo o que precisa nos 4 básicos com um pouco de reflexão). O que diferencia o REST dos outros mecanismos é sua maneira sem estado e consistente de implementar esses verbos. Você não deve tentar implementar o sistema de passagem de mensagens entre as camadas, pois, basicamente, não está fazendo o REST; em vez disso, está usando um mecanismo de passagem de mensagens, RPC ou fila de mensagens que, sem dúvida, perderá os benefícios do REST (ou seja, o simplicidade que faz com que funcione muito bem em uma conexão http).
Se você deseja um protocolo de mensagens complexo e com todos os recursos, crie-o (se você puder fazer isso pela Web, há uma razão pela qual o REST é tão popular), mas tente manter o design arquitetônico do REST.
fonte