padrão para compartilhar objetos entre API e aplicativo

9

Estou com sérias dúvidas sobre o design do meu aplicativo Web.

Eu queria separar a lógica de negócios da interface, então criei uma API da Web que lida com todas as solicitações ao banco de dados.

É uma API da Web do ASP.NET com estrutura de entidade e uma unidade de trabalho e padrão de repositório genérico. Até agora, tudo está bem.

PROBLEMA

Onde eu preciso de ajuda é que não consigo descobrir uma maneira eficiente de compartilhar objetos entre a API e o aplicativo.

Não quero serializar diretamente o objeto da entidade, pensei que seria uma prática ruim porque, se o modelo da entidade mudar, eu poderia acabar serializando objetos grandes sem motivo.

Como é implementado agora

Como minha interface é um aplicativo Web do ASP.NET em C # e minha API está em C #, criei uma biblioteca comum com a definição de todas as minhas classes que quero compartilhar entre elas.

Sei que a solução não funcionará quando desenvolver um aplicativo para Android. Terei que criar minhas aulas novamente em Java, mas esse não é o meu maior problema.

O problema é que sinto que estou sempre convertendo meus objetos.

EXEMPLO

Aqui está um exemplo do meu fluxo de trabalho:

Começo com um modelo com todos os objetos e as anotações de dados para o meu formulário, em seguida, o usuário colocaria esse modelo em um controlador.

No controlador, tenho que converter esse modelo em uma classe na minha biblioteca comum e depois enviar esse objeto para minha API.

Em seguida, um controlador na minha API captura a chamada e converte esse objeto em um objeto de entidade para atualizar o banco de dados.

Então eu tenho 3 aulas

  1. O modelo para a visualização com todas as anotações de dados para a validação (Cliente)
  2. As classes de biblioteca comuns para compartilhar os objetos (DLL)
  3. As classes de entidade (API)

Tenho a sensação de que faço algo realmente errado. Existe algo mais elegante? Gostaria de ter uma boa solução para esse problema antes que o projeto fique grande demais.

Marc
fonte
Se minha pergunta não estiver clara, não hesite em fazer perguntas.
Marc
Para mim, não está claro qual arquitetura você implementou (talvez seja o texto .net que me intriga) - é uma arquitetura de três camadas: cliente, servidor, banco de dados?
Andy
Sim, eu tenho um aplicativo Web que usa uma API Web. A API é a que possui a lógica de negócios com o banco de dados.
Marc

Respostas:

12

Sei que pode parecer que você está convertendo objetos o tempo todo entre objetos do banco de dados, objetos de transferência de dados, objetos do cliente com lógica de validação e assim por diante, mas eu diria que não, você não está fazendo nada errado .

Cada um desses objetos pode representar a mesma unidade de informação, mas eles têm responsabilidades muito diferentes. O objeto de banco de dados é sua interface de comunicação com o banco de dados e deve ser mantido na camada de banco de dados, pois pode ou não ter diferentes anotações de metadados e / ou detalhes desnecessários sobre a implementação do banco de dados.

Seu objeto de transferência de dados é a interface de comunicação com os consumidores da API. Devem ser o mais limpos possível para facilitar o consumo fácil de diferentes idiomas / plataformas. Isso pode impor certas restrições sobre a aparência e o comportamento delas, dependendo de quais consumidores de API você deseja oferecer suporte.

Seus objetos de cliente com lógica de validação realmente não fazem parte do seu projeto de API, eles fazem parte do seu projeto de consumidor. Estes não podem ser iguais aos objetos de transferência de dados nesse caso, pois você está adicionando lógica extra específica do cliente (neste caso, atributos de validação) sobre os quais o servidor não sabe nada (e não deve saber nada!). Você não deve conte esses objetos como parte da sua API, porque eles realmente não são. Eles são altamente específicos para aplicativos de consumo e alguns aplicativos que consomem sua API podem até não precisar criar esses objetos e podem sobreviver apenas nos objetos de transferência de dados. Por exemplo, se você não precisou de validação, não precisaria de uma camada extra de objetos que sejam completamente idênticos aos seus objetos de transferência de dados.

Para mim, parece que cada um dos três tipos de objetos é muito bem mapeado para uma única responsabilidade, que é a codificação limpa e as boas práticas. Infelizmente, código limpo e boas práticas às vezes significa que você está escrevendo muito código extra e pulando em bastidores extras "apenas porque". E durante a codificação, pode ser difícil apreciar o valor que isso está dando a você - mas assim que você libera seu aplicativo e começa a apoiá-lo ou a adicionar novos recursos para a próxima versão, provavelmente começará a perceber que demorou um pouco para separar essas preocupações adequadamente em primeiro lugar. (Sem mencionar que você '

Eu também odeio escrever código de conversão entre diferentes tipos de objetos como este, mas minha solução é geralmente uma das seguintes:

  • Use uma biblioteca que faça a maior parte do trabalho pesado de conversão de objetos para você - por exemplo, se você usa C #, pode usar a fantástica biblioteca AutoMapper ( http://automapper.org/ ). Acredito que existem algumas outras bibliotecas como essa, mas o AutoMapper é a mais poderosa que já vi até agora.
  • Se você não conseguir encontrar uma biblioteca para ajudá-lo nas conversões de objetos, escreva um conjunto de métodos utilitários para a conversão entre eles. Isso pode ser péssimo, mas vale a pena a longo prazo, escreva o método de conversão na primeira vez que você precisar converter algo - não espere.
wasatz
fonte
Obrigado por suas explicações, mas ainda acho difícil entender alguma coisa. Não entendo por que a camada para transferência de dados não tem validação? E se eu esquecer algumas validações para meu próximo aplicativo móvel? Pelo menos, não valida quando chamo a API, em vez de fazer uma exceção no meu modelo de banco de dados. Não tenho certeza se entendi.
Marc
11
Não estou dizendo que você não deve validar no nível da API. Para ser honesto, esse é o local mais importante para validar. A validação no seu aplicativo é apenas um "recurso interessante" para ajudar seus usuários a não cometer erros. A validação dos objetos de transferência de dados é para manter fora os dados maliciosos e errôneos. Desde que estes são diferentes casos de uso no entanto, você pode precisar usar diferentes quadros de validação (você vai usar diferentes estruturas de validação se o seu aplicativo e sua API não está escrito na mesma língua) e você pode validar as coisas um pouco diferentes em cada nível (Cont no próximo comentário)
wasatz
11
Portanto, você deve validar seus objetos de transferência de dados. Mas você também deve se certificar de que a maneira como você os valida não introduz acidentalmente nenhuma dependência em nenhuma outra estrutura . E, é claro, como eu disse anteriormente, você realmente não pode ter certeza de que seus objetos de transferência de dados foram validados ou que foram validados pela mesma estrutura - portanto, você deve "validar duas vezes".
Wasatz
2
Principalmente, você deve tentar visualizar seu aplicativo e sua API como dois aplicativos completamente diferentes e separados. Você pode desenvolvê-los ao mesmo tempo e eles podem estar no mesmo projeto de solução / eclipse do visual studio. Mas eles são realmente dois programas completamente separados. Quando você estiver trabalhando em seu aplicativo, tente "esquecer" que você é quem criou a API e use-a exatamente como faria com uma API de terceiros normal. Dessa forma, você terá uma chance melhor de ver como os outros se sentirão ao usar sua API e corrigir as piores partes desde o início.
Wasatz
11
E o mesmo é claro quando se trabalha no seu projeto de API, tente imaginar que você está escrevendo um serviço que muitos desenvolvedores de terceiros vão usar. Tente não pensar muito em seu aplicativo atual, mas lembre-se mais de "quais serviços estou fornecendo" e supondo que todos que estão usando sua API (incluindo você) são pessoas más que estão tentando matar seu servidor e faça você excluir todo o banco de dados.
Wasatz