Комментарии 7
Армянин?
Не требовать чистоты всего проекта одним заходом
Определи* ограниченный контекст и реализуй** его домен. Это оптимальный*** scope рефакторинга****.
(*) Придётся общаться с доменными экспертами и выяснить намерения
(**) Инварианты сначала
(***) Для систем с богатой бизнес логикой домен важнее технологий
(****) Рефакторинг это повторение старого поведения. Но доменные эксперты расскажут как должно быть, а не как реализовано. И после рефакторинга и сравнения со старым поведением придётся ещё заменить старое поведение на нужное
Нужно поменять бизнес-правило — идём в соответствующий сервис, правим его метод. Эффект автоматически распространяется наружу:
Надо полагать что луковичность предполагает что у нас сервис внутри сервиса, который внутри другого сервиса, ... В общем сказочная архитектура: игла в яйце, яйцо в утке, утка в зайце, ... Только, кажется, это придумали чтобы добраться до содержательной части (так сказать) было трудно, не очень понятно как это совместить с практическими задачами программирования. Опять сказки какие-то. Может лучше прямо называть это Капустная Архитектура? Это хотя бы к деньгам! А то со словом "луковичная" кто-то может прослезиться.
Луковая архитектура - это отличный способ сделать из простой задачи сложную, а из сложной - невыносимо сложную. Код надо структурировать на основе логических связей, а не по формальным признакам.
Удивительно, что преимущества луковой архитектуры, которые приводятся в статье, гораздо лучше достигаются, если этому паттерну не следовать. Если у вас вся логика эндпоинта прописана в обработчике, а не разбита на 5 слоёв, то любые её правки будут локализованными. Не нужно будет в голове собирать пазл из множества кусочков, а после правок перепроверять, что еще задето этими изменениями. Естественно, держать всю логику в эндпоинте - это не правило. Еще раз: надо смотреть на логические связи. Если логика дублируется, конечно, ее нужно делать переиспользуемой. Если кусок кода имеет сильные внутренние связи и слабые внешние - его можно отделить.
Отдельно обращу внимание, что эта методология нарушает причинность, что часто можно увидеть по уродливым интерфейсам нижних слоёв. Слои, обращающиеся за данными, не зависят от верхних только формально, по коду. На деле же их логика часто не является независимой, это просто вырванный кусок. Поэтому часто ему очень сложно придумать осмысленный нейминг.
Интересно увидеть, как на практике репозиторный слой держит границу транзакции. Выглядит сомнительно.
Вот банальный пример. Допустим, у вас есть юзкейс (в вашей классификации это второй "сервисный" слой). В нём необходимо выполнить регистрацию пользователя. Следовательно, это чтение из БД (проверка существования), затем запись в БД (свежий пользователь), а затем запись события в outbox (отдельная от пользователя таблица) и опционально запись события о регистрации для аудита (также отдельная таблица).
И если у вас транзакция держится на уровне UserRepository, то вам придётся пихать в репозиторий знания о том, что есть outbox и есть аудит. Это очень грязно.
По моему скромному опыту границы транзакций всё-таки определяются на уровне юзкейсов, а не на уровне репозиториев.

Луковичная архитектура: канон и где от него осознанно отступать