Основы доменной модели

2,836 views

Published on

Minsk Symfony 2 User Group 31.01.2014

Published in: Technology
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,836
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
32
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide

Основы доменной модели

  1. 1. DDD Основы доменной модели
  2. 2. Основные понятия Контекст - ограниченная зона ответственности. Сущность - модель объекта предметной области. Сводный корень - сущность, предоставляющая общий API. Объект-значение - свойство объектов предметной области. Службы - операции характерные для предметной области.
  3. 3. Знакомьтесь, доменный эксперт. Доменный эксперт - человек или группа людей обладающие необходимыми знаниями и опытом в предметной области.
  4. 4. Hello world! Система управления складом. Задачи: 1) Упорядочить прием товаров на склад. 2) Организовать систему заявок на выдачу. 3) Оповещать менеджмент о нехватке товаров.
  5. 5. Первый взгляд Как я представляю склад: Т О В А Р Ы Склад М А Г А З И Н Как Geek&Poke видят склад:
  6. 6. Единый язык Система терминов, понятная как IT специалисту, так и эксперту в предметной области. ent? m Ship Goods ? Ite Product! m?
  7. 7. Доменный эксперт говорит что... “Поставщики привозят на склад контейнеры с товарами.” Поставщик Контейнер Склад Поставщик Контейнер
  8. 8. Доменный эксперт говорит что... “В каждом контейнере могут быть разные товары и в разном количестве, кроме того у каждого товара есть срок годности.” Контейнер Товар: Продукт: Товар: - название; Товар: - название; - срок год.; - название; - срок год.; - срок год. Товар: - название; - срок год. Товар: Товар: - название; - название; - срок год.; - срок год.
  9. 9. Доменный эксперт говорит что... “Когда товар попадает на склад, мы записываем дату поступления.” Склад Товар: Товар: - название; Товар: - название; - срок год.; - название; - срок год.; - дата пос. - срок год.; - дата пос. - дата пос.
  10. 10. Промежуточный итог Контейнер Пр Товар Товар Товар Товар Товар Товар Склад Контейнер Пр Товар Товар Товар Товар Товар Товар Товар Товар Товар Да, да… очень похоже на то, что у нас происходит.
  11. 11. Пишим код ..! Product 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. class Product { public function __construct(Name $name, DateTime $expirationDate ) { $this->name = $name; $this->expirationDate = $exipationDate ; } public function accept(DateTime $deliveryDate) { $this->deliveryDate = $deliveryDate; return $this; } public function isExpired() { return $this->expirationDate > new DateTime(); } }
  12. 12. Пишим код ..! Container 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. class Container { private $products; public function __construct(array $products) { Assertion ::allIsInstanceOf ($products, 'Product'); $this->products = $products; } public function getProducts() { return $this->products; } }
  13. 13. Пишим код ..! Supplier 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. class Supplier { public function sendProducts(Warehouse $receiver, array $products) { $this->sendContainer($receiver, new Container($products)); } public function sendContainer (Warehouse $receiver, Container $container) { $receiver->acceptContainer ($container); } }
  14. 14. Пишим код ..! Warehouse 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. class Warehouse { private $products; public function acceptContainer (Container $container) { $now = new DateTime(); $products = $container->getProducts(); foreach ($products as $product) { $name = $product->getName(); $this->products[$name][] = $product->accept($now); } } }
  15. 15. Доменный эксперт говорит что... “Кажется мы забыли упомянуть что у нас два склада, и еще один строится рядом с кольцевой.” Склад - номер - адрес - статус Склад - номер - адрес - статус Склад - номер - адрес - статус
  16. 16. Рефакторим ..! Warehouse. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. class Warehouse implements Entity { private $id; private $address; private $status; public function __construct(WarehouseId $id, Address $address, Status $status = null) { $this->id = $id; $this->address = $address; $this->status = $status ?: new Status(Status::CLOSED); } public function acceptContainer (Container $container) { if ($this->status->isClosed()) { throw new Exception("Warehouse closed" ); } ... }
  17. 17. Объекты-значения 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. class Status { const CLOSED = 0; const OPENED = 1; 1) Равенство объектов-значений основано на равенстве их полей. private $value; public function __construct($value) { $this->value = $value; } 3) Строковое представление объектов-значений должно быть однозначно. public function isClosed() { return self::CLOSED === $this->value; } } 2) Объекты-значения неизменны. 4) Объекты значения могут хранить не только примитивы, но и другие объекты и даже сущности.
  18. 18. Сущности 1) Равенство сущностей основано на равенстве их идентификаторов. Кстати, неплохо было бы знать какой именно поставщик нам привез эти помидоры. 2) Основная единица бизнеслогики. 3) Имена сущностей и их методы должны иметь смысл в контексте единого языка.
  19. 19. Рефакторим ..! Supplier 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. class Supplier implements Entity { private $id; public function __construct(SupplierId $id) { $this->id = $id; } public function getId() { return $this->id; } public function sendProducts(Warehouse $receiver, array $products) { $this->sendContainer(new Container($products, $this )); } ...
  20. 20. Система управления складом 1) Упорядочить прием товаров на склад. 2) Организовать систему заявок на выдачу. 3) Оповещать менеджмент о нехватке товаров.
  21. 21. Доменный эксперт говорит что... “Магазины подают заявки на получение товаров со склада.” Заявка Магазин Склад Заявка
  22. 22. Доменный эксперт говорит что... “В заявке указаны требуемые наименования товаров и их количество.” Заявка - номер; - товар => кол-во.; - товар => кол-во.; - товар => кол-во.; - товар => кол-во.; - ... Ну и, естественно, мы не отгружаем товары с истекшим сроком годности. Их надо сразу списывать.
  23. 23. Доменный эксперт говорит что... “Если на складе достаточно товаров, то заявке одобряется и машина с товарами отправляется в магазин.” Заявка Магазин Склад Машина
  24. 24. Пишим код ..! Receipt 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. class Receipt implements Entity { public function __construct(ReceiptId $id, Shop $receiver) { $this->id = $id; $this->receiver = $receiver; } public function addRequire(Name $name, $count) { Assertion ::integer($count); Assertion ::greater($count, 0); $this->requires[$name] = $count; } public function getList() { return $this->requires; } }
  25. 25. Пишим код ..! Shop 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. class Shop implements Entity { private $id; private $address; public function __construct(ShopId $id, Address $address) { $this->id = $id; $this->address = $address; } public function createReceipt (array $products) { $receipt = new Receipt(new ReceiptId(new DateTime), $this); foreach ($products as $name => $count) { $receipt->addRequire(new Name($name), $count); } return $receipt; } }
  26. 26. Пишим код ..! Warehouse 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. class Warehouse implements Entity { public function resolveReceipt (Receipt $receipt) { $toSend = []; foreach ($receipt->getList() as $name => $count) { $available = $this->getAvailable($name); if ($count > count($available)) { throw new AvailableException ($name, $available, $count); } $needed = array_slice($available, 0, $count); $toSend = array_merge($toSend, $needed); $this->writeOff($needed, new Reason('Resolved for receipt №' .$receipt->getId())); } $receipt->resolve(new DateTime()); return new Car($toSend); } }
  27. 27. Сводный корень А как изменять статус заявки? Сущность Warehouse производит все бизнес-операции с сущностью Receipt и отвечает за изменение ее статуса: одобрено или отложено. В данном случае сущность Warehouse является сводным корнем. В различных контекстах возможны разные сводные корни, например Receipt может быть сводным корнем для Product.
  28. 28. Контекст В данном примере мы имеем два распределенных контекста: поставщиксклад и склад-магазин. Поставщик Контейнер Заявка Магазин Склад Поставщик Контейнер Машина
  29. 29. Система управления складом 1) Упорядочить прием товаров на склад. 2) Организовать систему заявок на выдачу. 3) Оповещать менеджмент о нехватке товаров.
  30. 30. Доменный эксперт говорит что... “Знаете, мы понятия не имеем, что нужно знать менеджерам и как они работают с нашим складом. Давайте поговорим об этом завтра с Аланом.” Код домена и задание от Алана можно посмотреть на GitHub.
  31. 31. Вопросы? Антон Шабовта E-mail: zloyusr@gmail.com Facebook: https://www.facebook.com/zloyusr VK: http://vk.com/shabouta

×