Обновить

Комментарии 6

Статья неплохая, есть ряд вопросов:

1. container - это глобальный объект?
2. Можем ли иметь несколько контейнеров?
3. Насколько эффективно ресолвятся зависимости?
4. Не совсем понял пример с тем, что меняется входная схема. Да, мы не привязываемся к неймингу, отдаем сырые данные , там под капотом происходит магия. Но в таком случае получается, что мы ничего как клиент не знаем о контракте, если контракт поменяется мы бы в любом случае получили проблему совместимости, но когда явно указываешь схему передачи, ide подсветит тебе, что у тебя синус с косинусом не сходятся или ту же проблему получишь при запуске линтов. Как бы никто не защищен, если от того, что у тебя и исходную схему модернизируют, так что она перестанет работать у клиентов сервиса. Но тут мы это прячем на слой поглубже.

DI в целом очень хорош, нужен ли он в django проекте?

  1. Да

  2. Технически — да, можно создавать контейнеры на уровне app-ки в Django. Вопрос насколько это будет удобно и не понадобится ли какой-то сервис из одной аппки в сервисе другой аппки. Можно легко запутаться если контейнеров много.

  3. Я не проводил бенчмарк-тесты, но это одна из самых легких DI-либ + 100% покрытие тестами. Минимальный шанс, что где-то выстрелит.

4)

Да, мы не привязываемся к неймингу, отдаем сырые данные , там под капотом происходит магия. Но в таком случае получается, что мы ничего как клиент не знаем о контракте, если контракт поменяется мы бы в любом случае получили проблему совместимости, но когда явно указываешь схему передачи, ide подсветит тебе, что у тебя синус с косинусом не сходятся или ту же проблему получишь при запуске линтов

В моем примере я использовал dict потому что это было удобно в случае с сериализатором. Можно написать более явный контракт и передавать именнованные аргументы (а в фабрике соответственно их принимать и маппить в DTO):

service = container.resolve("SomeService", id=1, price=2, amount=3)

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

Это правда, что никто не защищен. Однако в данном случае при изменении исходной схемы мы не зависим от внутренней реализации сервиса. Что-то менять нужно и там, и там, однако, при использовании фабрики — многие вещи становятся гораздо удобнее. Взять то же версионирование сервисов — мы можем реализовать его в фабрике, и не выносить этот if-код наружу. Опять же - скрываем детали реализации.

2) Думаю, речь не про уровень аппки, а про то чтобы контейнер создавался при старте и передавался во вьюхи. Чтобы его можно было, в частности, в тестах подменить

4) все ещё не понимаю зачем вы передаете данные при резолвинге сервиса. Ну передайте вы при вызове его методов, предвариательно заложив в интерфейс. Если же это конфигурационные параметры - передавайте при настройке контейнера, а не во вьюхе опять же

4) Думаю здесь вы правы и стоило прокинуть Product в метод call а не конструктор, а зависимости оставить на уровне конструктора, было бы более констистентно, спасибо.

Не раскрыта тема внедрения зависимостей. Ваш сервис по факту ни от чего не зависит - ни от адаптера для доступа к БД, ни от вспомогательных объектов, реализующих БЛ. Вместо этого почему-то он принимает продукт в init, а не как данные. Это немного странно

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

Суммарно, это больше выглядит как паттерн ServiceLocator, а не Dependency Injection.

Что же касается самого punq, меня в нем в своё время остановила одна вещь - отсутствие явных скоупов. Вы не можете ему сказать, что всё время пока вы обращаетесь к контейнеру внутри обработчика запроса надо возвращать один и тот же экземпляр конкретного класса, а при выходе - почистить (иногда вызвав доп функции финализации).

Приветствую

Не раскрыта тема внедрения зависимостей. Ваш сервис по факту ни от чего не зависит - ни от адаптера для доступа к БД, ни от вспомогательных объектов, реализующих БЛ.

Может я не совсем понял о чем речь — есть пример, где для работы сервиса нужно передать другой сервис который работает с CRM и инжектится внутри фабрики.

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

Суммарно, это больше выглядит как паттерн ServiceLocator, а не Dependency Injection.

Я понимаю что вы имеете в виду — скорее всего использование контейнера внутри вьюхи. Да, эта часть выглядит как ServiceLocator и это единственное место где сервис инжектится подобным образом, но! По моему скромному мнению для джанги и его вьюшек - это допустимое поведение. Использование всяких декораторов над методом или переопределение конструктора вьюхи — совсем печально выглядит. Но и это относится только к вьюхам — остальные зависимости попадают через фабрику.

Что же касается самого punq, меня в нем в своё время остановила одна вещь - отсутствие явных скоупов. Вы не можете ему сказать, что всё время пока вы обращаетесь к контейнеру внутри обработчика запроса надо возвращать один и тот же экземпляр конкретного класса, а при выходе - почистить (иногда вызвав доп функции финализации).

Что есть — то есть. Насколько знаю в punq-е можно определять два поведения глобально для каждого объекта - singletone и создавать новый объект. Но при использовании это поведение определить на ходу нельзя. Однако для нас это не играет большой роли.

Спасибо, что прокомментировал, для меня это действительно важно.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации