Dise√Īo impulsado por dominios: una receta para un pragm√°tico


¬ŅPor qu√© los DDD generalmente se abordan desde el lado equivocado? ¬ŅY de qu√© lado quieres? ¬ŅQu√© tienen que ver las jirafas y los ornitorrincos con todo esto?

Especialmente para Habr: una transcripci√≥n de texto del informe "Dise√Īo impulsado por el dominio: una receta para un pragm√°tico". El informe se realiz√≥ en la conferencia DotNext .NET, pero puede ser √ļtil no solo para los donantes, sino para todos los que est√©n interesados ‚Äč‚Äčen DDD (creemos que dominar√° un par de ejemplos de c√≥digo C #). Tambi√©n se adjunta una grabaci√≥n de video del informe.



Hola a todos, mi nombre es Alexey Merson. Te dir√© qu√© es el dise√Īo impulsado por dominio y cu√°l es su esencia, pero primero, descubramos por qu√© es necesario.



Martin Fowler dijo: "Hay pocas cosas que son menos lógicas que la lógica de negocios". La jirafa es definitivamente una de estas pocas. La distancia entre el cerebro y la laringe de una jirafa es de solo unos centímetros. Sin embargo, el nervio que los conecta alcanza los 4 metros. Primero, baja por todo el cuello, allí rodea la arteria y luego regresa casi de la misma manera.

A primera vista, realmente no hay l√≥gica. Pero este es solo un denso legado que qued√≥ de los peces antiguos. En los peces, como saben, no hay cuello, por lo que este nervio recorre el camino √≥ptimo. Y cuando aparecieron los mam√≠feros despu√©s de varios millones de a√Īos de refactorizaci√≥n, el nervio tuvo que extenderse para mantener la compatibilidad con versiones anteriores. Bueno, ¬Ņno remodelas por alguna jirafa?

Pero la jirafa est√° bien, porque hay un ornitorrinco.


Pi√©nsalo bien. El mamifero Con un pico. Vive principalmente en el agua. Pone huevos. Y adem√°s, venenoso. Puede parecer que la √ļnica explicaci√≥n l√≥gica de su existencia es que √©l es de Australia.

Pero creo que todo es m√°s banal. El contratista simplemente se olvid√≥ del dise√Īo y ahorr√≥ con StackOverflow, bueno, o lo que hab√≠a en esos d√≠as.

S√© lo que est√°s pensando ahora: "Alexey, bueno, ¬°nos prometiste un dise√Īo impulsado por dominio, y aqu√≠ hay una especie de" en el mundo animal "!"

Colegas, ¬Ņqu√© es el desarrollo? El desarrollo es cuando tomamos parte del mundo real, un proceso de negocios, y lo convertimos en c√≥digo, es decir, construimos un modelo de software. ¬ŅQu√© problemas nos esperan en el camino?

El primero es la complejidad de los procesos comerciales en s√≠ mismos, es decir, la dificultad de comprender c√≥mo funciona el negocio, qu√© procesos tienen lugar all√≠, seg√ļn la l√≥gica con la que se construyen.

El segundo problema es la implementación de estos procesos de negocio en forma de código, el uso de los patrones correctos, los enfoques correctos, etc. Este también es un tema bastante complicado.

Mire, los procesos comerciales son como esa jirafa: comenzaron con los unicelulares más simples, y luego "lo" mira, y nadie entiende "de dónde vino" o "cómo funciona".

Para construir un modelo exitoso de dicho proceso, primero debe responder la pregunta "¬Ņpor qu√©?". ¬ŅPor qu√© queremos construir este modelo? ¬ŅQu√© objetivos queremos alcanzar? Despu√©s de todo, si el cliente quer√≠a una jirafa de peluche, pero ten√≠a las agallas, se molestar√≠a, incluso si la digesti√≥n en este modelo se implementa por el bien de los ojos. Y el cliente perder√° no solo dinero y tiempo, perder√° la confianza en nosotros como desarrolladores, y nosotros perderemos nuestra reputaci√≥n y cliente.

Pero incluso si descubrimos los objetivos, esto todav√≠a no garantiza que no obtendremos el ornitorrinco como resultado. El hecho es que el objetivo es poco para entender. El objetivo debe ser alcanzado. Y esto nos ayuda a un dise√Īo basado en dominio.

El objetivo principal del dise√Īo impulsado por dominio es combatir la complejidad de los procesos comerciales y su automatizaci√≥n e implementaci√≥n en c√≥digo. "Dominio" se traduce como "dominio", y el desarrollo y el dise√Īo dentro del marco de este enfoque se alejan del dominio.

El dise√Īo controlado por dominio incluye muchas cosas. Esta planificaci√≥n estrat√©gica, y la interacci√≥n entre las personas, los enfoques de la arquitectura y los patrones t√°cticos, es todo un arsenal que realmente funciona y realmente ayuda a hacer proyectos. Solo hay un "pero". Antes de comenzar a lidiar con la complejidad con el dise√Īo impulsado por dominio, debe aprender a lidiar con la complejidad del dise√Īo impulsado por dominio.



Cuando una persona comienza a sumergirse en este tema, se le cae una gran cantidad de informaci√≥n: libros gruesos, un mont√≥n de art√≠culos, patrones, ejemplos. Todo esto es confuso, y es f√°cil, como dicen, no darse cuenta detr√°s de los √°rboles del bosque. Una vez sent√≠ esto en m√≠ mismo, pero hoy quiero compartir mi experiencia con usted y ayudarlo a atravesar esta jungla, finalmente comenzando a usar el dise√Īo impulsado por dominio.

El t√©rmino dise√Īo impulsado por el dominio fue propuesto por Eric Evans en 2003 en su libro impronunciable, que la comunidad simplemente llama el Libro Azul. El problema es que la primera mitad del libro Evans habla sobre patrones t√°cticos (todos los conocen: son f√°bricas, entidades, repositorios, servicios), y las personas generalmente no llegan a la segunda mitad. El hombre mira: todo es familiar, ir√© a buscar la aplicaci√≥n DDD.

A la derecha está lo que sucede si lanzas locamente patrones tácticos en el compilador. Izquierda: si usa patrones estratégicos.



Desde el lanzamiento del Libro Azul, se ha formado una comunidad DDD bastante fuerte, se han repensado muchas cosas. S√≠, y el propio Evans admiti√≥ que ya no comprende c√≥mo podr√≠a poner fin a algo tan importante como el dise√Īo estrat√©gico.

Y 10 a√Īos despu√©s, en 2013, el Libro Rojo fue publicado por Vaughn Vernon. Y en este libro, la presentaci√≥n ya est√° construida en el orden correcto: comienza con el dise√Īo estrat√©gico, con lo b√°sico. Y cuando el lector ha recibido la base necesaria, ya comienzan a hablar sobre patrones t√°cticos y detalles de implementaci√≥n.

Por lo general, en los informes sobre DDD recomiendan leer Evans, en Internet incluso hay manuales completos en el orden en que debe leer los cap√≠tulos para una inmersi√≥n adecuada. Recomiendo hacerlo m√°s f√°cilmente: comience con el Libro Rojo, l√©alo y luego contin√ļe con Azul.

Y dado que el dise√Īo estrat√©gico es algo tan importante, hablemos de sus ideas clave.

"Ideas clave del dise√Īo estrat√©gico"


En cualquier proyecto de automatización de negocios, siempre hay expertos en dominios. Estas son personas que entienden mejor cómo funcionan los procesos de negocio que se van a modelar. Estos pueden ser desarrolladores líderes, ejecutivos, altos directivos. En general, puede ser cualquiera, si solo él comprende los procesos comerciales con los que tenemos que lidiar.



Por otro lado, hay expertos t√©cnicos: desarrolladores, arquitectos que est√°n directamente involucrados en la automatizaci√≥n e implementaci√≥n de aplicaciones. En el ejemplo representado, el cliente probablemente quer√≠a un ferrocarril para ni√Īos, pero result√≥ ser una especie de monstruo.

¬ŅPor qu√© est√° pasando esto? Debido a que la interacci√≥n entre expertos t√©cnicos y expertos en dominios en una situaci√≥n t√≠pica se ve m√°s o menos as√≠: hay un muro muy grande entre ellos, y un gerente camina a lo largo de la parte superior de este muro y primero trata de escuchar lo que gritan a un lado del muro, luego trata de gritarlo al mejor de los paquetes al otro lado de la pared, y as√≠ sucesivamente en un c√≠rculo.

A veces, un gerente es sordo, entonces se puede construir una cadena completa de tales administradores, lo que, por supuesto, no contribuye al √©xito del proyecto. ¬ŅY c√≥mo deber√≠a ser?



Debe haber una interacción constante. Expertos técnicos, expertos en dominios: todos los participantes del proyecto deben mantener una comunicación constante, sincronizarse, discutir objetivos, formas de alcanzarlos y por qué hacemos todo esto.

Y aqu√≠ llegamos al primer y, probablemente, el punto clave m√°s importante tanto del dise√Īo estrat√©gico como del dise√Īo impulsado por dominio en general.



La comunicaci√≥n entre los participantes del proyecto forma lo que Domain-Driven Design llama lenguaje ubicuo. √Čl no es uno en el sentido de que es uno para todas las ocasiones. Justo lo contrario. Es √ļnico en el sentido de que todos los participantes se comunican en √©l, toda la discusi√≥n se lleva a cabo en t√©rminos de un solo idioma, y ‚Äč‚Äčtodos los artefactos deben ser m√°ximos en t√©rminos de un solo idioma, es decir, comenzando desde TK y terminando con un c√≥digo.

Escenarios de negocios


Para una mayor discusi√≥n, necesitamos alg√ļn tipo de escenario empresarial. Imaginemos esta situaci√≥n:



El director del grupo JUG.ru se acerca a nosotros y dice: "Chicos, el flujo de informes está creciendo, la gente, en general, es torturada para hacer todo manualmente ... Automaticemos el proceso de preparación de la conferencia". Respondemos: "¡Está bien!" - y ponte a trabajar.

El primer escenario que automatizaremos es: "El orador presenta una solicitud para un informe en un evento espec√≠fico y agrega informaci√≥n sobre su informe". ¬ŅQu√© vemos en este escenario? Qu√© es un orador, hay un evento y hay un informe, lo que significa que ya es posible construir el primer modelo de dominio.



Aquí tenemos un modelo de dominio: Altavoz - orador, Talk - informe, Evento - evento. Pero el modelo de dominio no puede ser ilimitado, no puede cubrir todo, de lo contrario se volverá borroso y perderá el foco, por lo que el modelo de dominio debe estar limitado por algo. Este es el siguiente punto clave.



Tanto el modelo de dominio como el lenguaje ubicuo están limitados por el contexto que Domain-Driven Design llama contexto acotado. Restringe el modelo de dominio de tal manera que todos los conceptos dentro de él no sean ambiguos y todos entiendan lo que está en juego.

Si dicen "Usuario", entonces todo deber√≠a estar claro a la vez, deber√≠a tener un papel comprensible, un significado comprensible, no deber√≠a ser alg√ļn tipo de usuario abstracto desde el punto de vista de la industria de TI.



En nuestro caso, este modelo de dominio es v√°lido para el contexto de la preparaci√≥n de la conferencia, por lo que es en el contexto que llamaremos el "contexto de planificaci√≥n de eventos". Pero para que el orador agregue algo, cambie la informaci√≥n, de alguna manera debe iniciar sesi√≥n, debe tener algunos derechos. Y este ya ser√° otro contexto, "Contexto de identidad", en el que habr√° alg√ļn tipo de sus propias entidades: Usuario, Rol, Perfil.

Y mira qu√© cosa est√° aqu√≠. Cuando una persona inicia sesi√≥n en el sistema y tiene la intenci√≥n de ingresar alg√ļn tipo de informaci√≥n, f√≠sicamente esta es la misma persona, pero en diferentes contextos est√° representada por diferentes entidades, y estas entidades no est√°n directamente relacionadas.

Si tomamos y, por ejemplo, heredamos el altavoz del usuario, entonces mezclaríamos cosas que no se pueden mezclar, y algunos atributos podrían mezclarse por lógica. Y el modelo perdería el foco en el significado específico que tiene, dividiéndose en varios contextos.

Demostración: servicio de ventas


Pasemos un poco de la teoría seca y miremos el código.

Una conferencia no es solo la preparaci√≥n de contenido, sino tambi√©n las ventas. Imaginemos que ya se ha escrito un servicio para vender boletos, y un gerente de ventas se nos acerca y nos dice: ‚Äú¬°Chicos! Una vez que alguien escribi√≥ este servicio, averig√ľ√©moslo, algo no me queda claro c√≥mo se considera el descuento para clientes habituales ‚ÄĚ.

Después de hablar con el gerente, descubrimos que todo el escenario de este servicio es el siguiente: al hacer clic en Pagar, el precio final del boleto se considera teniendo en cuenta el descuento regular para el cliente, y el pedido pasa al estado "Esperando el pago".

El código que ahora analizaremos se puede ver por separado en el repositorio .

Abra la solución, mire la estructura:



Parece que todo se ve bien: hay Aplicaci√≥n y N√ļcleo (aparentemente, la gente sabe sobre capas), Repositorio ... Aparentemente, la persona domin√≥ la primera mitad de Evans.

Abra OrderCheckoutService. ¬ŅQu√© vemos all√≠? Aqu√≠ est√° el c√≥digo :

public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders() .Count(o => o.CustomerId == ord.CustomerId && o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-3)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.StateId = 1; _ordersRepository.SaveOrder(ord); } 


Nos fijamos en la línea con el precio: aquí el precio cambia. Llamamos a nuestro gerente de ventas y le decimos: "Aquí, en resumen, el descuento se considera aquí, todo está claro":

 ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; 


√Čl mira sobre su hombro: ‚Äú¬°Oh! ¬°As√≠ es como se ve Brainfuck! Y me dijeron que los chicos est√°n escribiendo en C # ".

Obviamente, el desarrollador de este c√≥digo respondi√≥ bien a una entrevista sobre algoritmos y estructuras de datos. Escrib√≠ en las olimpiadas de la escuela con el mismo estilo. Despu√©s de un tiempo, utilizando el formato y la refactorizaci√≥n obscena , descubrimos qu√© es qu√© y le explicamos a nuestro sufrido gerente de ventas que la l√≥gica es esta: si el n√ļmero de pedidos en los √ļltimos 3 a√Īos no es inferior a uno, entonces recibe un 10% de descuento , no menos de tres - 20%, y no menos de cinco - 30%. Se marcha alegre: ahora est√° claro c√≥mo funciona todo.

Creo que muchos han leído el Código Limpio de Bob Martin. Allí dice sobre la regla de Boy Scout: "El estacionamiento después de que nos vayamos debería estar más limpio de lo que estaba antes de llegar allí". Por lo tanto, refactoricemos este código para que se vea humano y se corresponda con lo que hablamos un poco antes sobre el lenguaje ubicuo y su uso en el código.

Aquí está el código refactorizado.

  public class DiscountCalculator { private readonly IOrdersRepository _ordersRepository; public DiscountCalculator(IOrdersRepository ordersRepository) { _ordersRepository = ordersRepository; } public decimal CalculateDiscountBy(long customerId) { var completedOrdersCount = _ordersRepository.GetLast3YearsCompletedOrdersCountFor(customerId); return DiscountBy(completedOrdersCount); } private decimal DiscountBy(int completedOrdersCount) { if (completedOrdersCount >= 5) return 30; if (completedOrdersCount >= 3) return 20; if (completedOrdersCount >= 1) return 10; return 0; } } 


Lo primero que hacemos es transferir el c√°lculo de descuento a un Calculador de descuento por separado, en el que aparece el m√©todo CalculateDiscountBy customerId. Todo se lee humanamente, todo est√° claro: qu√©, por qu√© y c√≥mo. Dentro de este m√©todo, vemos que tenemos globalmente dos pasos para calcular el descuento. Primero: obtenemos algo del repositorio de pedidos, todo depende del caso del usuario, ni siquiera tiene que entrar si esta no es la parte que le interesa ahora. El hecho es que obtenemos el n√ļmero de algunos pedidos completados, despu√©s de lo cual inmediatamente consideramos el segundo descuento para esta cantidad como el segundo paso.

Si queremos ver cómo se considera, vamos a DiscountBy, y aquí casi lo mismo está escrito en inglés casi humano que nuestro "tipo de brainfair" era antes, todo es claro y preciso.

La √ļnica pregunta que podr√≠a surgir es en qu√© unidades se mide el descuento. Ser√≠a posible agregar la palabra "porcentaje" en el nombre del m√©todo para que quede claro, pero por el contexto y las cifras involucradas, lo m√°s probable es que adivine que estos son porcentajes, y por brevedad puede omitirse. Si queremos ver cu√°l fue el n√ļmero de pedidos, entonces iremos al c√≥digo del Repositorio y veremos. Ahora no haremos esto. En nuestro Servicio, necesitamos agregar una nueva dependencia de DiscountCalculator. Y veamos con qu√© terminamos en la segunda versi√≥n del m√©todo Checkout.

 public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _discountCalculator.CalculateDiscountBy(order.CustomerId); order.ApplyDiscount(discount); order.State = OrderState.AwaitingPayment; _ordersRepository.SaveOrder(order); } 


Mire, el método Checkout recibe orderId, luego recibe un orderId por orderId, de acuerdo con el CustomerId de este pedido, considera el descuento utilizando la calculadora de descuentos, aplica el descuento al pedido, establece el estado en AwaitingPayment y guarda el pedido. Teníamos un guión en ruso en la diapositiva, pero aquí prácticamente leemos la traducción de este guión al inglés y todo está claro, todo es obvio.

¬ŅVes lo que es el encanto? Este c√≥digo se puede mostrar a cualquiera: no solo a los programadores, sino tambi√©n al control de calidad, a los analistas, a los clientes. Todos entender√°n lo que est√° sucediendo, porque todo est√° escrito en lenguaje humano. Utilizo esto en nuestro proyecto, realmente QA puede ver algunas piezas, consultar con Wiki y comprender que hay alg√ļn tipo de error. Porque el Wiki lo dice, y el c√≥digo es un poco diferente, pero entiende lo que est√° sucediendo all√≠, aunque no es un desarrollador. Y de la misma manera, podemos analizar el c√≥digo con el analista y analizarlo en detalle. Yo digo: "Mira, as√≠ es como funciona en c√≥digo". Nuestro √ļltimo recurso no es el Wiki, sino el c√≥digo. Todo funciona tal como est√° escrito en el c√≥digo. Es muy importante utilizar un lenguaje ubicuo al escribir c√≥digo.



Este es el tercer punto clave.

Hay tanta confusi√≥n sobre el dise√Īo impulsado por dominio en cosas como dominio, subdominio, contexto acotado, c√≥mo se relacionan con lo que significan. Parece que todo el mundo est√° limitando algo, todos de alguna manera est√°n ordenados. Pero no est√° claro cu√°l es la diferencia, por qu√© son tan diferentes inventados.



El dominio es algo global, es un √°rea tem√°tica global en la que este negocio en particular gana dinero. Por ejemplo, para DotNext esta es una conferencia, para Pyaterochka es una venta minorista de bienes.

Las grandes corporaciones pueden tener varios dominios. Por ejemplo, Amazon se dedica tanto a la venta de bienes a través de Internet como a la provisión de servicios en la nube, estas son diferentes áreas temáticas.

Sin embargo, es algo global y no puede automatizarse directamente, incluso investigarlo es difícil. Para el análisis, el dominio se divide inevitablemente en subdominios, es decir, en subdominios.



Los subdominios son partes de un negocio que, en nuestro idioma, est√°n altamente conectados, es decir, son alg√ļn tipo de procesos l√≥gicos aislados que interact√ļan entre s√≠ en alg√ļn nivel importante.

Por ejemplo, si tomamos una tienda en línea, será la formación y el procesamiento de pedidos, será la entrega, esto es trabajo con proveedores, esto es marketing, esto es contabilidad. Estas son algunas de estas piezas: en esto se divide el negocio.



Desde el punto de vista de DDD, los subdominios se dividen en tres tipos. Y aquí quiero decir una cosa más: a menudo en libros y artículos, el Subdominio simplemente se reduce a Dominio, pero generalmente en el caso cuando se combina con el tipo de Subdominio. Es decir, cuando dicen "Dominio principal", se refieren a Subdominio principal, no se confundan en esto. Al principio me dejó alucinado.

Los subdominios se dividen en tres tipos.



El primero y m√°s importante es Core. Core es el subdominio principal, esta es la ventaja competitiva de la compa√Ī√≠a, lo que le hace ganar dinero a la compa√Ī√≠a, c√≥mo se diferencia de sus competidores, su know-how, como se llame. Si tomamos la conferencia DotNext, entonces este es el contenido. Todos vinieron aqu√≠ por contenido, si no hubiera tal contenido aqu√≠, no ir√≠an o ir√≠an a otra conferencia. No habr√≠a DotNext en la forma en que est√°.



El segundo tipo es Subdominio de soporte. Esto tambi√©n es algo importante para ganar dinero, tambi√©n es algo sin lo cual es imposible, pero no es alg√ļn tipo de conocimiento, una verdadera ventaja competitiva. Esto es lo que admite el subdominio principal. Desde el punto de vista de la aplicaci√≥n del dise√Īo impulsado por dominio, esto significa que se gasta menos esfuerzo en el subdominio de soporte, todas las fuerzas principales se lanzan en Core.

Un ejemplo para el mismo DotNext es el marketing. Es imposible sin marketing, de lo contrario, nadie habría sabido sobre la conferencia, pero sin marketing de contenido no es necesario.



Y finalmente, el subdominio genérico. Genérico es una tarea empresarial típica, que, por regla general, puede automatizarse con productos terminados o externalizarse. Esto es lo que también se necesita, pero no necesariamente requiere una implementación independiente por nuestra parte, e incluso más que eso, generalmente será una buena idea usar un producto de terceros.

Por ejemplo, venta de boletos. DotNext vende boletos a través de TimePad. TimePad automatiza perfectamente este subdominio, y no necesita escribir un segundo TimePad usted mismo.



Y finalmente, contexto acotado. El contexto limitado y el subdominio siempre est√°n cerca, pero hay una diferencia significativa entre ellos. Esto es muy importante



Hay una pregunta en StackExchange sobre cómo el contexto acotado difiere del Subdominio. El subdominio es una parte del negocio, una parte del mundo real, es el concepto de un espacio de declaración de problemas. El contexto limitado limita el modelo de dominio y el lenguaje ubicuo, es decir, cuál es el resultado del modelado y, en consecuencia, el contexto limitado es el concepto de un espacio de solución. En el proceso de implementación del proyecto, se realiza un tipo de mapeo de Subdominios en contextos limitados.



Un ejemplo cl√°sico: la contabilidad como un Subdominio, c√≥mo se mapea el proceso, est√° automatizado, por ejemplo, 1C Contabilidad, Elba o "Mi negocio" - de alguna manera est√° automatizado por alg√ļn producto. Este es el contexto limitado de la contabilidad, en el que existe su lenguaje ubicuo, su propia terminolog√≠a. Esa es la diferencia entre ellos.



Si volvemos a DotNext, entonces, como dije, los tickets se asignan a TimePad, y el contenido que es nuestro Subdominio principal se asigna a una aplicación personalizada que estamos desarrollando para la administración de contenido.

Tama√Īo de contexto acotado


Hay un momento que plantea muchas preguntas. ¬ŅC√≥mo elegir el tama√Īo correcto para el contexto acotado? En los libros, uno puede encontrar esa definici√≥n: "El contexto limitado debe ser exactamente tal que el lenguaje ubicuo sea completo, consistente, inequ√≠voco, inequ√≠voco, consistente". Definici√≥n genial, al estilo de un matem√°tico de una broma famosa: muy precisa, pero in√ļtil.

Analicemos c√≥mo entendemos lo mismo: si deber√≠a ser una Soluci√≥n, un Proyecto o un espacio de nombres, ¬Ņqu√© escala deber√≠a adjuntarse al contexto acotado?



Lo primero que puede leer en casi todas partes: idealmente, un subdominio debe mapearse a un contexto limitado , es decir, ser automatizado por un contexto limitado. Suena lógico, porque tanto allí como existen limitaciones de un proceso comercial separado, en ambos casos, algunos términos comerciales, aparece un solo idioma. Pero aquí debe comprender que esta es una situación ideal, no necesariamente tendrá esto, y no es necesario tratar de lograrlo.

Porque, por un lado, el Subdominio puede ser bastante grande, y se pueden obtener varias aplicaciones o servicios que lo automatizar√°n, por lo que puede resultar que varios contextos limitados correspondan a un Subdominio.

Pero hay una situaci√≥n inversa, como regla, esto es t√≠pico de Legacy. Es decir, cuando crearon una aplicaci√≥n muy grande que automatiza todo en el mundo en esta empresa, todo lo contrario resultar√°. Una aplicaci√≥n es un contexto limitado, es probable que el modelo sea alg√ļn tipo de ambig√ľedad, pero los Subdominios no han desaparecido de este, respectivamente, un contexto limitado corresponder√° a varios Subdominios.

Cuando la arquitectura de microservicios se puso de moda, apareci√≥ otra recomendaci√≥n (aunque no se contradicen entre s√≠): un contexto limitado por microservicio . Nuevamente, suena l√≥gico, la gente realmente hace eso. Porque el microservicio debe asumir una funci√≥n clara, que internamente tiene una alta conectividad, y se comunica con otros servicios a trav√©s de alg√ļn tipo de interacci√≥n. Si usa una arquitectura de microservicio, puede tomar esta recomendaci√≥n usted mismo.

Pero eso no es todo. Perm√≠tame recordarle una vez m√°s que el dise√Īo impulsado por el dominio es mucho: sobre el lenguaje, sobre las personas. Y no puede ignorar a las personas y solo hacer criterios t√©cnicos en este asunto. Por lo tanto, escrib√≠ esto: un contexto es igual a X-man . Sol√≠a ‚Äč‚Äčpensar que x es aproximadamente 10, pero hablamos un poco con Igor Labutin ( twitter.com/ilabutin ) y la pregunta permaneci√≥ abierta.

Aqu√≠ es importante entender esto: un solo idioma permanece unificado mientras todos los participantes hablan, discuten y todos lo entienden sin ambig√ľedades. Est√° claro que un n√ļmero infinito de personas no puede hablar el mismo idioma. Nuestra historia de la humanidad muestra claramente esto. En cualquier caso, aparecen algunos dialectos, algunos de sus significados, ahora incluso puedes agregar memes, etc. De una forma u otra, el idioma se volver√° borroso.

Por lo tanto, debe entenderse que el n√ļmero de personas que usan este lenguaje √ļnico y, en consecuencia, participan en el desarrollo, en la automatizaci√≥n, es limitado. Los libros tambi√©n hablan de algunas razones pol√≠ticas: si dos equipos trabajan bajo el liderazgo de diferentes gerentes y trabajan en el mismo contexto acotado, y por alguna raz√≥n estos gerentes no son amigos entre s√≠, los conflictos comenzar√°n y se perder√° el enfoque. Por lo tanto, ser√° mucho m√°s simple y correcto hacer dos contextos limitados para cada comando y no intentar combinar lo que no se combina.

Arquitectura y gestión de dependencias


Desde el punto de vista del dise√Īo impulsado por dominio, realmente no importa qu√© arquitectura elija. El dise√Īo dirigido por el dominio no se trata de eso; el dise√Īo dirigido por el dominio se trata del lenguaje y la comunicaci√≥n.



Pero hay un punto importante, desde el punto de vista de los criterios para elegir la arquitectura que nos interesa desde la perspectiva del dise√Īo impulsado por dominio: nuestro objetivo es eliminar al m√°ximo la l√≥gica empresarial de las dependencias de terceros . Porque, tan pronto como aparecen las dependencias de terceros, aparece la terminolog√≠a, aparecen palabras que no entran en un solo idioma y comienzan a ensuciar nuestra l√≥gica comercial.



Veamos un ejemplo clásico de arquitectura: la conocida arquitectura de tres capas. Tan pronto como no llamen una capa de dominio (aquí la capa Business): business, core y domain son todos iguales. En cualquier caso, esta es la capa en la que se encuentra la lógica de negocios, y si depende de la capa de datos, significa que algunos conceptos de la capa de datos fluirán de alguna manera en la capa de dominio y la ensuciarán.



La arquitectura de cuatro capas es esencialmente la misma, la capa de dominio a√ļn depende, y como depende, las dependencias innecesarias de terceros llegar√°n a ella.



Y en este sentido, hay una arquitectura que permite evitar esto: es la arquitectura de cebolla ("cebolla"). Su diferencia es que consiste en capas concéntricas, las dependencias van del exterior al centro. Es decir, la capa externa puede depender de las internas, la capa interna no puede depender de las externas.

La capa más externa es la interfaz de usuario en un sentido global (es decir, no es necesariamente una interfaz de usuario humana, puede ser una API REST ni nada). Y la infraestructura, que a menudo en general también se parece a E / S, es la misma base de datos, de hecho, una capa de datos. Todas estas cosas están en la capa externa. Es decir, debido a que la aplicación de alguna manera recibe algunos datos, comandos, etc., se elimina y la capa de dominio elimina la dependencia de estas cosas.

Luego viene la capa de aplicación, un tema bastante holístico, pero esta es la capa en la que se encuentran los guiones, los casos de los usuarios. Esta capa usa la capa de dominio para implementar sus conceptos.

En el centro est√° la capa de dominio. Como vemos, ya no depende de nada; se convierte en una cosa en s√≠ mismo. Y es por eso que la capa de dominio a menudo se llama "Core", porque es el n√ļcleo, es lo que est√° en el centro, lo que no depende de cosas de terceros.



Una de las opciones para implementar dicha arquitectura de cebolla es la arquitectura hexagonal, o "puertos y adaptadores". Traje esta foto para intimidar, no voy a hablar de eso. Al final de la publicación hay un enlace a uno de un millón de artículos sobre esta arquitectura, puede leer.

Un poco sobre patrones t√°cticos: interfaz separada


Como dije, en primer lugar, la mayoría de los patrones tácticos son familiares para todos, y en segundo lugar, el objetivo de mi informe es que no son la esencia. Pero me gusta el patrón de Interfaz separada por separado, y quiero hablar sobre él por separado.

Volvamos al código de nuestro microservicio y veamos qué pasó con el repositorio.



La capa de dominio tenía la interfaz del repositorio IOrdersRepository.cs y su implementación, OrdersRepository.cs.

 using System.Linq; namespace DotNext.Sales.Core { public interface IOrdersRepository { Order GetOrder(long id); void SaveOrder(Order order); IQueryable<Order> GetOrders(); #region V2 int GetLast3YearsCompletedOrdersCountFor(long customerId); #endregion } } 


Aqu√≠ hemos agregado un cierto m√©todo para recibir pedidos durante los √ļltimos tres a√Īos GetLast3YearsCompletedOrdersCountFor.

Y lo implementaron de alguna forma (en este caso, a través del Entity Framework, pero puede ser cualquier cosa):

  public int GetLast3YearsCompletedOrdersCountFor(long customerId) { var threeYearsAgo = DateTime.UtcNow.AddYears(-3); return _dbContext.Orders .Count(o => o.CustomerId == customerId && o.State == OrderState.Completed && o.OrderDate >= threeYearsAgo); } 


Mira cuál es el problema. El repositorio terminó en la capa de dominio, su implementación en la capa de dominio, pero el código, que comienza con DateTime.UtcNow.AddYears (-3), inherentemente no pertenece a la capa de dominio, y no es una lógica de negocios. Sí, LINQ lo hace más o menos humanizado, pero si, por ejemplo, hubo consultas SQL aquí, todo sería completamente triste.

El significado del patrón de interfaz separada es que la interfaz de servicio que utilizamos en la lógica de dominio se declara en la capa de dominio. Estamos hablando de repositorios y servicios similares en los que los detalles de la implementación de estos servicios no son lógica empresarial. La lógica de negocios es el hecho de la existencia de estos servicios y el hecho de su llamado y uso en la capa de dominio. Por lo tanto, la interfaz del repositorio permanece en la capa de dominio y la implementación se mueve a la capa de infraestructura.

Preparé otra opción. La interfaz del repositorio permanece en el ensamblaje Core, pero la implementación se traslada a Infrastructure.EF.



Por lo tanto, trajimos a la infraestructura aquellos conceptos que no eran peculiares de la capa de dominio. Como efecto secundario, podemos reemplazar esta infraestructura con alguna otra implementación. Pero este no es el objetivo principal, el objetivo principal es, como dije, eliminar la lógica del dominio de las dependencias de terceros.

Una vez m√°s sobre el idioma.


Hablemos una y otra vez sobre el idioma.

Al principio, creamos el modelo de dominio "orador - hablar - evento". Creo que nadie ha planteado ninguna pregunta especial.

Y aquí está el escenario en base al cual construimos este modelo de dominio:



Mira, el guión está en ruso y el modelo de dominio está en inglés.

Para los desarrolladores que no hablan inglés, esto es algo con lo que tienes que vivir constantemente.



Cada uno de ustedes, muy probablemente, realiza constantemente este proceso: traduce del ruso al inglés y viceversa. Aquellos que trabajan con clientes y proyectos de habla inglesa son un poco más fáciles, porque los requisitos están en inglés, las discusiones con los clientes en inglés, por regla general, todos los escenarios están en inglés, el código está en inglés y solo hay comunicación dentro del equipo en ruso, que crece rápidamente en inglés (cliente - cliente, pedido - pedido). Y esa carga cognitiva, esa sobrecarga, creada por una traducción constante, retrocede un poco.

, , , . , .

1, . , ‚ÄĒ , , .



1. PascalCase , , , , , , , - - .

, - ?



, use case, , . , . C#, , , . , , , .

, , Domain-Driven Design. , , , , C# . .

, - Continuous Integration. , , , - - . , - , , . , 95% , , Continuous Integration, , TeamCity . .

, . . , 1-, , . ¬ę¬Ľ , . , , .



, Domain-Driven Design.

‚ÄĒ , . Domain-Driven Design ‚ÄĒ , . ‚ÄĒ , , ubiquitous language. , , . , , , .

. , . - , , , , , , , , , , ‚ÄĒ . .

. . . . , , . DSL-. .NET-, - , , , , . , .

, - . , , ubiquitous language -. .



, , GitHub .

DotNext:
, ¬ę , ¬Ľ. DotNext ( 15-16 ) . , 1 , .

Source: https://habr.com/ru/post/440772/


All Articles