Коллекции и Реальность

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

Но в реальном мире все иначе. Обычно мы создаем веб-приложения с жизненным циклом запрос-процесс-ответ-смерть.

Мы должны загружать объекты из постоянной памяти, например, базы данных, работать с ними и сохранять их снова, пока процесс завершен. Это не отражает реальность, когда все работает постоянно, такой подход несовместим с доменом.

Репозиторий

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

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

Репозитории создаются для агрегатов только потому, что агрегаты являются нашими строительными блоками, нашими единицами. Они также всегда работают со всем агрегатом, а не только с внутренней частью, не с частичным агрегатом, всегда со всем агрегатом.

Репозиторий реализован на уровне домена, потому что он работает с объектами домена. Но на уровне домена мы не должны иметь представления ни о какой базе данных, ни о каком-либо хранилище, поэтому репозиторий - это просто интерфейс.

Ответственность за настойчивость

Репозиторий может отвечать за сохранение объектов. Было бы разумно иметь метод сохранения, который мгновенно сохраняет объект.

Но такого варианта использования с коллекциями памяти нет, поэтому нам придется внести в домен требования к инфраструктуре. Если бы была операция сохранения, у нас были бы проблемы с транзакциями - один объект сохраняется, а второй вызывает исключение при сохранении, и что теперь?

Решение простое. Репозиторий не отвечает за сохранение объекта. Кто-то другой отвечает за настойчивость. Мы можем обернуть варианты использования домена в слой, который отвечает за постоянство.

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

Конкретная реализация

Мы можем хранить объекты домена в реляционной базе данных, в базе данных документов, во внешней системе, подключенной через API, или во всем остальном, что мы можем себе представить. Все эти системы являются инфраструктурой домена, поэтому реализация репозитория находится на уровне инфраструктуры.

Инверсия зависимости

В шаблоне сохранения активной записи и подобных шаблонах домен зависит от инфраструктуры. Но мы создали интерфейс репозитория домена, и реализация - это инфраструктура. Уровень домена по-прежнему независим. Для тех, кто любит SOLID, все идеально сочетается друг с другом.

Реализация памяти

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

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

Тест интерфейса

Мы можем писать тесты для реализации памяти, и когда мы интегрируем хранилище базы данных, мы можем писать тесты для интеграции с базой данных. Но эти тесты могут быть очень похожими, поэтому мы можем думать только о тестировании интерфейса репозитория.

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

Больше всего я понял, что тест является абстрактным классом, а тест реализации расширяет абстрактный тест. Я бы предпочел провести один тест с несколькими поставщиками реализации, но я не нашел способа реализовать этот стиль. Если у вас есть идея получше, поделитесь комментарием.

Метод промывки дополняет настойчивость и начало новой жизни процесса. Реализация памяти не использует ее, и она подготовлена ​​для реального постоянного репозитория.

TL;DR

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

В следующий раз мы реализуем репозиторий базы данных с помощью Doctrine.

использованная литература

КЛЕМСОН, Тоби. Стратегии тестирования микросервисной архитектуры [онлайн]. 2014 [2018–01–11]. Доступно: https://martinfowler.com/articles/microservice-testing/

ЭВАНС, Эрик. Дизайн на основе предметной области: решение сложных задач в самой основе программного обеспечения. Бостон: Аддисон-Уэсли, 2004. ISBN 0–321–12521–5.

ВЕРНОН, Вон. Реализация дизайна на основе предметной области. Верхняя Сэдл-Ривер, Нью-Джерси: Addision-Wesley, 2013. ISBN 978–0–321–83457–7.

Полный код

Https://github.com/simara-svatopluk/cart/

Контакт

Вы проектируете архитектуру и вам нравится подход DDD? Наймите меня, я могу вам помочь - svatasimara.cz