alexey.merson@gmail.com 2 - - PowerPoint PPT Presentation
alexey.merson@gmail.com 2 - - PowerPoint PPT Presentation
Domain Driven Design: alexey.merson@gmail.com 2 3 4 5 6 7 8 DDD 9 Domain Driven Design:
2
3
4
5
6
7
8
DDD
9
Domain Driven Design:
Стратегическое проектирование Взаимодействие между людьми Подходы к архитектуре Тактические паттерны Борьба со сложностью
10
11
12
13
14
15
Ключевые идеи стратегического проектирования
16
17
Доменные эксперты
18
Доменные эксперты Технические специалисты
19
Доменные эксперты Технические специалисты
20
Доменные эксперты Технические специалисты
21
Общение между участниками проекта формирует ubiquitous la language
Сценарий: Докладчик регистрируется на событие и добавляет информацию о докладе
22
23
Speaker Talk Event Domain model
24
Доменная модель и ubiquitous language ограничены контекстом (bounded context)
25
Speaker Talk Event Domain model Event planning context
Speaker Talk Event Event planning context User Role Profile Identity context
26
27
Speaker Talk Event Event planning context User Role Profile Identity context
28
Sales service
Сценарий: По нажатию на Checkout считается окончательная цена заказа с учетом скидки постоянного клиента, и заказ переходит в статус «Ожидание оплаты»
29
30
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
31
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
32
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
33
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
34
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
35
public void Checkout(long id) { var ord = _ordersRepository.GetOrder(id); var orders = _ordersRepository.GetOrders().Count(
- => o.CustomerId == ord.CustomerId
&& o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5));
- rd.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100;
- rd.StateId = 1;
_ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019
36
37
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
38
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
39
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
40
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
41
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
42
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
44
public decimal CalculateDiscountBy(long customerId) { var completedOrdersCount = _ordersRepository .GetLast5YearsCompletedOrdersCountFor(customerId); return DiscountBy(completedOrdersCount); }
https://github.com/a-merson/Stachka2019
45
private decimal DiscountBy(int completedOrdersCount) { if (completedOrdersCount >= 5) return 30; if (completedOrdersCount >= 3) return 20; if (completedOrdersCount >= 1) return 10; return 0; }
https://github.com/a-merson/Stachka2019
46
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _сalculator.CalculateDiscountBy(order.CustomerId);
- rder.ApplyDiscount(discount);
- rder.State = OrderState.AwaitingPayment;
_ordersRepository.SaveOrder(order); }
https://github.com/a-merson/Stachka2019
47
Доменная модель и бизнес-логика должны использовать ubiquitous language
Domain
Subdomain Subdomain Subdomain Bounded context Bounded context Bounded context
48
Domain
Subdomain Subdomain Subdomain Bounded context Bounded context Bounded context
49
Domain
Subdomain Subdomain Subdomain Bounded context Bounded context Bounded context
50
Subdomains Core Supporting Generic
51
Subdomains Core Supporting Generic
52
Subdomains Core Supporting Generic
53
Контент
Subdomains Core Supporting Generic
54
Subdomains Core Supporting Generic
55
Маркетинг
Subdomains Core Supporting Generic
56
Subdomains Core Supporting Generic
57
Оплата
Domain
Subdomain Subdomain Subdomain Bounded context Bounded context Bounded context
58
Subdomain Bounded context
Задачи бизнеса Программные решения
59
Бухгалтерия Программные решения
60
61
Билеты Контент
Яндекс Касса Custom application
Архитектура и управление зависимостями
62
Domain Driven Design
Micro services Layers Event- Driven CQRS
63
Цель: максимально избавить доменную логику от зависимостей
64
Data layer Business layer Presentation layer
65
Infrastructure layer Domain layer Application layer Presentation layer
66
Domain layer Application layer UI & Infrastructure
67
Domain layer Application layer UI & Infrastructure
68
Domain layer Application layer UI & Infrastructure
69
Domain layer Application layer UI & Infrastructure
70
Domain layer Application layer UI & Infrastructure
71
72
Гексагональная архитектура Порты и адаптеры
Еще раз о языке
73
74
Speaker Talk Event Domain model
75
Speaker Talk Event Domain model
Сценарий: Докладчик регистрируется на событие и добавляет информацию о докладе
76
English Русский
77
78
https://github.com/a-merson/Stachka2019
79
https://github.com/a-merson/Stachka2019
Рецепт для прагматика
- 1. Общение + общение + общение = ubiquitous language
80
Рецепт для прагматика
- 1. Общение + общение + общение = ubiquitous language
- 2. Модели ограничиваются контекстами
81
Рецепт для прагматика
- 1. Общение + общение + общение = ubiquitous language
- 2. Модели ограничиваются контекстами
- 3. Минимум зависимостей для доменной модели
82
Рецепт для прагматика
- 1. Общение + общение + общение = ubiquitous language
- 2. Модели ограничиваются контекстами
- 3. Минимум зависимостей для доменной модели
- 4. Максимально выразительный код бизнес-логики
83
Рецепт для прагматика
- 1. Общение + общение + общение = ubiquitous language
- 2. Модели ограничиваются контекстами
- 3. Минимум зависимостей для доменной модели
- 4. Максимально выразительный код бизнес-логики
- 5. ?????
- 6. PROFIT
84
Полезные ссылки:
- 1. https://habr.com/users/marshinov (например Как мы попробовали
DDD, CQRS и Event Sourcing и какие выводы сделали)
- 2. https://blog.byndyu.ru
- 3. DDD и функциональное программирование
- https://fsharpforfunandprofit.com/
- 4. Hexagonal Architecture (Ports&Adapters)
- https://herbertograca.com/2017/09/14/ports-adapters-architecture/
85