Из схемы модуля видно что при обращении к модулю идёт вызов к Anti-Corruption Layer, а не к менеджеру модуля.
В тексте и изображении схемы всё верно. При обращении к другому модулю ACL нашего модуля вызывает их менеджер.
Anti-Corruption Layer скорее всего это и есть слой Presentation
Слой Presentation о другом: он содержит view-хи и прочие представления данных. Задача ACL создать собственный dto, класс которого расположен у нас, в нашем модуле. Это позволяет использовать его у себя в модуле без порождения внешних зависимостей. Такой подход дополнительно обеспечивает безопасность от изменений в других модулях: у них в ответе от менеджера 10 свойств, мы используем только 2, любые изменения остальных 8 никак не отразятся на нашем модуле. Оставшиеся 2 свойства, которые используются, не дадут повредить статические анализаторы.
Ещё один плюс такого подхода, который хочется отметить, это то, что все “мапперы”, реализующие ACL, располагаются системно. Всегда знаешь где их искать у себя и в других модулях. Узнать список модулей, от которых зависит твой, просто и быстро.
Непонятно что именно понимается под блоком Components и где находится блок доменной логики?
Components и есть блок доменной логики. Как видно из схемы, блоки Components, Dto, Models и прочие расположены внутри объединяющего их, группирующего блока Domain. Все они находятся внутри директории Domain каждого модуля.
Наоборот, благодаря такому подходу кода в файлах становится меньше. Внутри одного модуля мы используем не один глобальный менеджер, а несколько небольших.
Каждый из них создается под узкий круг задач и отвечает за конкретную таблицу в БД или отдельную сферу. Иногда встречаются менеджеры всего с одним методом — это удобно для будущего расширения логики в этой конкретной области. Нам предпочтительнее создать 10 разных специализированных менеджеров внутри одного контекста, чем плодить один гигантский класс на 100500 строк.
Мы взяли классический Onion лишь за основу и адаптировали его под реалии Flowwow. В итоге у нас получилась своя архитектура: слой Application заменил Infrastructure, став публичным.
Мы не переносили Infrastructure в доменный слой — мы от него полностью отказались. Точкой входа и границей модуля стал Application. Да, в некоторых модулях внутри приватной области можно встретить раздел Infrastructure, но он несет совершенно другой смысл. Там мы пишем “провайдеры” для связи со сторонними внешними сервисами.
Как видится мне - разделением на модули вы получаете дублирование кода
Дублирование кода сведено к минимуму благодаря жесткому разделению предметных областей. Команда товаров занимается только товарами, команда гео — картами. Им концептуально негде написать один и тот же код.
у вас на каждый юзер кейс сколько обращений к базе?
Количество обращений к БД зависит от задачи: где-то хватает одного, где-то их десятки. Как правило такие сложные процессы уходят в очередь и выполняются постепенно
У каждого модуля свои обращения? А как на счёт сложных join запросов?
Каждый модуль работает только со своими таблицами в базе, через модели, расположенные внутри модуля. Эти модели не дублируются в других модулях. Получить от них данные можно только через менеджеры. Да и сами модели менеджеры не вернут, они преобразуют их в DTO. Сложные join разрешаем по разному: иногда, в рамках одного контекста, когда обе таблицы ему принадлежат, прописываем связи между моделями, как заложено в ActiveRecord. В других случаях, когда модели из разных контекстов, рассматриваем отдельно.
Зачастую связи прописывать не нужно вовсе, подобные задачи решаются в несколько запросов: достаточно отдельно получить id из одной таблицы и добавить их в запрос к другой, а вторым запросом, уже в своем модуле, можно получить результат. Только в исключительных, редких кейсах, когда действительно нужна оптимизация, мы договариваемся о применении прямых запросов к базе. Что согласовывается с архитектором, либо DBA командой отдельно.
разве много бизнес задачи которые затрагивают 1 конкретный модуль? Большинство задач превращается в тим билдинги?
Полностью изолированных задач, которые решаются внутри одного модуля, у нас много. Если же для бизнес-задачи нужны данные из соседнего контекста, разработчик просто вызывает менеджер чужого модуля. Благодаря единой структуре всех модулей чужой код читается легко. Идти к соседям в чат нужно только в одном случае — если нужного метода еще не существует. И это скорее плюс: владельцы контекста всегда подскажут наиболее оптимальное решение для своей зоны ответственности.
Любой модуль при необходимости можно вынести в отдельный сервис без радикальной переработки.
Модуль действительно уедет в отдельный сервис вместе со своим фреймворком. Но главное преимущество в том, что теперь появилась возможность сделать это за пару дней, а не за месяц. Четкая структура, локализованные внешние связи в менеджерах и зависимости, описанные в deptrac, делают процесс переноса значительно проще.
Я очень сильно надеюсь что вы здесь не про инверсию зависимостей
Да, в тексте описано направление подключения классов. О том, что обращение к модулю опирается на application, а он на domain, только в таком порядке.
В тексте и изображении схемы всё верно. При обращении к другому модулю ACL нашего модуля вызывает их менеджер.
Слой Presentation о другом: он содержит view-хи и прочие представления данных. Задача ACL создать собственный dto, класс которого расположен у нас, в нашем модуле. Это позволяет использовать его у себя в модуле без порождения внешних зависимостей. Такой подход дополнительно обеспечивает безопасность от изменений в других модулях: у них в ответе от менеджера 10 свойств, мы используем только 2, любые изменения остальных 8 никак не отразятся на нашем модуле. Оставшиеся 2 свойства, которые используются, не дадут повредить статические анализаторы.
Ещё один плюс такого подхода, который хочется отметить, это то, что все “мапперы”, реализующие ACL, располагаются системно. Всегда знаешь где их искать у себя и в других модулях. Узнать список модулей, от которых зависит твой, просто и быстро.
Components и есть блок доменной логики. Как видно из схемы, блоки Components, Dto, Models и прочие расположены внутри объединяющего их, группирующего блока Domain. Все они находятся внутри директории Domain каждого модуля.
Наоборот, благодаря такому подходу кода в файлах становится меньше. Внутри одного модуля мы используем не один глобальный менеджер, а несколько небольших.
Каждый из них создается под узкий круг задач и отвечает за конкретную таблицу в БД или отдельную сферу. Иногда встречаются менеджеры всего с одним методом — это удобно для будущего расширения логики в этой конкретной области. Нам предпочтительнее создать 10 разных специализированных менеджеров внутри одного контекста, чем плодить один гигантский класс на 100500 строк.
Спасибо за комментарий! Давайте по порядку.
Мы взяли классический Onion лишь за основу и адаптировали его под реалии Flowwow. В итоге у нас получилась своя архитектура: слой Application заменил Infrastructure, став публичным.
Мы не переносили Infrastructure в доменный слой — мы от него полностью отказались. Точкой входа и границей модуля стал Application. Да, в некоторых модулях внутри приватной области можно встретить раздел Infrastructure, но он несет совершенно другой смысл. Там мы пишем “провайдеры” для связи со сторонними внешними сервисами.
Дублирование кода сведено к минимуму благодаря жесткому разделению предметных областей. Команда товаров занимается только товарами, команда гео — картами. Им концептуально негде написать один и тот же код.
Количество обращений к БД зависит от задачи: где-то хватает одного, где-то их десятки. Как правило такие сложные процессы уходят в очередь и выполняются постепенно
Каждый модуль работает только со своими таблицами в базе, через модели, расположенные внутри модуля. Эти модели не дублируются в других модулях. Получить от них данные можно только через менеджеры. Да и сами модели менеджеры не вернут, они преобразуют их в DTO.
Сложные join разрешаем по разному: иногда, в рамках одного контекста, когда обе таблицы ему принадлежат, прописываем связи между моделями, как заложено в ActiveRecord. В других случаях, когда модели из разных контекстов, рассматриваем отдельно.
Зачастую связи прописывать не нужно вовсе, подобные задачи решаются в несколько запросов: достаточно отдельно получить id из одной таблицы и добавить их в запрос к другой, а вторым запросом, уже в своем модуле, можно получить результат. Только в исключительных, редких кейсах, когда действительно нужна оптимизация, мы договариваемся о применении прямых запросов к базе. Что согласовывается с архитектором, либо DBA командой отдельно.
Полностью изолированных задач, которые решаются внутри одного модуля, у нас много. Если же для бизнес-задачи нужны данные из соседнего контекста, разработчик просто вызывает менеджер чужого модуля. Благодаря единой структуре всех модулей чужой код читается легко. Идти к соседям в чат нужно только в одном случае — если нужного метода еще не существует. И это скорее плюс: владельцы контекста всегда подскажут наиболее оптимальное решение для своей зоны ответственности.
Модуль действительно уедет в отдельный сервис вместе со своим фреймворком. Но главное преимущество в том, что теперь появилась возможность сделать это за пару дней, а не за месяц. Четкая структура, локализованные внешние связи в менеджерах и зависимости, описанные в deptrac, делают процесс переноса значительно проще.
Да, в тексте описано направление подключения классов. О том, что обращение к модулю опирается на application, а он на domain, только в таком порядке.