El concepto de un diseño de lógica pesada y segregada para conseguir sistemas con “Casi- infinita escalabilidad ” está escrito en el illuminating paper – “Life beyond Distributed Transactions: an Apostate’s Opinion” (Pat Helland), también aparece en Vaughn Vernon´s “Implementing Domain Driven Design”. En este artículo, voy a intentar dar algunas ideas, desde mi perspectiva, de cómo entiendo el concepto “Casi-infinita Escalabilidad en arquitectura de software y su fuerte relación con la lógica de diseño.

Basandome en mi experiencia, una de las partes más difíciles de poner en práctica para la escalabilidad en arquitectura de software en DDD ha sido siempre el diseño del límite de aggregate roots.
Típicamente, en los comienzos del DDD, tuvimos grandes partes de entidades que empezaban por una “central”. Cada una de ellas estaba relacionada con las demás mediante directas o indirectas asociaciones navegables.
El ORM se hace cargo del atractivo de las entidades a través de “lazy-loading”.
El mecanismo se usó en medio de aggregate roots, aunque voy a mostrar que no fué tan beneficioso para el modelo.
Una justificación fué para soportar las lecturas del mismo modelo utilizado para escribir, que fue otra fuerte asumpción “a escondidas”.
Simplemente todo estaba bien soportado por todas las herramientas. ORMs, relational (transactional) databases, tecnologías proactivas e imperativas, todas parecían soportar este tipo de diseño tan bien que las preocupaciones de “transactionallity by design” eran simplemente percibidas como exageradas.
Las guías discutidas por Vernon en el escrito “4 rules of thumb” guió hacia una perspectiva de diseño completamente diferente.
Son lógicamente justificadas por los fundamentos OO como Single Responsibility Principle, Interface Segregation Principle y demás.

Echemos un vistazo a las “mates”:

Como está descrito anteriormente, utilizando aplicaciones consecutivas de un set conocido de los principios OO, inherentemente conseguimos agregar divisiones que cumplen con las “reglas de Vernon”.

 

Beneficios en la arquitectura de un modelo segregado

 

  • Explicit transactional scope: segregando el dominio, cada uno es más dado a ser completamente responsable de las transacciones que operan. Eso es, debido a la correspondencia entre el método en el aggregate root y la operational transaction misma. Transaccionalidad es un mecanismo guiado por la persistence component, en caso de tecnologias relacionadas, aún puedes beneficiarte usando SQL Transactions. Pero en alguna database no relacionada, como por ejemplo MongoDB, el único mecanismo de transacción es la propiedad ACID cuando se guarda un “documento”, el cual debería corresponder a un estado agregado (aggregate state). 
  • Diseño de portabilidad: teniendo unos límites explícitos de transacciones hace que el diseño sea llevadero. En una hipotética transición hacia un sistema distribuido, podría ser conveniente introducir una consistencia entre un fuerte límite de transacciones y otro. Piensa por ejemplo sobre posibles migraciones hacia tecnologías message-driven.
  • Cohesiveness: Desde el punto de vista de la cohesión, estando el modelo en su forma normal, un cambio es más dado a que haga efecto únicamente en un domain, desacoplado del resto de los agregados.
  • Simplicidad: el mantenimiento de un, simple, cohesivo y desacoplado módulo es siempre más simple que el mismo en un gran nicho de clases. Para mi, este concepto en solitario, justifica la segregación del approach del dominio.
  • Fetching performance: siendo un modelo no relacionado con otros dominios, es factible utilizar estrategias más atractivas por defecto. Esto debería ayudar cuando aparece la típica trampa teniendo la database heavily shot desde lazy loads “escondidos”. En una database no-relacionada, donde a menudo lazy-loading no tiene sentido, todavía puedes beneficiarte de evitar grandes documentos (esto es un problema enorme en I/O) y gran objetos mapping.
  • Consumo de memoria: la propiedad de cohesión minimiza la cantidad de valor propiedades/intrínseco de lo objetos a un mínimo que hace falta conseguir para la transacción misma.
  • Domains colaborativos: debido a la cantidad reducida de data en cada límite de transacción, son menos probables los conflictos de una intensa colaboración en la misma data.
  • Reading Performance: siguiendo la misma lógica, la extracción de un tipo de modelo separado para la lectura, encaja de manera natural como “eager read derivation” (siendo un modelo de lectura, vistas materializadas o incluso CQRS). Incluso en caso de evitar eager derivation techniques, no hay ninguna magia negra derivando la la parte de la lectura, y además el peligro de rebasar la database se reduce.
  • Decoupling from the underlying mechanisms: dadas las anteriores propiedades, el role de un ORM (generalmente más de un Data Mappers) se reduce al mínimo. Idealmente, el modelo no ha de cambiar en caso de, por ejemplo, una migración del uso de un ORM hacia un raw-file. Únicamente lo hace la implementación de de los componentes persistentes.
  • Testabilidad: una consecuencia importante de desacoplarse del mecanismo subyacente, es que los domains son más fáciles de testear. Eso ocurre porque no hay necesidad de construir grandes ramas de entidades para tener accesorios completos, y por la persistente ignorancia.

 

Escalabilidad en arquitectura de software

 

La idea detrás de los beneficios de la escalabilidad en arquitectura de software es que, si queremos distribuir una gran ramificación de objetos navegable, probablemente necesitaremos límites de transacciones para adoptar el modelo de interacción completo. Por descontado, las tecnologías que permiten transacciones distribuidas existen. Pero el problema es que son “lógicamente” un gran impedimento para el motivo.
En realidad, en un sistema distribuido, cada entidad podría permanecer en diferentes máquinas. Eso implica llaves de transacción en diferentes lugares con confiabilidad y problemas de actuación.
Este efecto se hace incluso más aparente cuando se considera distribuir “sistema elástico” donde los efectos de grandes transacciones distribuidas son menos predecibles.
Cierto es que es posible imaginar scale-aware Data Mappers que preservarian un modelo “transparente” navegable.
Mi visión, es que basándonos herramientas de navegación entre aggregate roots es un error por ver. No da ningún beneficio para la Escalabilidad en arquitectura de software la simplicidad de pensar en ello desde una perspectiva, “relational”, sin embargo llega con el precio de renunciar a todos los beneficios mencionados anteriormente. Lo que realmente me gusta de segregaciones domains, desde un punto de vista de escalabilidad y manejo de transacciones, es que da forma a transacciones de una forma que habilita sistemas de distribución mediante “design”.
En otras palabras, todo está en el domain.

 

Lecciones aprendidas de tecnologías non-relational

 

El uso de mecanismos como automatic relationship population en data mappers, o similarmente el uso de “hooks” de persistencia, en tecnologías non-relational, es a menudo una fuente de grandes problemas según nuestra experiencia.
Estos son intentos de utilizar modelling relational en tecnologías non-relational, lo que es un error de modelaje en primer caso.
DDD se basa en hacer los dominios y contexts en el centro de la aplicación, por lo que in-memory relational approach no tiene sentido.
Además, genera los mismos problemas que lazy-loading (la database esta rebasada), más severos debido a que la mayoría de NRDMSSs no son tan buenas como RDBMs en respuesta a la gran cantidad de preguntas.
En este sentido, Tecnologias Non-Relational son una gran oportunidad para practicar la normatización Domain, de una manera que se reduce la brecha entre un dominio in-memory cuidadosamente diseñado y su persistente representación.

 

Puntos de contacto con programación funcional

 

Como cada vez vemos más en Apiumhub, los principios funcionales de programación a menudo no están en contradicción con los clásicos de diseño orientado a objetos.
Es importante para nosotros estresar que los pequeños y específicos domains llevan consigo una característica especial: capacidad de compilación sobre navegabilidad, como contraposición al aproach típico de “nesting aggregates” viniendo de un approach más clásico en DDD.
En este sentido, las aplicaciones de transacciones pueden ser vistas como una (monadic) composición entre servicios de dominios.

 

Drawbacks de segregación “extrema”

 

Renuncia: Estoy escribiendo sobre la lógica de segregación que vemos arriba. No lo voy a marcar como unidades físicas de deployment aquí, o debatiré sobre los “microservices” en este artículo.
En nuestra experiencia, los drawbacks en “demasiada” segregación son varios:

  1. La proliferación de domains
  2. La proliferación del código “boilerplate” conectando domains.

Mientras que el primer punto puede convertirse en un problema de verdad incluso para equipos experimentados, normalmente solo es visto como una proliferación de módulos.
Incluso refiriéndome a ello, no es fácil atrapar las abstracciones en primer lugar, obviamente llama a un proceso iterativo y teniendo módulos pequeños, ayuda a ello.
Otro hecho es que, si hay “demasiados dominios”, probablemente sea debido a la duplicación en las reglas de modelaje business, o que llama a un nuevo contexto bounded.
Sin embargo, a menudo, es verdad, que los developers perciben un problema cuando la lógica modular fuerza a una proliferación de los módulos físicos. Ver el punto dos.

Respecto al segundo punto, estamos convencidos de que hay mejores maneras de expresar los servicios de domain express en la escalabilidad en arquitectura de software, eliminando una gran cantidad de código “boilerplate” y archivos físicos, mediante altos niveles de abstracción cuando se está conectando los códigos. Esto es especialmente relevante en tecnologías con lenguaje Scala.

Si te gustó este artículo sobre Escalabilidad en arquitectura de software, probablemente te pueda gustar: