Переходим от Feature-based разработки к Domain Driven Design

Содержание

Слайд 2

SkyEng

Skyeng — это онлайн-школа английского языка нового поколения.
В школе работают профессионалы,

SkyEng Skyeng — это онлайн-школа английского языка нового поколения. В школе работают
помогающие жителям современных мегаполисов выучить английский язык в условиях недостатка времени.

Слайд 4

Маркетинг

Ма́рке́тинг (от англ. marketing «рыночная деятельность») — организационная функция и совокупность процессов создания, продвижения

Маркетинг Ма́рке́тинг (от англ. marketing «рыночная деятельность») — организационная функция и совокупность
и предоставления продукта или услуги покупателям и управление взаимоотношениями с ними с выгодой для организации.

Слайд 5

Маркетинг

Тратить меньше (на продвижение и предоставление)
Получать больше (увеличение аудитории, создание новых продуктов)
Деньги!

Маркетинг Тратить меньше (на продвижение и предоставление) Получать больше (увеличение аудитории, создание новых продуктов) Деньги!

Слайд 7

Что требуется от разработки

Качественно
Быстро
Дешево


Что требуется от разработки Качественно Быстро Дешево

Слайд 8

Пример

Пример

Слайд 9

Задачка

Надо сделать виджет
Дизайн есть!
Пользователь оставляет заявку
В календаре выбирает дату и время вводного

Задачка Надо сделать виджет Дизайн есть! Пользователь оставляет заявку В календаре выбирает
урока

Слайд 10

Вводный урок

Что это?

Вводный урок Что это?

Слайд 11

Задачка

Надо сделать виджет
Дизайн есть!
Пользователь оставляет заявку
В календаре выбирает дату и время вводного

Задачка Надо сделать виджет Дизайн есть! Пользователь оставляет заявку В календаре выбирает
урока

Слайд 13

Как будем делать тех. ревью?

От базы/интеграций
От api фронтенда
От проблемы бизнеса

Как будем делать тех. ревью? От базы/интеграций От api фронтенда От проблемы бизнеса

Слайд 14

И от базы/интеграций и от api

Сервис букинга — получить, выбрать, отменить
Фронтовое

И от базы/интеграций и от api Сервис букинга — получить, выбрать, отменить
api — получить, выбрать, отменить
База — таблица свзяка education_service_id, booking_slot_id
Что там дальше, подумаем потом ;)
Что думает по этому поводу бизнес?

Слайд 17

Чего хочет бизнес от разработки.

Качественно — не терять сценарии и лучше понимать

Чего хочет бизнес от разработки. Качественно — не терять сценарии и лучше
бизнес проблемы
Быстро — быстро описывать сценарии в коде в отрыве от конкретных технологий (технологии не важны)
Дешево — возможность проверять сценарии как можно раньше (оно вообще работает? может и разрабатывать не надо?)


Слайд 18

Что дальше?

Опишем сервис
Пробуем удовлетворить все 3 потребности
Посмотрим со стороны гексагональной архитектуры

Что дальше? Опишем сервис Пробуем удовлетворить все 3 потребности Посмотрим со стороны гексагональной архитектуры

Слайд 19

«Allow an application to equally be driven by users, programs, automated test

«Allow an application to equally be driven by users, programs, automated test
or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.».

— Alistair Cockburn

Позволяет взаимодействовать с приложением как пользователю, так и программам, автоматическим тестам, скриптам пакетной обработки. Также позволяет разрабатывать и тестировать приложение без каких-либо дополнительных устройств или баз данных.

Слайд 20

Hexagonal architecture / Ports and adapters

Пользователь Программы Тесты Скрипты

Базы Внешние Апи Доп. устройства

Приложение

Hexagonal architecture / Ports and adapters Пользователь Программы Тесты Скрипты Базы Внешние Апи Доп. устройства Приложение

Слайд 21

Попробуем описать сервис — Application

Приложение

Попробуем описать сервис — Application Приложение

Слайд 22

class SelfTrialBookingService
{
...
public function __construct(
OperatorsServiceInterface $operatorsService,
BookingServiceInterface $bookingService,
SelfTrialRepositoryInterface $selfTrialRepository

class SelfTrialBookingService { ... public function __construct( OperatorsServiceInterface $operatorsService, BookingServiceInterface $bookingService, SelfTrialRepositoryInterface
)
{
$this->operatorsService = $operatorsService;
$this->bookingService = $bookingService;
$this->selfTrialRepository = $selfTrialRepository;
}
}

Какие сервисы нужны? (что если их нет? или есть?)
Что нам понадобится от них?
Что нужно от репозитория?

Слайд 23

interface OperatorsServiceInterface
{
public function holdCall(int $educationServiceId, DateInterval $interval, string $reason): void;
public

interface OperatorsServiceInterface { public function holdCall(int $educationServiceId, DateInterval $interval, string $reason): void;
function disableCall(int $educationServiceId, string $reason): void;
public function enableCall(int $educationServiceId, string $reason): void;
}

Отложить звонок, сразу после заявки
Отменить звонок вообще, если пользователь выбрал дату/время
Назначить звонок, если пользователь передумал

Слайд 24

interface BookingServiceInterface
{
public function bookSlot(string $slotId, string $reason): void;
public function cancelSlot(string

interface BookingServiceInterface { public function bookSlot(string $slotId, string $reason): void; public function
$slotId, string $reason): void;
public function isSlotAvailableForEducationService(string $slotId, int $educationServiceId): bool;
public function getAvailableSlots();
}

Выбрать дату/время
Отменить дату/время
Проверить подходит ли дата/время
Получить список дат/времени

Слайд 25

interface SelfTrialRepositoryInterface
{
public function save(SelfTrial $selfTrial);
public function getSelfTrialByEducationServiceId(int $educationServiceId): ?SelfTrial;
}

Сохранить
Получить

interface SelfTrialRepositoryInterface { public function save(SelfTrial $selfTrial); public function getSelfTrialByEducationServiceId(int $educationServiceId): ?SelfTrial; } Сохранить Получить

Слайд 26

public function startSelfTrialProcess(int $educationServiceId): void
{
$this->operatorsService->holdCall(
$educationServiceId,
new DateInterval(self::HOLD_CALL_INTERVAL),
'self_trial'
);
$selfTrial

public function startSelfTrialProcess(int $educationServiceId): void { $this->operatorsService->holdCall( $educationServiceId, new DateInterval(self::HOLD_CALL_INTERVAL), 'self_trial' );
= SelfTrial::start($educationServiceId);
$this->selfTrialRepository->save($selfTrial);
}

public static function start(int $educationServiceId) : SelfTrial
{
$instance = new self($educationServiceId);
$instance->status = SelfTrialStatus::STARTED();
return $instance;
}

Слайд 28

public function bookSlot(int $educationServiceId, string $slotId, string $reason): void
{
$selfTrial = $this

public function bookSlot(int $educationServiceId, string $slotId, string $reason): void { $selfTrial =
->selfTrialRepository
->getSelfTrialByEducationServiceId($educationServiceId);
//Валидация и DomainException
$this->bookingService->bookSlot($slotId, $reason);
$this->operatorsService->disableCall($educationServiceId, $reason);
$selfTrial->bookSlot($slotId);
$this->selfTrialRepository->save($selfTrial);
}

public function bookSlot(string $slotId)
{
$this->slotId = $slotId;
$this->status = SelfTrialStatus::BOOKED();
}

Слайд 30

public function cancelSelfTrial(int $educationServiceId, string $reason): void
{
$selfTrial = $this
->selfTrialRepository
->getSelfTrialByEducationServiceId($educationServiceId);

public function cancelSelfTrial(int $educationServiceId, string $reason): void { $selfTrial = $this ->selfTrialRepository
//Валидация и DomainException
$this->bookingService->cancelSlot($selfTrial->getSlotId(), $reason);
$this->operatorsService->enableCall($educationServiceId, $reason);
$selfTrial->cancel();
$this->selfTrialRepository->save($selfTrial);
}

public function cancel()
{
$this->status = SelfTrialStatus::CANCELLED();
}

Слайд 32

Application

Качественно — не терять сценарии и лучше понимать бизнес проблемы
Быстро — быстро

Application Качественно — не терять сценарии и лучше понимать бизнес проблемы Быстро
описывать сценарии в коде в отрыве от конкретных технологий (технологии не важны)
Дешево — возможность проверять сценарии как можно раньше (оно вообще работает? может и разрабатывать не надо?)


Слайд 33

Насколько это гибко?

Вот тут будет кнопка отмены!!!

Насколько это гибко? Вот тут будет кнопка отмены!!!

Слайд 35

Насколько это гибко?

Насколько это гибко?

Слайд 36

public function bookSlot(int $educationServiceId, string $slotId, string $reason): void
{
$selfTrial = $this

public function bookSlot(int $educationServiceId, string $slotId, string $reason): void { $selfTrial =
->selfTrialRepository
->getSelfTrialByEducationServiceId($educationServiceId);
//Валидация и DomainException
$this->bookingService->bookSlot($slotId, $reason);
$this->operatorsService->disableCall($educationServiceId, $reason);
$this->operatorsService->enableCall($educationServiceId, $reason);
$selfTrial->bookSlot($slotId);
$this->selfTrialRepository->save($selfTrial);
}

Слайд 37

+ обновление деталей звонка

Да

+ обновление деталей звонка Да

Слайд 38

При чем тут DDD?

Ubiquitous Language (единый язык)
Можно показать заказчику
Если не поймет, покрыть

При чем тут DDD? Ubiquitous Language (единый язык) Можно показать заказчику Если
BDD тестом
Bounded Context (контекст предметной области)

Слайд 39

Hexagonal architecture / Ports and adapters

Пользователь Программы Тесты Скрипты

Базы Внешние Апи Доп. устройства

Приложение

Hexagonal architecture / Ports and adapters Пользователь Программы Тесты Скрипты Базы Внешние Апи Доп. устройства Приложение

Слайд 40

Более красивая картинка ;)

https://herbertograca.com/2017/09/14/ports-adapters-architecture/

Более красивая картинка ;) https://herbertograca.com/2017/09/14/ports-adapters-architecture/

Слайд 41

Зачем

Позволяет концентрироваться на домене
Выделение бизнес логики
Тесты
Заменяемые элементы
Дисциплина (именование папок, куда что положить)

Зачем Позволяет концентрироваться на домене Выделение бизнес логики Тесты Заменяемые элементы Дисциплина

Слайд 42

Заметки на полях

Что с атомарностю (@synchronized)?
Почему не ивенты из модели?
Где эксепшены?

Заметки на полях Что с атомарностю (@synchronized)? Почему не ивенты из модели? Где эксепшены?