Обновить
8
1
Леонид Сухин@leva1981

Java разработчик

Отправить сообщение

Ну все таки DDD это про перенос логики прямо в доменный объект. А если логика оттуда выехала, то это уже анемичная модель.

Но это я так, просто расставить точки над i. Мне самому не до конца нравится история, что в классическом DDD все равно приходится сидеть на шпагате - часть логики у нас в классах доменных объектов, а часть (это неизбежно) выезжает в отдельные сервисы.

Принял по всем пунктам, большое спасибо за развернутые ответы!

"Доменные модели лично я запрещал с логикой. Дата-классы." - тут просто решили не связываться с DDD ?

Не NDA конечно. Обычные человеческие слабости. Сложно, не нужно, непонятно, непривычно, избыточно...

За структуру спасибо, очень интересно! Есть несколько вопросов.

1) АПИ в отдельном слое/модуле - ок. Домен в отдельном слое/модуле - ок. Но насколько оправданно выносить из слоя api слои connector, messaging-int, web? Не было бы удобнее перенести их в app ? Ведь по сути это то, что нужно для работы приложения.

2) Почему домен разбит на два модуля - domain и domain-logic? Не является ли это избыточным разбиением? Сущности домена - анемичные или с логикой? Если с логикой, то не является ли избыточным domain-logic и почему дополнительная логика не реализована в app/service вместо целого модуля domain-logic?

3) Насколько оправдан вынос entity из домена? Я имею ввиду, почему не стали реализовывать entity используя доменные объекты, а вместо этого решились на введение дополнительных мапперов и конвертаций? Насколько это оправданно и удобно?

4) Где тесты (вижу только пакет с интеграционными) ? :)

Не, не, не)) Вместо картинки лучше уж в самых простых вариантах пример. Я сам сторонник такого подхода, но подступиться очень тяжело. И самому тяжело и плюс сопротивление коллег как правило нешуточное. Какое там апи, которое аналитики напишут с архитектором... Сваггер + @Schema наше все, rest-service-dao самые лучшие и понятные слои. И вообще, работать надо, а не фигней всякой страдать, времени на это сейчас нету...

Отличная статья. Но довольно сложная для восприятия, потому что тема на самом деле ооооочень многогранная и сложная.

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

Дмитрий, возможно не совсем понял вопрос. Подход, который я описал, используется в ci/cd реальных проектов. Ежедневно делаем сборки, Jenkins, ранее TeamCity. Оверхед в виде дополнительного времени конечно присутствует. Но все работает.

Дефолтные параметры я обычно не менял. Думаю, для подобных экспериментов лучше не интеграционные тесты, а полноценное нагрузочное тестирование.

Я был в такой ситуации и с Zonky, он же EmbeddedPostgres, Embedded... работал.

По времени работы не соглашусь. Если вы присмотритесь, то обнаружите, что у него под капотом те же тестконтейнеры. Одним словом, шило на мыло в условиях корпоративных ограничений.

По покрытию. Посмотрите пожалуйста ответ на коммент выше, там где много букв. Я не предлагаю все методы покрывать интеграционниками. Достаточно happy path по всем сутевым кейсам. Юнит-тесты никто не отменял, через них прекрасно тестируется бизнес логика, если она не содержит зависимостей (DDD, утильные классы и библиотеки, просто отдельные методы с вынесенной в них логикой, ветвления с exception для повышения покрытия по параметру branch). Веду к тому, что и интеграционных тестов и юнитов должно быть ровно столько сколько нужно, чтобы покрыть все, что реально надо покрыть и что-бы эта история была устойчива к рефакторингу, насколько это возможно.

Ок, давайте подискутируем. У Хорикова описывается довольно много различных подходов, а также их плюсы и минусы. Как мне показалось, одна из ключевых мыслей Хорикова - что необходимо уйти от хрупких тестов Лондонской школы, когда мокается все и вся и по возможности использовать тесты, которую тестируют ваше приложение по принципу "черного ящика" и тестируют не классы, а определенный функционал. Но повторюсь - в книге разобрано много кейсов и мой ключевой вывод это только мой вывод.

Я не ставил себе целью показать все подходы, описанные у Хорикова. Я упомянул его книгу потому что а) она реально очень крутая и б) в ней основная мысль про то, что тестировать "черный ящик" гораздо лучше, чем "белый ящик", если можно так выразиться.

Основная цель статьи - научить людей пользоваться тест-контейнерами и сделать это быстро. Из моего опыта чтения других туториалов - как правило все требуется дорабатывать напильником, часто очень и очень много, моя же цель была дать реально production-ready инструмент, чтобы можно было сосредоточиться на тестах, а не мудохаться неделю с первичной настройкой.

Теперь про подход.

Пишем интеграционные тесты на все happy path. С поднятием инфры через тест-контейнеры и так далее. Так ты точно знаешь, что все связки отрабатывают насквозь, по крайней мере по одному положительному сценарию. Это кстати уже обычно дает примерно 65-70% покрытия кода.

Затем по мере возможности ты выносишь бизнес-логику в отдельные методы. Цель - метод без внешних зависимостей, без внешних сервисов. Такие методы от и до тестируешь через юнит-тесты. Подобные тесты неплохо пишет ИИ, с обработкой кучи корнер-кейсов (только за ИИ обязательно все надо перепроверить). Таким образом прекрасно тестируется вся логика, если вам повезло практиковать DDD-подход. То есть если у тебя есть бизнес-логика без зависимостей, то ее все так же тестируем через юниты. Это очень годно работает для всяких библиотек, которые что-нибудь считают, или там регулярками обрабатывают. Там прямо юниты рулят.

Что касается тестирования простых объектов. Этого нет в докладе и коде, но да, объекты типа dto, репозитории и тому подобное необходимо вообще исключать из анализа тестового покрытия, включать их в исключения JaCoCo/Сонара. Это не вошло в реализацию и в доклад.

Что касается "прикручиваете прорву моков, которые на запросы к базе возвращают кучу данных и на методы сохранения в базу прикручиваете моки, которые проверяют, что вы пытаетесь сохранить а базу. Еще и пытаетесь наверное, протестировать, как sql-ки формируются." Тут уж извините, но вам стоит повнимательнее еще раз прочитать доклад и посмотреть код. В том то и дело, что я не прикручиваю моки. Я поднимаю реальную инфру, которая нужна для функционирования сервиса. Реальный Пострес, реальную Кафку, реальный Редис (тут его нет) и так далее. И потом тестирую максимально реальное поведение сервиса. Мне не надо тестировать "sql-ки формируются" потому что я тестирую конечный результат. Дал на вход определенные параметры, в рест или кафку, и жду определенного результата - появления/изменения данных в базе, исходящего сообщения в очередь, вызова внешнего сервиса... Исходя из того, что вы пишите, создается впечатление, что как в анекоде из СССР - "Пастернака не читал. Но осуждаю". Так же и вы невнимательно по диагонали прочитали статью и судя по всему не удосужились посмотреть код. Пожалуйста, дайте статье и коду второй шанс - приглядитесь. Возможно, вы в итоге до конца не согласитесь с моим подходом и реализацией, но совершенно точно ваша критика будет другой.

Возможно вы слишком категоричны. Можете развернуть комментарий?

По первому вопросу - у меня мало опыта "натравливания" LLM на репозитории)) Наверно наличие фрагментов кода под комментами (ИЛИ-ИЛИ) действительно может создать некоторые затруднения. Но мне реально не хотелось делать две разные ветки, которые бы отличались буквально четырьмя строками кода и наличием/отсутствием одного-двух файлов. Я оставил все в одной куче специально, чтобы было сразу видно в чем собственно отличия. Наверно есть смысл форкнуть, удалить лишнее и уже после этого натравить LLM.

По второму вопросу - можно использовать в любых проектах.

Спасибо за статью. Подскажите пожалуйста, с каким минимальным железом стоит заходить?

Иван, браво! Потрясающая статья!

Норм, понял. Правки внес, спасибо! Текст не переведенный, писал сам. Но этот момент пропустил.

Не соображу, о чем речь. Возможно ошибаюсь, но Formatter это про преобразование только в одну сторону.

Информация

В рейтинге
1 807-й
Откуда
Рязань, Рязанская обл., Россия
Дата рождения
Зарегистрирован
Активность

Специализация

Бэкенд разработчик, Разработчик приложений
Средний
От 100 000 ₽
Java
Spring Boot
Java Spring Framework
Hibernate
PostgreSQL
REST
Junit
SQL
Git
Docker