Domain Driven Design: рецепт для прагматика Алексей Мерсон alexey.merson@gmail.com
2
3
4
5
6
7
8
DDD 9
Domain Driven Design: Стратегическое Взаимодействие между проектирование людьми Борьба со сложностью Подходы к архитектуре Тактические паттерны 10
11
12
13
14
15
Ключевые идеи стратегического проектирования 16
Доменные эксперты 17
Доменные эксперты Технические специалисты 18
Доменные эксперты Технические специалисты 19
Доменные эксперты Технические специалисты 20
Общение между участниками проекта формирует ubiquitous la language 21
Сценарий: Докладчик регистрируется на событие и добавляет информацию о докладе 22
Domain model Speaker Talk Event 23
Доменная модель и ubiquitous language ограничены контекстом (bounded context) 24
Event planning context Domain model Speaker Talk Event 25
Event planning Identity context context User Speaker Role Talk Profile Event 26
Event planning Identity context context User Speaker Role Talk Profile Event 27
Sales service 28
Сценарий: По нажатию на Checkout считается окончательная цена заказа с учетом скидки постоянного клиента, и заказ переходит в статус «Ожидание оплаты» 29
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(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.StateId = 1; _ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019 30
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(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.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 => o.CustomerId == ord.CustomerId && o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.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 => o.CustomerId == ord.CustomerId && o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.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 => o.CustomerId == ord.CustomerId && o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.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 => o.CustomerId == ord.CustomerId && o.StateId == 3 && o.OrderDate >= DateTime.UtcNow.AddYears(-5)); ord.Price *= (100 - (orders >= 5 ? 30m : orders >= 3 ? 20m : orders >= 1 ? 10m : 0)) / 100; ord.StateId = 1; _ordersRepository.SaveOrder(ord); } https://github.com/a-merson/Stachka2019 35
36
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _ с alculator.CalculateDiscountBy(order.CustomerId); order.ApplyDiscount(discount); order.State = OrderState. AwaitingPayment ; _ordersRepository.SaveOrder(order); } https://github.com/a-merson/Stachka2019 37
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _ с alculator.CalculateDiscountBy(order.CustomerId); order.ApplyDiscount(discount); order.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); order.ApplyDiscount(discount); order.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); order.ApplyDiscount(discount); order.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); order.ApplyDiscount(discount); order.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); order.ApplyDiscount(discount); order.State = OrderState. AwaitingPayment ; _ordersRepository.SaveOrder(order); } https://github.com/a-merson/Stachka2019 42
public decimal CalculateDiscountBy(long customerId) { var completedOrdersCount = _ordersRepository .GetLast5YearsCompletedOrdersCountFor(customerId); return DiscountBy(completedOrdersCount); } https://github.com/a-merson/Stachka2019 44
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 45
public void CheckoutV2(long orderId) { var order = _ordersRepository.GetOrder(orderId); var discount = _ с alculator.CalculateDiscountBy(order.CustomerId); order.ApplyDiscount(discount); order.State = OrderState. AwaitingPayment ; _ordersRepository.SaveOrder(order); } https://github.com/a-merson/Stachka2019 46
Доменная модель и бизнес - логика должны использовать ubiquitous language 47
Domain Subdomain Bounded Subdomain context Bounded context Bounded context Subdomain 48
Domain Subdomain Bounded Subdomain context Bounded context Bounded context Subdomain 49
Domain Subdomain Bounded Subdomain context Bounded context Bounded context Subdomain 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 Bounded Subdomain context Bounded context Bounded context Subdomain 58
Задачи бизнеса Программные решения Bounded Subdomain context 59
Бухгалтерия Программные решения 60
Яндекс Билеты Касса Custom Контент application 61
Архитектура и управление зависимостями 62
Micro services Domain Driven CQRS Layers Design Event- Driven 63
Цель: максимально избавить доменную логику от зависимостей 64
Presentation layer Business layer Data layer 65
Presentation layer Application layer Domain layer Infrastructure layer 66
UI & Infrastructure Application layer Domain layer 67
UI & Infrastructure Application layer Domain layer 68
UI & Infrastructure Application layer Domain layer 69
Recommend
More recommend