architecture servicestack separation-of-concerns

architecture - Servicestack: arquitectura y reutilización de POCO para todo



separation-of-concerns (1)

Me refiero a la documentación de ServiceStack sobre el uso de POCO:

Dado que promueve código limpio y reutilizable, ServiceStack siempre ha alentado el uso de POCO de código primero para casi todo.

es decir, se puede usar el mismo POCO:
DTO de solicitud y respuesta (en cliente y servidor)
En serializadores de texto JSON, JSV y CSV
Como modelo de datos en OrmLite, db4o y NHibernate
Como las entidades almacenadas en Redis
Como blobs almacenados en cachés y sesiones
Caído y ejecutado en los servicios de MQ "

Me encanta la pila de servicios y lo fácil que es escribir servicios web con ella. Estoy tratando de entender la mejor manera de configurar mi proyecto y no tener ningún problema en el futuro.

Específicamente, estoy luchando con la idea arquitectónica de devolver un objeto de respuesta que también es un modelo de datos (como lo sugiere SS). La idea de la separación de las preocupaciones está muy arraigada en mí. Uno no se encontrará con problemas en el futuro si utiliza los mismos POCO para todo. ¿No es "más seguro" devolver, por ejemplo, ver objetos en su lugar?


El mayor enemigo del software

En primer lugar, quiero repetir que las bases de Complejidad y Código grande son el peor enemigo del desarrollo de software y que, junto con el cumplimiento de los requisitos del proyecto (es decir, obtener valor de nuestro software), gestionar la complejidad y mantener un código evolutivo mínimo y de baja fricción La base debe estar a la vanguardia de nuestras mentes, ya que estamos mejorando continuamente nuestro software con nuevas características y requisitos. Cualquier pauta, regla o proceso que agreguemos para aumentar la calidad del software debe centrarse directamente en la gestión de su complejidad esencial. Una de las mejores cosas que podemos hacer para reducir la complejidad es reducir el tamaño de la base del código, es decir, SECAR el código repetible y eliminar cualquier abstracción innecesaria, indirección, conceptos, tipos y fricciones que no sean absolutamente esenciales para la función del software.

YAGNI este punto de vista, YAGNI es uno de los mejores principios a seguir para garantizar una base de código simple y YAGNI al enfocarse en lo que es esencial para entregar valor.

Evita las reglas generales

Evito las "reglas generales", que considero una de las principales causas de la complejidad innecesaria en el Software, donde a menudo se aplica de forma liberal e irreflexiva, infectando una base de código sin justificación. Cada vez que impones una limitación artificial, estás creando fricción e inercia para desarrollarse dentro de sus límites con el fin de satisfacerla, razón por la cual cualquier regla que apliques debe aplicarse cuidadosamente y cuidadosamente y limitarse a los lugares donde agrega valor.

Tenga cuidado con las reglas y patrones no válidos

Incluso los patrones de diseño de software son en muchos casos deficiencias de lenguaje de programación , donde lo que es útil en un idioma es innecesario y se resuelve de manera más elegante en lenguajes más expresivos y potentes. Del mismo modo con las "reglas", lo que es una guía de precaución en un dominio puede no ser aplicable en otros. Por lo tanto, lo que es más importante que "la regla" en sí misma, es el valor que realmente proporciona y qué efecto secundario concreto está tratando de evitar. Una vez que comprendamos su verdadero valor, podemos optimizar para obtener el máximo valor y, junto con YAGNI, saber cuándo aplicarlo selectivamente.

La vida simple de POCO

Como ha notado, ServiceStack logra gran parte de su simplicidad y reutilización al poder reutilizar los mismos POCO indiscriminadamente en cualquier lugar para interactuar y comunicarse libremente entre sus diferentes bibliotecas y componentes. Esto permite el máximo valor y la reutilización de sus modelos y reduce la fricción en el mapeo entre diferentes dominios que generalmente requieren tener tipos específicos para cada propósito, cada uno con su propia configuración única que limita su aplicabilidad y posible reutilización.

Los modelos ORM pesados ​​son DTO pobres

No reutilizar los modelos de datos como DTO se aplica a los ORM pesados ​​que alientan a los Modelos de datos con dependencias cíclicas y objetos proxy con acoplamiento estrecho y lógica incrustada que pueden desencadenar el acceso no intencionado a datos N + 1, lo que hace que estos modelos sean malos candidatos para su uso como DTO y por qué siempre debe cópielos en DTO específicos de propósito que sus Servicios pueden devolver para que sean serializables sin problema.

POCO limpios

Los complejos modelos de datos almacenados en OrmLite o Redis no sufren ninguno de estos problemas que pueden utilizar POCO limpios y desconectados. Están acoplados libremente, donde solo la "Forma" del POCO es significativa, es decir, mover proyectos y cambiar los espacios de nombres no afectará la serialización, cómo se almacena en tablas RDBMS, estructuras de datos Redis, proveedores de almacenamiento en caché, etc. tampoco está asociado a tipos específicos, puede usar un tipo diferente para insertar datos en OrmLite que el que usa para leer de él, ni necesita ser la "Forma exacta", ya que OrmLite puede llenar un DTO con solo un subconjunto de Los campos disponibles en la tabla subyacente. Tampoco hay distinción entre la tabla, la vista o el procedimiento almacenado, OrmLite felizmente correlacionará cualquier conjunto de resultados en cualquier campo coincidente en el POCO especificado, ignorando otros.

Efectivamente, esto significa que los POCO en ServiceStack son extremadamente resistentes e interoperables, por lo que puede volver a usar los mismos DTO en OrmLite y viceversa sin problemas. Si los modelos DTO y Data solo se desvían ligeramente, puede ocultarlos para que no se serialicen o almacenen en OrmLite con los siguientes atributos:

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

De lo contrario, cuando necesite separarlos, por ejemplo, se agregaron más campos a la tabla RDBMS de los que desea devolver, el DTO incluye campos adicionales poblados de fuentes alternativas, o simplemente desea que sus Servicios los proyecten de manera diferente. En ese momento (YAGNI), puede tomar una copia del DTO y agregarla a su Implementación de servicios para que puedan crecer por separado, sin obstáculos por sus diferentes preocupaciones. Luego puede convertir sin esfuerzo entre ellos usando
El mapeo automático incorporado de ServiceStack , por ejemplo:

var dto = dbPoco.ConvertTo<Poco>();

La asignación automática incorporada también es muy tolerante y puede combinar propiedades con diferentes tipos, por ejemplo, a / desde cadenas, diferentes tipos de colección, etc.

Objetos de transferencia de datos - DTO

Por lo tanto, si está utilizando POCO limpios y serializables sin dependencias externas (por ejemplo, de fuentes OrmLite, Redis o alt ServiceStack), puede reutilizarlos felizmente como DTO y refactorizarlos libremente en diferentes modelos cuando lo necesite. Pero cuando está reutilizando los Modelos de datos como DTO, aún deben mantenerse en el proyecto ServiceModel (también conocido como DTO .dll) que debe contener todos los tipos que devuelve su Servicio. Los DTO deben ser lógicos y libres de dependencias, por lo que la única dependencia a la que hace referencia el proyecto ServiceModel es el ServiceStack.Interfaces.dll libre de ServiceStack.Interfaces.dll que como PCL .dll, puede ser referenciado libremente desde todas las plataformas .NET Mobile y Desktop .

Desea asegurarse de que todos los tipos que devuelven sus Servicios estén en el DTO .dll, ya que esto, junto con la url base de dónde están alojados sus Servicios, es todo lo que los consumidores del Servicio deben conocer para poder consumir sus Servicios. Que pueden usar con cualquiera de los Clientes de Servicio .NET para obtener una API con tipo de extremo a extremo sin code-gen, herramientas o cualquier otra maquinaria artificial. Si los clientes prefieren el código fuente, pueden usar Agregar referencia de ServiceStack para acceder a los DTO escritos por los servidores en su plataforma preferida y el idioma de su elección.

Servicios

Los servicios son la mejor forma de encapsular la complejidad y ofrecen el más alto nivel de reutilización de software. Empaquetan sus capacidades y las ponen a disposición de sus consumidores de forma remota con una complejidad nunca mayor que el costo de una llamada de servicio.

Los DTO son lo que define su contrato de Servicios, mantenerlos aislados de cualquier implementación de Servidor es cómo su Servicio puede encapsular sus capacidades (que pueden ser de complejidad ilimitada) y ponerlas a disposición detrás de una fachada remota. Separa lo que proporciona su Servicio de la complejidad en cómo lo realiza. Define la API para su Servicio y le dice a los Consumidores del Servicio la información mínima que necesitan saber para descubrir qué funcionalidad proporcionan sus Servicios y cómo consumirlos (manteniendo una función similar a los archivos de Encabezado en el código fuente C / C ++). Los contratos de servicio bien definidos desacoplados de la implementación, hacen cumplir la interoperabilidad asegurando que sus servicios no exijan implementaciones específicas del cliente, lo que garantiza que cualquier cliente HTTP pueda consumirlos en cualquier plataforma. Los DTO también definen la forma y la estructura de su formato de cable de Servicios, asegurando que puedan deserializarse limpiamente en estructuras de datos nativas, eliminando el esfuerzo de analizar manualmente las Respuestas de Servicio.

Desarrollo de cliente paralelo

Dado que capturan el contrato completo, también permite a los clientes desarrollar sus aplicaciones antes de que se implementen los Servicios, ya que pueden vincular su aplicación a sus modelos concretos de DTO y pueden burlarse fácilmente de su cliente de Servicio para devolver datos de prueba hasta los Servicios de fondo son implementados.

En lo que respecta a las reglas, garantizar un contrato de servicio (DTO) bien definido desacoplado de su implementación es la esencia de lo que es un servicio y el valor que proporciona.

Solicitud y respuesta DTO

En cuanto a qué DTO son buenos candidatos para la reutilización como Modelos de datos, no desea utilizar Solicitar DTO para nada más que definir su API de servicios externos, que generalmente es un verbo que se agrupa idealmente por semántica de llamadas y tipos de respuesta , por ejemplo:

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

Sus tablas RDBMS son normalmente entidades definidas como sustantivos , es decir, lo que devuelve su servicio:

public class SearchProductsResponse { public List<Product> Results { get; set; } public ResponseStatus ResponseStatus { get; set; } }

Incluso el DTO que contiene la respuesta que define lo que devuelve su Servicio no es un buen candidato para su reutilización como Modelo de datos. Por lo general, uso DTO discretos para las respuestas del servicio, ya que permite ampliar libremente los servicios existentes para devolver datos o metadatos adicionales sin romper los clientes existentes.

Además de los DTO de Solicitud y Respuesta, todos los otros Tipos que devuelve su Servicio serían candidatos para su reutilización como Modelos de Datos, lo que hago con frecuencia, manteniéndolos en el proyecto ServiceModel por las razones anteriores.