WCF / SOA - Por que devo criar objetos de parâmetro para solicitações simples

12

Nossa empresa está iniciando uma iniciativa SOA bastante grande. Estamos fazendo muitas coisas certas: há uma boa comunicação; dinheiro para ferramentas, quando apropriado; e adquirimos uma boa experiência para nos ajudar na transição.

Estamos tentando desenvolver padrões que possamos seguir como um grupo, e um dos padrões propostos está me incomodando bastante:

Padronizamos o padrão em que toda operação pega um objeto de solicitação e retorna um objeto de resposta.

Percebo que essa é uma abordagem mais ou menos padrão para muitas pessoas, mas estou perguntando por que devo me preocupar. (Eu não sou tão bom com a sabedoria recebida, preciso do porquê).

A maioria dos serviços que fornecerei são simples recuperação de metadados organizacionais. Por exemplo, encontre a política de segurança para um usuário específico. Isso precisa de uma identificação de usuário e nada mais. O padrão diz que eu devo agrupar essa solicitação em um objeto e agrupar a política retornada em um objeto de resposta.

Meu mal-estar é amplificado pela análise do WSDL gerado a partir de nossos contratos. O WCF gera mensagens de solicitação e resposta automaticamente e agrupa até o objeto de solicitação / resposta.

Entendo perfeitamente que, se você estiver fazendo uma solicitação complexa, é necessário um objeto de entrada complexo. Isso é o que você faria mesmo se os serviços não estivessem envolvidos.

Minha pergunta é por que devo envolver automaticamente solicitações e respostas quando:

  • Torna os serviços simples menos expressivos
  • Você faria isso de qualquer maneira por um serviço complexo
  • O WCF cria uma mensagem de solicitação / resposta de qualquer maneira

Encontrei os seguintes argumentos a favor dessa abordagem:

Ele suporta controle de versão, permitindo que parâmetros opcionais sejam inseridos no objeto de solicitação.

Naquela época, eu fazia bastante COM, e consideraria isso quase um antipadrão para versionamento. Para algumas coisas, acho que ajudaria, mas espero que, onde ajudaria, você já tenha um objeto de parâmetro de qualquer maneira.

Permite que dados e comportamentos comuns sejam isolados em uma classe base

Este carrega algum peso comigo.

Afasta as pessoas de um comportamento no estilo RPC e em direção ao comportamento de mensagens

Eu li isso no site da Microsoft e o ouvi de nosso guru, mas ainda não tenho uma idéia clara do que eles significam ou por que é valioso. Será que as interfaces com aparência natural fazem as pessoas esquecerem que estão chamando um serviço remoto?

Eu estou olhando para refatorar as assinaturas de talvez 300 métodos, então isso é uma quantidade não trivial de dor. Sou um grande fã de consistência nas implementações, por isso estou disposto a enfrentar a dor, isso só ajudará a saber que tudo valerá a pena no final.

Andy Davis
fonte

Respostas:

3

Eu acho que o controle de versão é provavelmente o melhor argumento. Quando você tem um contrato de operação existente, como

int GetPersons(int countryId);

que você deseja aprimorar, por exemplo, por outro filtro mais tarde

int GetPersons(int countryId, int age);

Você precisaria escrever um novo contrato de operação e com um novo nome, pois ele precisa ser único. Ou você manteria o nome e publicaria uma nova v2 do seu serviço, com a antiga v1 ainda disponível para compatibilidade com versões anteriores.

Se você agrupar o parâmetro em um objeto, sempre poderá estendê-lo com parâmetros padrão / opcionais e todos os seus clientes existentes não serão afetados quando você reutilizar o mesmo contrato de operação.

No entanto, também gostaria de nomear seus objetos adequadamente. Mesmo que apenas envolva um int, se você começar com IntMessagealgo semelhante, não estará fazendo um favor a si próprio para estendê-lo. Você teria que nomeá-lo, por exemplo, PersonFilterdesde o início, o que significa que você deve pensar um pouco sobre o que essa chamada de serviço deve esperar como parâmetro semanticamente e, portanto, o que ela deve fazer. Talvez (e talvez seja muito vago) isso ajude no desenvolvimento dos serviços certos e mantenha uma API de tamanho decente.

Permite que dados e comportamentos comuns sejam isolados em uma classe base

Isso é algo para ser cauteloso. Contratos de herança e dados não combinam tão bem. Funciona, mas você terá que especificar todos os subtipos conhecidos do contrato que possam passar por cima do fio, caso contrário, o serializador do contrato de dados falhará ao reclamar sobre tipos desconhecidos.

Mas o que você poderia fazer (mas provavelmente ainda não deveria, ainda estou indeciso sobre isso) é reutilizar as mesmas mensagens entre diferentes serviços. Se você colocar os contratos de dados em uma dll separada, poderá compartilhá-lo entre cliente e serviço e não precisará converter entre tipos quando chamar serviços diferentes que esperam basicamente a mesma mensagem. Por exemplo, você cria um PersonFilter e o envia para um serviço para obter uma lista de filtros de pessoas e depois para outro serviço e ter os mesmos objetos no cliente. Não consigo encontrar um bom exemplo do mundo real para isso, e o perigo é sempre que uma extensão dos contratos de dados não seja geral o suficiente para todos os serviços que usam esse contrato.

No geral, além do controle de versão, também não consigo encontrar a principal razão para fazê-lo dessa maneira.

Andreas
fonte
Eu acho que a razão pela qual eu tomo o
Andy Davis
(desculpe, a interface de comentários está me deixando triste) Obrigado por responder. Eu acho que a razão pela qual eu tomo o argumento de versionamento com tanto grão de sal é que, se você adicionou um novo argumento, provavelmente mudou a semântica. Se (como no seu exemplo) você acabou de adicionar uma idade, provavelmente a semântica era para pesquisa e você tinha um "objeto de pesquisa" lá para começar.
Andy Davis
Agora considere meu exemplo de política de segurança. Talvez decidamos que, para fornecer adequadamente uma política de segurança, precisamos conhecer não apenas o usuário, mas também o recurso em que eles estão trabalhando. Isso é muito mais do que adicionar um argumento, alteramos a semântica da chamada. Supondo que, de alguma forma, possamos fornecer essas informações para um chamador da versão anterior, acho que faz mais sentido a versão do contrato de serviço. Em seguida, a implementação da versão antiga pode ser isolada e você não acaba misturando a semântica antiga com a nova.
Andy Davis
0

As anotações de Martin Fowler sobre o objeto de transferência de dados são apropriadas aqui, eu acho.

Quando você trabalha com uma interface remota, como Fachada remota (388), cada chamada é cara. Como resultado, você precisa reduzir o número de chamadas, e isso significa que você precisa transferir mais dados a cada chamada. Uma maneira de fazer isso é usar muitos parâmetros. No entanto, isso geralmente é complicado de programar - na verdade, muitas vezes é impossível com linguagens como Java que retornam apenas um único valor.

A solução é criar um objeto de transferência de dados que possa conter todos os dados da chamada. Ele precisa ser serializado para atravessar a conexão. Normalmente, um assembler é usado no servidor para transferir dados entre o DTO e qualquer objeto de domínio.

O mesmo pode se aplicar a solicitações. Quanto ao RPC, e por que é ruim:

Será que as interfaces com aparência natural fazem as pessoas esquecerem que estão chamando um serviço remoto?

Eu acho que é verdade, mas não a principal razão. Outro motivo para evitar o RPC é que ele pode incentivar clientes e serviços fortemente acoplados.

Kyle Hodgson
fonte
Obrigado pela contribuição, mas não acho que a discussão sobre o DTO seja relevante. É o mesmo número de chamadas e, se você observar o WSDL, tudo será empacotado automaticamente em um objeto de solicitação e resposta. A convenção é sobre semântica visível , ou seja, as pessoas devem pensar nisso como uma solicitação e resposta, em oposição a uma chamada de método remoto.
Andy Davis
Você gostaria de elaborar RPCs que incentivem clientes e serviços fortemente acoplados? Não vejo que isso afete o serviço. Para o cliente, também não vejo como algo realmente muda. Nos dois casos, tenho o cliente segurando um proxy que descreve várias operações fornecidas por um serviço. Quem realmente implementa o outro lado do serviço não é da conta do cliente.
Andy Davis