LINUX.ORG.RU

Используете Dependency Injection? Тогда у вас проблемы.

 ,


3

3

Далее будет описание ключевых проблем возникающих от использования одной из техник Inversion of Control (IoC): Dependency Injection (DI). Проблемы как проистекают как из самой идеи DI, так и из применения оной на языке java.

Первым делом небольшое соглашение: в данном случае полагается, что в DI имеет смысл помещать исключительно объекты подходящие под определение «сервиса». Для сервиса характерно:

  • Отсутствие или сокрытие состояния, напр. сервис выполняющий сериализацию в json, сервис выполняющий шифрование и сервис доступа к бд, кеш.
  • Разделение API: публичное (собственно API сервиса, как правило за него отвечает отдельный интерфейс) и управления (сюда входит и управление жизненным циклом сервиса и конфигурация)
  • Наличие характерных стадий жизненного цикла: создание реализации -> конфигурация -> работа (или обработка запросов) -> завершение

С учетом того что API управления должно быть скрытым от пользователя сервиса, то наиболее краткий вариант реализации сервиса будет в виде: http://ic.pics.livejournal.com/wayerr/33550674/1829/1829_900.png Допустим нашему сервису требуется доступ к парочке иных сервисов: http://ic.pics.livejournal.com/wayerr/33550674/1590/1590_900.png

Эта очевидная и удобная схема логично проистекает из самого языка программирования и правил хорошего кода (не всех). Однако в реальности разработчик столкнется с ситуацией когда у сервиса появится дополнительная зависимость, если это в рамках одного проект - то нет никаких проблем, в конструктор легко добавить параметр. Если же дело происходит в библиотеке которую используют другие проекты, то конструктор менять нельзя - это сломает API. Можно сделать второй конструктор, но множество DI фреймворков не поддерживают это (хуже того их поведение может быть не определено в этом случае).

Отлично, раз нам нужна расширяемость то используем конфигурацию сервиса через сеттеры: http://ic.pics.livejournal.com/wayerr/33550674/2102/2102_900.png На этом большинство разработчиков удовлетворяется. Но нет, проблемы подкрались незаметно:

  • Сервис не имеет стадии инициализации - т.е. у нашего сервиса нет той точки в коде, после которой можно с уверенностью заявить, что он корректно сконфигурирован. При этом конструктор объекта уже не выполняет своей роли.
  • API конфигурации публичен, а значит возможно изменение конфигурации в процессе работы. Особенно много радости от отладки эта возможность подарит в многопоточном окружении.
  • Так как очень часто возникает необходимость в выполнении некоторых действий после инициализации то появляются затейливейшие костыли вроде методов аннотированных @PostConstruct.

Чтобы избавится от этих проблем надо четко выделить стадию инициализации, нетрудно догадаться что для инициализации служит конструктор, значит вернемся к инициализации через конструктор, но немного другим образом: http://ic.pics.livejournal.com/wayerr/33550674/2359/2359_900.png

На диаграмме видно новый объект: конфигурация сервиса, он содержит только ссылки на объекты необходимые для инициализации сервиса. При таком подходе мы сохраняем расширяемость (в конфигурацию всегда можно добавть еще свойство). Вновь выполняет свои задачи конструктор сервиса, в нем теперь можно валидировать конфигурацию. API конфигурации скрыто от пользователя и сервис уже нельзя переконфигурировать во время работы.

Напоследок стоит отметить две вещи:

  • Большинство DI контейнеров, не поддерживают такой подход без дополнительной доработки.
  • Получившийся дизайн сервиса можно упростить если использовать Service Locator который передавать в конструктор, при этом мы получим все теже достоинства но без написания лишнего кода. Да, это уже не будет IoC, зато сохраняются все его преимущества и теряются недостатки.

зы. Да это опять я, и по традиции с картинками тут.

ps2. http://thecodelesscode.com/case/104?lang=ru&trans=smal - для тех кто скажет про документацию к сервису

Deleted

Последнее исправление: Deleted (всего исправлений: 1)

Ответ на: комментарий от Deleted

Клиенты тебя проклянут.

Клиенты будут благодарны за то, что я не дал им возможности нарваться на NPE после обновления из-за того, что они не были в курсе новой обязательной зависимости.

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

Обратная совместимость в конструкторе это херня по сравнению с описанными в предыдущем сообщении преимуществами. Херово, это когда ты ломаешь интерфейсы.

Ты забываешь что там не только зависимости но и «настройки» а значит их может быть очень много изначально. Например как в апачевском http client.

Во-первых, апачевский http client приводить в качестве примера хорошего кода некорректно. Там, пардон, угребищное апи, которое даже в руки противно брать. Во-вторых, настройки можно/нужно группировать по dtoшкам и, опять же, если у тебя их слишком много, это серьезный повод задуматься.

f1xmAn ★★★★★
()
Ответ на: комментарий от f1xmAn

Клиенты будут благодарны за то, что я не дал им возможности нарваться на NPE после обновления из-за того, что они не были в курсе новой обязательной зависимости.

Новая обязательная зависимость - вот за что они тебя проклянут.

сравнению с описанными в предыдущем сообщении преимуществами

которых нет

Там, пардон, угребищное апи, которое даже в руки противно брать.

Ты пардон, в какой версии его последний аз видел?

Во-вторых, настройки можно/нужно группировать по dtoшкам

Какие DTO для настроек, выдыхай, тот объект который ты называешь DTO - являет собой конфигурацию описанную в посту, т.е. то против чего ты выступаешь.

Deleted
()
Ответ на: комментарий от Deleted

Новая обязательная зависимость - вот за что они тебя проклянут.

Эээ.. ну ок.

которых нет

Слепой?

Ты пардон, в какой версии его последний аз видел?

Года 2 назад. Предпочитаю использовать RestTemplate.

Какие DTO для настроек, выдыхай, тот объект который ты называешь DTO - являет собой конфигурацию описанную в посту, т.е. то против чего ты выступаешь.

Нет. Отдельно зависимости, отдельно настройки.

f1xmAn ★★★★★
()
Ответ на: комментарий от Deleted

ты не начинай с азов, а бред свой объясняй, а если веществ употребил - сразу так и скажи.

maloi ★★★★★
()
Ответ на: комментарий от f1xmAn

Слепой?

Ты не увидел что я тебе про них написал еще на первой странице?

Года 2 назад.

Хорошая версия библиотеки, да.

Нет. Отдельно зависимости, отдельно настройки.

Что нет, 4 сервиса + 3 объекта настроек?

Deleted
()
Ответ на: комментарий от f1xmAn

Не много, irl бывают классы и по жирнее, другое дело что ты их объявляешь анафемой и прикрываешься RestTemplate который их юзает унутри 8)

Deleted
()

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

dizza ★★★★★
()

И кстати сеттеры не плохой вариант. Инициализируемость объекта неплохо проверяет IDEA, например через аннотацию Required. З.Ы. ну скока можно занимать срывом покровов, когда можно просто изучить свой инструмент, или поискать более подходящий.

dizza ★★★★★
()
Последнее исправление: dizza (всего исправлений: 1)

как использовать DI в c99?

zenden
()
Ответ на: комментарий от dizza

Это слишком просто и скучно. Нужно больше хлеба и зрелищ.

ii8_ ★★★★
()
Ответ на: комментарий от Deleted

Что ты понимаешь под недоинициализированным? Проблемы в многопоточности? Ну так сделай hb ребро между записью в сеттере и использованием и будь счастлив.

DiKeert ★★
()
1 октября 2015 г.
Ответ на: комментарий от dizza

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

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

Инициализируемость объекта неплохо проверяет IDEA, например через аннотацию Required.

Костыль.

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

Единственный инструмент javac - все остальное, очевидные грабли.

Deleted
()
Ответ на: комментарий от Deleted

Костыль.

Добро пожаловать в реальный мир.

Единственный инструмент javac - все остальное, очевидные грабли.

Все остальное просто инструмены, которые нужно не выеживаться, а учить и использовать.

dizza ★★★★★
()
Ответ на: комментарий от dizza

Добро пожаловать в реальный мир.

Пока-пока.

Все остальное просто инструмены,

кто «все», ты нагородил препроцессоров от си к яве или костылишь байткод в рантайме?

Deleted
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.