Pull to refresh

Comments 10

Уважаемый автор, прошу, добавьте подсветку кода в примерах

Как по мне этот пример больше про 3-слойное приложение:

  1. Все модели наследуются от BaseModel, который нужен для правильной сериализации и работы с БД - и только для этого

  2. Модели анемичные. По факту, выполняют роль DTO

  3. На диаграмме бизнес-логика зависит от БД

  4. В данном классе должна быть заключена вся бизнес-логика приложения (BookBookService) - я увидел лишь простое делегирование вызовов, без какой либо бизнес-логики

Вывод - это 3 слойное приложение, которое называют чистой архитектурой

1. В данном примере модели и играют роль DTO, в статье не приведены модели БД, предполагается, что они уже есть и созданы любым удобным способом.
2. Да они анемичные, потому что они выпоkняют роль DTO.
3. На диаграмме бизнес логи зависит не от БД, а от слоя repository, который выполняет взаимодействие с БД.
4. Бизнес логика не приведена в BookBookService, т.к. не хотелось высасывать ее из пальца.

Про ваш вывод вообще не очень понятно, что вы имеете в виду

Синглетоны и глобальные объекты? Ну да, конечно, как же иначе - в копипасте по-другому никак.

а можете пояснить, в чем именно выигрыш сервиса обьявленного классом, по сравнению с банальным импортом метода из питон файла с именем book_service.py? Импорт, кстати, в этом примере также присутствует. Я так понимаю, изначальный смысл всего этого инжектинга в возможности подменить реализацию. Тут ее можно подменить?

Идея в том, чтобы заключить всю логику бизнес-логику связанную с объектом в одной сущности в данном случае BookBookService. Это и позволяет нам обеспечить внедрение зависимостей. Если по какой то причине этот класс поменяется, данную зависимость легко можно будет подменить в методе get_book_service.

Фактически, такой подход в разработке показался неудобным, мы соединили в одном файле модель, роуты и сервисы к роутам, стало удобно.

Вообще странно, а в чем было неудобство, обычно как раз разделение удобней:

  • Позволяет работать с кодом не создавая конфликтов, т.к. по файлам реже пересекаетесь

  • Значительно удобней когда тебе надо править бизнес-логику, посмотреть один класс чисто по ней, а не бегать по одному большому файлу.

  • Ну и про развитие классов с их подменой, тоже проще когда они в отдельных файлах.

Тема не совсем раскрыта. Во-первых, есть подход к дизайну информационных систем, именуемый DDD, где сущность (Модель) раскрывается более полно. Модель - это абстракция, описывающая особенности бизнес-задачи. Модели могут описывать данные или сущности, над которыми производятся действия в рамках выполнения бизнес-логики. Например, можно иметь Модель "Лицевой счëт", который представляет собой некий артефакт бизнеса, характеризующийся идентификатором клиента и некоторой суммой денег или баллов, находящихся во владении клиента. И можно иметь Модель "Транзакция", которая описывает действие по изменению Лицевого Счëта.

Поскольку, модель является абстракцией, имплементации которой может быть записью в Базе Данных, мы должны создать некоторую абстракцию над коллекцией имплементаций или инстансов. Этой коллекцией является слой Repository, который имеет точку входа от клиента или дополнительного слоя (Service) и точку выхода - в имплементации хранилища модели. То есть, репозиторий принимает на вход команды "дай список", "покажи одну запись", "добавь в коллекцию", "измени объект в коллекции", "удали объект из коллекции". На выходе он генерирует БД-специфичные команды или orm-сценарии. Например, Select, Insert, Update, Delete. А ресурсом для Репозитория является модель, сеанс БД, и т.д..

Команды на входе модели и на выходе отличаются. Они относятся к разным формальным языкам.

Сервисный слой является более высоким уровнем абстракции, который оперирует несколькими репозиториями. На вход он принимает команды в виде "покажи только счета с отрицательным балансом и инфу о нищебродах, которые ими владеют". И этот формальный язык Сервис переводит в другой: "репа счетов, выведи список счетов с балансом меньше нуля", "репа аккаунтов, вот тебе список id счетов, дай ФИО держателей". Далее, Сервис соединяет инфо и отдаëт ответ.

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

То есть, Инъекция Зависимостей гарантирует, что все Репозитории будут работать с одним сеансом (пулом соединений) БД, что Сервисы и Репозитории будут работать с одним инстансом Settings. И т.д.. И вот здесь возникает момент, когда надо задуматься: а нужно ли нам всегда пользоваться инъекциями? Например, я бы хотел, чтобы для разных кейсов в рамках одного запроса, у меня создавалось несколько экземпляров одного Репозитория (допустим, коллекция Клиентов и коллекция Менеджеров из одного UserRepository). Тогда, я не буду использовать Depends. Это противоречит моим целям.

В остальном, базовые вещи описаны относительно верно, но без ожидаемого пристрастия.

Sign up to leave a comment.

Articles