1

Всем привет, я читаю книгу Р. Мартина "Чистая архитектура". В ней приводится такая структура приложения: Структура чистой архитектуры

Я разрабатываю телеграмм бота для автоматизации рассылок инстаграм. У меня получилась следующая структура: Сущности: User, Instagram, Work(сущность фоновой задачи), интерфейсы вариантов использования, доступа к данным и тд. Сущности не требуют в себе никакой критической бизнес логики, просто структуры данных. От сущностей зависит проект с бизнес логикой (варианты использования, далее: слой с бизнес логикой). Там определены сервисы ответа на команды ботом, запуск задач, оплата и тд. От бизнес логики зависят несколько компонентов, они все реализуют интерфейсы, определенные в сущностях. Это доступ к данным, отправка запросов телеграмму, инстаграму, работа с платежной системой, компонент MVC.

Вопрос заключается в чем.

  1. Правильно ли хранить все интерфейсы в сущностях, или интерфейсы для доступа к данным к примеру должны находиться в проекте с бизнес логикой?
  2. Детали (тот же проект доступа к данным) должны общаться с слоем с бизнес логикой с помощью DTO. Где их хранить? В Сущностях или в слое с бизнес логикой?
  3. Может ли бизнес логика контактировать с деталями (компоненты, зависящие от нее) с помощью сущностей? К примеру репозиторий будет возвращать объекты сущностей из бд? Или для них нужно создавать отдельные DTO (InstagramDTO, UserDTO...) и при необходимости мапить их в сущности в слое с бизнес логикой.
  4. И вообще, может ли слой с бизнес логикой зависеть от сторонних библиотек? Автомапера там, CSVHelper и тд, или все сторонние библиотеки необходимо оставить для компонентов, зависящих от бизнес логики?
  5. Если все интерфейсы находятся в сущностях, то может быть детали должны зависеть от сущностей, а не от слоя с бизнес логикой? В таком случае изменения в бизнес логике не потребуют согласования с компонентами (если не изменяется какая-то очень важная часть бизнес логики)?

1 Answers1

2

Дисклаймер Если у вас полтора класса в проекте, то вам вероятно и не надо заморачиваться с архитектурой. Я бы вообще почитал сначала Мартина Фаулера - Шаблоны корпоративных приложений, а потом уже читал дядю Боба. Также полезно знать, что универсальной архитектуры для всего нет в природе. Вы можете однажды обнаружить, что натягиваете сову на глобус.

Теперь по порядку.

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

  2. Бизнес логика не общается с помощью DTO. DTO - это просто объект передачи данных. Зачем этим классам лежать рядом с логикой? Если они часть интерейсов - пусть лежат с интерфейсами рядом. Если они часть доступа к данным - пусть там и находятся. Сущности ваши вообще ничего не должны знать о том, что они вообще хранятся или передаются куда либо. Потому DTO рядом с сущностями не хранят.

  3. Может быть что угодно. Лично я предпочитаю не мешать хранение и доменные модели просто потому, что модель хранения может отличаться от модели-сущности. Но это не правило. Действуйте так, как имеет смысл для вашего приложения.

  4. Это вообще непонятный вопрос. Для взаимодействия с внешним миром у вас есть всякие контроллеры/шлюзы, там и добавляйте свои зависимости. Как вы делаете уровень доступа к БД, также и уровень доступа к CSV или HTTP или что там у вас есть.

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

p.s. Фоновая задача называется Job, а не Work.

tym32167
  • 32,857
  • Больше спасибо за ответ
    1. "Не плодите ли вы интерфейсы впустую?" А как без интерфейсов воплощать инверсию зависимостей?
    2. "Бизнес логика не общается с помощью DTO". А с помощью чего же она общается? К примеру контроллер, который хочет получить какую-то информацию. Он обращается к бизнес логике, которая должна ему вернуть данные, вероятно объединенные в DTO, разве нет?
    3. Я имел ввиду, что у есть сущность User у EntityFramework. Я могу ее смапить в доменную сущность User и вернуть, либо мне нужно для этого какая-то промежуточная DTO, которую вернет репозиторий? Я уже понял, что не нужна.
    – Егор Лазеба Mar 09 '22 at 19:02
  • Понятно, что для взаимодействия с внешним миром есть соответствующий слой. Я имею ввиду внутри слоя с бизнес логикой (красный на картинке) могут быть добавлены библиотеки для обработки данных к примеру, или этот слой лучше оставить зависимым только от сущностей?
  • Действительно, эти интерфейсы стоит хранить в слое с бизнес логикой (красный). Детали - все, что не бизнес логика я имел ввиду, доступ к данным, сторонние сервисы и тд.
  • А в целом большое спасибо за ответ, есть над чем подумать!

    – Егор Лазеба Mar 09 '22 at 19:09
  • 1
    @ЕгорЛазеба 1) я не отговаривал от интерфейсов, просто не создавайте из без причины 2) DTO - это просто объект, он может быть использован с системой хренения, а может быть использован для чего другого - например, для передачи по сети. Я это имел ввиду. 4) приведите пример, с примером проще понять ваш вопрос. – tym32167 Mar 09 '22 at 19:58
  • К примеру автомаппер. У меня есть сущность User: https://github.com/lncendia/DirectBot/blob/master/DirectBot.Core/Models/UserDTO.cs которая ссылается на сущность InstagramLite: https://github.com/lncendia/DirectBot/blob/master/DirectBot.Core/Models/InstagramDTO.cs (в проекте есть сущность Instagram со ссылкой на User. Для избежания циклической зависимости была добавлена сущность InstagramLite, если ее можно таковой считать). И чтобы установить соответствующее значение у User я должен получить соответствующий Instagram через репозиторий и смапить его в InstagramLite.
  • – Егор Лазеба Mar 09 '22 at 20:35
  • Структура проекта не верная, я знаю. И сущности у меня с припиской Dto - это тоже ошибка, они по факту являются сущностями. – Егор Лазеба Mar 09 '22 at 20:36
  • @ЕгорЛазеба По идее, слою бизнес логики вообще не надо знать про то, как там собираются модели. То есть БД<-> Data Layer (DTO) <-> Шлюз (маппинг) <-> Бизнес логика - ну это на вскидку, как я это представил сейчас. Бизнес логика принимает нужные модели и вызывает нужные шлюзы. Также она на моделях может какие то методы вызвать, специфичные для предприятия. – tym32167 Mar 09 '22 at 20:42
  • Мне пришлось добавить Lite-сущности для избежания циклических зависимостей в сущностях. Я могу сделать перегрузку в репозитории с Instagram, чтоб был метод, возвращающий Instagram и аналогичный InstagramLite, но какой в этом смысл, если эти сущности по факту одинаковые и выполняют одни и те же задачи, просто в одной отсутствуют некоторые свойства. Здесь можно было бы применить преобразование типов, но я хочу показать пример, когда сторонняя библиотека решает какую-то проблему в слое с бизнес логикой. Я понимаю, это ужасный пример, но какой есть – Егор Лазеба Mar 09 '22 at 20:55