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

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

  • Upload
    -

  • View
    592

  • Download
    1

Embed Size (px)

DESCRIPTION

Minsk Symfony 2 User Group 31.01.2014

Citation preview

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

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

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

Основные понятия

Контекст - ограниченная зона ответственности.Сущность - модель объекта предметной области.Сводный корень - сущность, предоставляющая общий API.Объект-значение - свойство объектов предметной области.Службы - операции характерные для предметной области.

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

Знакомьтесь, доменный эксперт.

Доменный эксперт - человек или группа людей обладающие необходимыми знаниями и опытом в предметной области.

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

Hello world!

Система управления складом.Задачи:1) Упорядочить прием товаров на склад.2) Организовать систему заявок на выдачу.3) Оповещать менеджмент о нехватке товаров.

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

Первый взгляд

Как я представляю склад:

Как Geek&Poke видят склад:

ТОВАРЫ

Склад

МАГАЗИН

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

Единый язык

Система терминов, понятная как IT специалисту, так и эксперту в предметной области.

Goods?

Shipment? Item?

Product!

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

Доменный эксперт говорит что...

“Поставщики привозят на склад контейнеры с товарами.”

Склад

Поставщик

Поставщик

Контейнер

Контейнер

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

Доменный эксперт говорит что...

“В каждом контейнере могут быть разные товары и в разном количестве, кроме того у каждого товара есть срок годности.”

Продукт:- название;- срок год.;

Контейнер

Товар:- название;- срок год.

Товар:- название;- срок год.;

Товар:- название;- срок год.;

Товар:- название;- срок год.;

Товар:- название;- срок год.

Товар:- название;- срок год.

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

Доменный эксперт говорит что...

“Когда товар попадает на склад, мы записываем дату поступления.”

Склад

Товар:- название;- срок год.;- дата пос.

Товар:- название;- срок год.;- дата пос.

Товар:- название;- срок год.;- дата пос.

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

Промежуточный итог

СкладТовар

ТоварТовар

ПрКонтейнерТоварТовар

ТоварТовар

ТоварТовар

ПрКонтейнерТоварТовар

ТоварТовар

ТоварТовар

Да, да… очень похоже на то, что у нас происходит.

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

Пишим код ..! Product1. class Product2. {3. public function __construct(Name $name, \DateTime $expirationDate)4. {5. $this->name = $name;6. $this->expirationDate = $exipationDate;7. }8. 9. public function accept(\DateTime $deliveryDate)10. {11. $this->deliveryDate = $deliveryDate;12. return $this;13. }14. 15. public function isExpired()16. {17. return $this->expirationDate > new \DateTime();18. }19. }

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

Пишим код ..! Container1. class Container2. {3. private $products;4. 5. public function __construct(array $products)6. {7. Assertion::allIsInstanceOf($products, 'Product');8. 9. $this->products = $products;10. }11. 12. public function getProducts()13. {14. return $this->products;15. }16. }

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

Пишим код ..! Supplier1. class Supplier2. {3. public function sendProducts(Warehouse $receiver, array $products)4. {5. $this->sendContainer($receiver, new Container($products));6. }7. 8. public function sendContainer(Warehouse $receiver, Container $container)9. {10. $receiver->acceptContainer($container);11. }12. }

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

Пишим код ..! Warehouse1. class Warehouse2. {3. private $products;4. 5. public function acceptContainer(Container $container)6. {7. $now = new \DateTime();8. $products = $container->getProducts();9. 10. foreach ($products as $product) {11. $name = $product->getName();12. $this->products[$name][] = $product->accept($now);13. }14. }15. }

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

Доменный эксперт говорит что...

“Кажется мы забыли упомянуть что у нас два склада, и еще один строится рядом с кольцевой.”

Склад- номер- адрес- статус

Склад- номер- адрес- статус

Склад- номер- адрес- статус

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

Рефакторим ..! Warehouse.1. class Warehouse implements Entity2. {3. private $id;4. private $address;5. private $status;6.7. public function __construct(WarehouseId $id, Address $address, Status $status = null)8. {9. $this->id = $id;10. $this->address = $address;11. $this->status = $status ?: new Status(Status::CLOSED);12. }13. 14. public function acceptContainer(Container $container)15. {16. if ($this->status->isClosed()) {17. \throw new Exception("Warehouse closed");18. }19. 20. ...21. }

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

Объекты-значения1. class Status2. {3. const CLOSED = 0;4. const OPENED = 1;5. 6. private $value;7. 8. public function __construct($value)9. {10. $this->value = $value;11. }12. 13. public function isClosed()14. {15. return self::CLOSED === $this->value;16. }17. }

1) Равенство объектов-значений основано на равенстве их полей.2) Объекты-значения неизменны.3) Строковое представление объектов-значений должно быть однозначно.4) Объекты значения могут хранить не только примитивы, но и другие объекты и даже сущности.

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

Сущности

1) Равенство сущностей основано на равенстве их идентификаторов.2) Основная единица бизнес-логики.3) Имена сущностей и их методы должны иметь смысл в контексте единого языка.

Кстати, неплохо было бы знать какой именно поставщик нам привез эти помидоры.

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

Рефакторим ..! Supplier1. class Supplier implements Entity2. {3. private $id;4. 5. public function __construct(SupplierId $id)6. {7. $this->id = $id;8. }9. 10. public function getId()11. {12. return $this->id;13. }14. 15. public function sendProducts(Warehouse $receiver, array $products)16. {17. $this->sendContainer(new Container($products, $this));18. }19. 20. ...

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

Система управления складом

1) Упорядочить прием товаров на склад.2) Организовать систему заявок на выдачу.3) Оповещать менеджмент о нехватке товаров.

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

Доменный эксперт говорит что...

“Магазины подают заявки на получение товаров со склада.”

СкладМагазин

Заявка

Заявка

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

Доменный эксперт говорит что...

“В заявке указаны требуемые наименования товаров и их количество.”Заявка- номер;- товар => кол-во.;- товар => кол-во.;- товар => кол-во.;- товар => кол-во.;- ...

Ну и, естественно, мы не отгружаем товары с истекшим сроком годности.Их надо сразу списывать.

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

Доменный эксперт говорит что...

“Если на складе достаточно товаров, то заявке одобряется и машина с товарами отправляется в магазин.”

СкладМагазин

Машина

Заявка

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

Пишим код ..! Receipt1. class Receipt implements Entity2. {3. public function __construct(ReceiptId $id, Shop $receiver)4. {5. $this->id = $id;6. $this->receiver = $receiver;7. }8. 9. public function addRequire(Name $name, $count)10. {11. Assertion::integer($count);12. Assertion::greater($count, 0);13. 14. $this->requires[$name] = $count;15. }16. 17. public function getList()18. {19. return $this->requires;20. }21. }

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

Пишим код ..! Shop1. class Shop implements Entity2. {3. private $id;4. private $address;5. public function __construct(ShopId $id, Address $address)6. {7. $this->id = $id;8. $this->address = $address;9. }10. 11. public function createReceipt(array $products)12. {13. $receipt = new Receipt(new ReceiptId(new \DateTime), $this);14. 15. foreach ($products as $name => $count) {16. $receipt->addRequire(new Name($name), $count);17. }18. 19. return $receipt;20. }21. }

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

Пишим код ..! Warehouse1. class Warehouse implements Entity2. {3. public function resolveReceipt(Receipt $receipt)4. {5. $toSend = [];6. foreach ($receipt->getList() as $name => $count) {7. $available = $this->getAvailable($name);8. if ($count > count($available)) {9. throw new \AvailableException($name, $available, $count);10. }11. 12. $needed = array_slice($available, 0, $count);13. $toSend = array_merge($toSend, $needed);14. $this->writeOff($needed, new Reason('Resolved for receipt №'.$receipt->getId()));15. }16.17. $receipt->resolve(new \DateTime());18.19. return new Car($toSend);20. }21. }

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

Сводный корень

Сущность Warehouse производит все бизнес-операции с сущностью Receipt и отвечает за изменение ее статуса: одобрено или отложено.В данном случае сущность Warehouse является сводным корнем.В различных контекстах возможны разные сводные корни, например Receipt может быть сводным корнем для Product.

А как изменять статус заявки?

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

Контекст

В данном примере мы имеем два распределенных контекста: поставщик-склад и склад-магазин.

СкладМагазин

Машина

ЗаявкаПоставщик

Поставщик

Контейнер

Контейнер

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

Система управления складом

1) Упорядочить прием товаров на склад.2) Организовать систему заявок на выдачу.3) Оповещать менеджмент о нехватке товаров.

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

Доменный эксперт говорит что...

“Знаете, мы понятия не имеем, что нужно знать менеджерам и как они работают с нашим складом. Давайте поговорим об этом завтра с Аланом.”

Код домена и задание от Алана можнопосмотреть на GitHub.

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

Вопросы?

Антон ШабовтаE-mail: [email protected]

Facebook: https://www.facebook.com/zloyusrVK: http://vk.com/shabouta