Servicestack – arquitetura e reutilização de POCOs para tudo

Refiro-me ao uso de reg do POCOs na documentação do ServiceStack:

Como ele promove código limpo e reutilizável, o ServiceStack sempre incentivou o uso de POCOs com código em primeiro lugar para quase tudo.

ou seja, o mesmo POCO pode ser usado:
Em Solicitação e Resposta DTO’s (no cliente e no servidor)
Em serializadores de texto JSON, JSV e CSV
Como o modelo de dados em OrmLite, db4o e NHibernate
Como as entidades armazenadas no Redis
Como gotas armazenadas em caches e sessões
Descartado e executado nos serviços do MQ ”

Eu amo serviços e como é fácil escrever serviços web com ele. Eu estou tentando entender a melhor forma de configurar o meu projeto e não me deparar com qualquer problema no futuro.

Especificamente, estou lutando com a idéia arquitetônica de retornar um object de resposta que também é um modelo de dados (como sugerido por SS). A ideia de separação de preocupações está fortemente enraizada dentro de mim. Ninguém vai ter problemas na estrada se você usar os mesmos POCOs para tudo. Não é “mais seguro”, por exemplo, retornar, por exemplo, exibir objects?

O maior inimigo do software

Primeiramente, quero fazer uma iteração de que as bases Complexity e Large Code são o pior inimigo do desenvolvimento de software e que, além de atender aos requisitos do projeto (ou seja, derivar valor de nosso software), gerenciar a complexidade e manter um código mínimo e fricto base deve estar na vanguarda de nossas mentes à medida que aprimoramos continuamente nosso software com novos resources e requisitos. Quaisquer diretrizes, regras ou processos que adicionamos para aumentar a qualidade do software devem ser focados diretamente no gerenciamento de sua complexidade essencial. Uma das melhores coisas que podemos fazer para reduzir a complexidade é reduzir o tamanho da base de código, ou seja, DRYing repeatable code e eliminar quaisquer abstrações desnecessárias, indireção, conceitos, tipos e atritos que não sejam absolutamente essenciais para a function do software.

Sob esse aspecto , a YAGNI é um dos melhores princípios a serem seguidos para garantir uma base de código simples e enxuta, concentrando-se no que é essencial para gerar valor.

Evite regras gerais

Evito “regras gerais” que considero uma das principais causas de complexidade desnecessária no Software, em que muitas vezes é aplicada liberal e impensadamente, infectando um código-base sem justificativa. Toda vez que você impõe uma limitação artificial, você está criando fricção e inércia para desenvolver dentro de seus limites a fim de satisfazê-lo, e é por isso que qualquer regra que você impõe deve ser cuidadosamente e cuidadosamente aplicada e limitada a lugares onde agregue valor.

Desconfie de regras e padrões inválidos

Mesmo os Padrões de Design de Software são, em muitos casos, deficiências de linguagem de programação , onde o que é útil em um idioma é desnecessário e mais elegantemente resolvido em linguagens mais expressivas e poderosas. Da mesma forma com “regras”, o que é uma diretriz de advertência em um domínio pode não ser aplicável em outros. Portanto, o que é mais importante do que a “regra” em si, é o valor que ela realmente fornece e o efeito colateral concreto que ela está tentando evitar. Uma vez que entendemos seu verdadeiro valor, podemos otimizar para extrair o máximo valor dele e, juntamente com a YAGNI, saber quando aplicá-lo seletivamente.

A vida simples do POCO

Como você percebeu, o ServiceStack alcança grande parte de sua simplicidade e reutilização, sendo capaz de reutilizar indiscriminadamente os mesmos POCOs em qualquer lugar para fazer interface e se comunicar livremente entre suas diferentes bibliotecas e componentes. Isso permite o máximo valor e a reutilização de seus modelos e reduz o atrito no mapeamento entre diferentes domínios que normalmente exigem tipos específicos de finalidade, cada um com sua própria configuração exclusiva, limitando sua aplicabilidade e potencial reutilização.

Modelos pesados ​​de ORM são DTOs ruins

Não reutilizar modelos de dados à medida que DTOs se aplicam a ORMs pesados, que incentivam modelos de dados com dependencies cíclicas e objects proxy com acoplamento forte e lógica incorporada que podem acionar o access não intencional de dados N + 1, tornando esses modelos candidatos insatisfatórios para uso como DTOs e por que você deve sempre copie-os em DTOs específicos de finalidade que seus Serviços podem retornar para que sejam serializáveis ​​sem problemas.

Limpe os POCOs

Os complexos modelos de dados armazenados no OrmLite ou no Redis não sofrem com nenhum desses problemas que podem usar POCOs limpos e desconectados. Eles são fracamente acoplados, onde apenas o “Shape” do POCO é significativo, ou seja, mover projetos e alterar namespaces não afetará a serialização, como ele é armazenado em tabelas RDBMS, estruturas de dados Redis, provedores de cache, etc. também não acoplado a tipos específicos, você pode usar um tipo diferente para inserir dados em OrmLite do que o que você usa para ler, nem precisa ser a “Forma exata”, pois o OrmLite pode preencher um DTO com apenas um subconjunto de os campos disponíveis na tabela subjacente. Também não há distinção entre os procedimentos Table, View ou Stored, o OrmLite terá todo o prazer em mapear qualquer conjunto de resultados em qualquer campo correspondente no POCO especificado, ignorando outros.

Efetivamente, isso significa que os POCOs no ServiceStack são extremamente resilientes e interoperáveis, para que você possa reutilizar os mesmos DTOs no OrmLite e vice-versa sem problemas. Se os modelos DTO e Data apenas se desviarem ligeiramente, você poderá ocultá-los de serem serializados ou armazenados em OrmLite com os atributos abaixo:

public class Poco { [Ignore] public int IgnoreInOrmLite { get; set; } [IgnoreDataMember] public int IgnoreInSerialization { get; set; } } 

Caso contrário, quando você precisar separá-los, por exemplo, mais campos foram adicionados à tabela RDBMS do que você deseja retornar, o DTO includeá campos adicionais preenchidos de fonts alternativas, ou você apenas desejará que seus Serviços os projetem de maneira diferente. Nesse ponto (YAGNI), você pode fazer uma cópia do DTO e adicioná-lo à Implementação de Serviços para que eles possam crescer separadamente, sem serem afetados por suas diferentes preocupações. Você pode então facilmente converter entre eles usando
Auto Mapping interno do ServiceStack , por exemplo:

 var dto = dbPoco.ConvertTo(); 

O Auto Mapping integrado também é muito tolerante e pode co-criar propriedades com diferentes tipos, por exemplo, para / de strings, tipos diferentes de coleção, etc.

Objetos de transferência de dados – DTOs

Portanto, se você estiver usando POCOs limpos e serializáveis ​​sem dependencies externas (por exemplo, de fonts OrmLite, Redis ou alt ServiceStack), você poderá reutilizá-los como DTOs e refazê-los livremente em modelos diferentes quando e como for necessário. Mas quando você está reutilizando Data Models como DTOs, eles ainda devem ser mantidos no projeto ServiceModel (também conhecido como DTO .dll), que deve conter todos os tipos que seu Serviço retorna. Os DTOs devem ser lógicos e independentes de dependencies, portanto, a única dependência que o projeto ServiceModel faz referência é o ServiceStack.Interfaces.dll impl-free, que, como é um PCL .dll, pode ser livremente referenciado em todas as plataformas .NET Mobile e Desktop .

Você deseja garantir que todos os tipos retornados por seus Serviços estejam no DTO .dll, já que isso, juntamente com a URL base de onde seus Serviços estão hospedados, é tudo o que é necessário para que seus Consumidores de Serviços saibam para consumir seus Serviços. Que eles podem usar com qualquer um dos .NET Service Clients para obter uma API Typed end-to-end sem code-gen, ferramentas ou qualquer outro maquinário artificial. Se os clientes preferirem o código-fonte, eles poderão usar a Referência do Add ServiceStack para acessar os DTOs typescripts pelos Servidores em sua plataforma preferida e idioma de sua preferência.

Serviços

Os serviços são a forma final de encapsular a complexidade e oferecem o mais alto nível de reutilização de software. Eles empacotam seus resources e os disponibilizam remotamente para seus consumidores, nunca com mais complexidade do que o custo de uma chamada de serviço.

Interface DTO vs Implementação de Serviço

Os DTOs são o que define o seu contrato de serviços, mantendo-os isolados de qualquer implementação do servidor é como o seu serviço é capaz de encapsular suas capacidades (que podem ser de complexidade ilimitada) e disponibilizá-los por trás de uma fachada remota. Ele separa o que seu Serviço fornece da complexidade de como ele o realiza. Ele define a API para seu Serviço e informa aos Consumidores de Serviço as informações mínimas que eles precisam saber para descobrir que funcionalidade seus Serviços fornecem e como consumi-los (mantendo uma function semelhante aos arquivos de Cabeçalho no código-fonte C / C ++). Contratos de serviços bem definidos, desacoplados da implementação, reforçam a interoperabilidade, garantindo que seus Serviços não imponham implementações específicas de clientes, garantindo que eles possam ser consumidos por qualquer Cliente HTTP em qualquer plataforma. Os DTOs também definem a forma e a estrutura do formato de conexão do seu Serviço, garantindo que eles possam ser desserializados de forma limpa em estruturas de dados nativas, eliminando o esforço de analisar manualmente as Respostas do Serviço.

Desenvolvimento de Cliente Paralelo

Como eles capturam todo o contrato, ele também permite que os clientes desenvolvam seus aplicativos antes que os Serviços sejam implementados, pois eles podem vincular seu aplicativo aos seus modelos DTO concretos e podem facilmente fazer com que seu cliente de Serviço retorne dados de teste até os Serviços de back-end. são implementados.

No que diz respeito às regras, garantir um Contrato de Serviço (DTOs) bem definido, separado de sua implementação, vai para a essência do que é um Serviço e o valor que ele fornece.

DTOs de solicitação e resposta

Quanto a quais DTOs são bons candidatos para reutilização como Modelos de Dados, você não quer usar Solicitar DTOs para nada além de definir sua API de Serviços externa que é tipicamente um Verbo que é idealmente agrupado por Semântica de Chamadas e Tipos de Resposta , por exemplo:

 public class SearchProducts : IReturn { public string Category { get; set; } public decimal? PriceGreaterThan { get; set; } } 

Suas tabelas RDBMS são normalmente entidades definidas como Substantivos , ou seja, o que seu Serviço retorna:

 public class SearchProductsResponse { public List Results { get; set; } public ResponseStatus ResponseStatus { get; set; } } 

Até mesmo o Response DTO contendo que define o que seu Serviço retorna não é um bom candidato para reutilização como um Modelo de Dados. Eu costumava usar DTOs discretos para respostas de serviço, pois permite estender livremente os serviços existentes para retornar dados ou metadados extras sem prejudicar os clientes existentes.

Além dos DTOs de solicitação e resposta, todos os outros tipos que seu serviço retorna seriam candidatos para reutilização como modelos de dados, o que eu faço com frequência, mantendo-os no projeto ServiceModel pelos motivos acima.