design-patterns шаблоны - Каковы недостатки использования инъекций зависимостей?





паттерны проектирования (17)


Если вы используете DI без контейнера IOC, самым большим недостатком является то, что вы быстро видите, сколько зависимостей имеет ваш код и насколько тесно связаны все на самом деле. («Но я думал, что это хороший дизайн!»). Естественным шагом вперед является переход к контейнеру IOC, который может занять немного времени, чтобы учиться и реализовывать (не так плохо, как кривая обучения WPF, но она не является бесплатной или). Последним недостатком является то, что некоторые разработчики начнут писать честные тесты модульности, и им потребуется время, чтобы понять это. Devs, которые раньше могли пропустить что-то через полдня, вдруг проведут два дня, пытаясь понять, как издеваться над всеми их зависимостями.

Как и в ответе Марка Семанна, суть в том, что вы тратите время на то, чтобы стать лучшим разработчиком, а не взламывать кусочки кода и бросать его в дверь / в производство. Что может быть у вашего бизнеса? Только вы можете ответить на это.

Я пытаюсь представить DI как образец здесь на работе, и один из наших ведущих разработчиков хотел бы знать: что - если есть - являются недостатками использования шаблона Injection Dependency?

Примечание. Я ищу здесь, если возможно, исчерпывающий список, а не субъективную дискуссию по этой теме.

Уточнение : я говорю об шаблоне Injection Dependency (см. Эту статью Мартина Фаулера), а не о конкретной структуре, будь то основанной на XML (например, Spring) или основанной на кодах (например, Guice) или «самокаталированной», ,

Редактирование : Некоторые другие дальнейшие обсуждения / разглашение / дебаты идут /r/programming здесь.




Читаемость кода. Вы не сможете легко вычислить поток кода, поскольку зависимости скрыты в файлах XML.




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




Две вещи:

  • Они требуют дополнительной поддержки инструмента для проверки правильности конфигурации.

Например, IntelliJ (коммерческое издание) имеет поддержку проверки правильности конфигурации Spring и будет отмечать ошибки, такие как нарушения типа в конфигурации. Без такой поддержки инструмента вы не можете проверить правильность конфигурации перед запуском тестов.

Это одна из причин, почему шаблон «торт» (как известно сообществу Scala) является хорошей идеей: проводка между компонентами может быть проверена с помощью проверки типа. У вас нет этой выгоды с аннотациями или XML.

  • Это делает глобальный статический анализ программ очень сложным.

Рамки, такие как Spring или Guice, затрудняют точное определение того, как будет выглядеть граф объектов, созданный контейнером. Хотя они создают граф объектов при запуске контейнера, они не предоставляют полезные API, которые описывают граф объекта, который / будет / должен быть создан.




Если у вас есть доморощенные решения, зависимости прямо в вашем лице в конструкторе. Или, может быть, параметры метода, которые снова не так сложно обнаружить. Хотя управляемые зависимостями структуры, если они приняты до крайности, могут появляться как магия.

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

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

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

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

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




Я нахожу, что инсталляция конструктора может привести к большим уродливым конструкторам (и я использую его всю свою кодовую базу), возможно, мои объекты слишком детализированы?). Кроме того, иногда с интродукцией конструктора я получаю ужасные круговые зависимости (хотя это очень редко), поэтому вы можете столкнуться с каким-то готовым состоянием жизненного цикла с несколькими раундами инъекций зависимостей в более сложной системе.

Тем не менее, я предпочитаю инжектор инжектора за инсталляцию setter, потому что, как только мой объект сконструирован, я без всякого сомнения знаю, в каком состоянии он находится, независимо от того, находится ли он в единичной тестовой среде или загружен в какой-либо контейнер IOC. Который, в кругосветном виде, говорит, что я считаю основным недостатком инъекции сеттера.

(как побочный элемент, я нахожу всю тему довольно «религиозной», но ваш пробег будет отличаться от уровня технического фанатизма в вашей команде разработчиков!)




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

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

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

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




Одна вещь, которая заставляет меня немного подшутить над DI, - это предположение, что все введенные объекты дешевы для создания экземпляра и не производят никаких побочных эффектов -OR- зависимость используется так часто, что она перевешивает любые связанные с этим затраты на создание экземпляра.

Если это может быть существенным, тогда, когда зависимость не часто используется в классе потребления; например, как IExceptionLogHandlerService . Очевидно, что подобная услуга вызывается (надеюсь) :) редко в классе - предположительно только на исключениях, которые нужно записывать; но канонический конструктор-инъекционный образец ...

Public Class MyClass
    Private ReadOnly mExLogHandlerService As IExceptionLogHandlerService

    Public Sub New(exLogHandlerService As IExceptionLogHandlerService)
        Me.mExLogHandlerService = exLogHandlerService
    End Sub

     ...
End Class

... требует, чтобы был предоставлен «живой» экземпляр этой службы, прокляты затраты / побочные эффекты, необходимые для его получения. Не то, чтобы это было возможно, но что, если построение этого экземпляра зависимостей включало в себя попадание службы / базы данных или поиск файлов конфигурации или блокировку ресурса до его удаления? Если бы эта служба была построена по необходимости, на обслуживании или на заводе-изготовителе (все проблемы имеют свои собственные), тогда вы будете брать затраты на строительство только тогда, когда это необходимо.

Теперь общепризнанным принципом разработки программного обеспечения является то, что построение объекта дешево и не вызывает побочных эффектов. И хотя это хорошее понятие, это не всегда так. Однако, используя типичную конструктор-инъекцию, в основном это требует. Если вы создаете реализацию зависимостей, вы должны сконструировать ее с учетом DI. Возможно, вы сделали бы объектное строительство более дорогостоящим, чтобы получить выгоды в другом месте, но если эта реализация будет введена, это, скорее всего, заставит вас пересмотреть этот дизайн.

Кстати, некоторые методы могут смягчить эту точную проблему, разрешив ленивую загрузку Lazy<IService> зависимостей, например, предоставив классу Lazy<IService> экземпляр в качестве зависимости. Это изменит конструкторы зависимых объектов и сделает еще более осведомленным о деталях реализации, таких как затраты на строительство объектов, что тоже нежелательно.




Иллюзия, что вы отделили свой код, просто внедряя инъекцию зависимостей, не отключая его. Я думаю, что это самая опасная вещь в DI.




Это больше ничто. Но один из недостатков инъекции зависимостей заключается в том, что он немного затрудняет разработку и использование кода.

В частности, если вы Control-Click / Command-Click на вызове метода в коде, он приведет вас к объявлению метода на интерфейсе вместо конкретной реализации.

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

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

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




Несколько баллов:

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

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




Инъекция зависимостей на основе конструктора (без помощи магических «фреймворков») - это чистый и полезный способ структурирования OO-кода. В лучших кодовых таблицах, которые я видел, в течение нескольких лет, проведенных с другими бывшими коллегами Мартина Фаулера, я начал замечать, что большинство хороших классов, написанных таким образом, заканчивают тем, что имеют один метод doSomething .

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




Вот моя собственная первоначальная реакция: в основном те же самые недостатки любого шаблона.

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






Похоже, что предполагаемые преимущества статически типизированного языка значительно уменьшаются, когда вы постоянно используете методы для работы со статической типизацией. В одном крупном магазине Java, на котором я только что взял интервью, были сопоставления их зависимостей построения с статическим анализом кода ... которым нужно было проанализировать все файлы Spring, чтобы быть эффективными.




DI - это метод или шаблон и не имеет отношения к какой-либо структуре. Вы можете связать свои зависимости вручную. DI помогает вам с SR (единоличная ответственность) и SoC (разделение проблем). DI ведет к лучшей конструкции. С моей точки зрения и опыта нет недостатков . Как и с любым другим шаблоном, вы можете ошибочно или неправильно использовать его (но то, что в случае с DI довольно сложно).

Если вы представляете DI как принцип для устаревшего приложения, используя фреймворк - самая большая ошибка, которую вы можете сделать, это неправильно использовать его как Service-Locater. Сама DI + сама по себе велика и просто улучшилась везде, где я ее видел! С организационной точки зрения, есть общие проблемы с каждым новым процессом, техникой, шаблоном, ...:

  • Вы должны обучить команду
  • Вы должны изменить свое приложение (включая риски)

В общем, вы должны инвестировать время и деньги , кроме того, там нет недостатков, действительно!




MVVMC, или, возможно, MVC +, представляется жизнеспособным подходом как для предприятий, так и для быстрой разработки приложений. Хотя приятно отделить пользовательский интерфейс от бизнес-логики и взаимодействия, «чистый» шаблон MVVM и большинство доступных примеров лучше всего подходят для сингулярных представлений.

Не уверены в ваших проектах, но большинство моих приложений, однако, содержат страницы и несколько (многоразовых) представлений, и поэтому ViewModels действительно должны взаимодействовать в некоторой степени. Использование страницы в качестве контроллера полностью победит цели MVVM, поэтому не использовать подход «VM-C» для базовой логики может привести к ... сложным конструкциям по мере созревания приложения. Даже в VB-6 большинство из нас, вероятно, прекратили кодирование бизнес-логики в событие Button и начали «ретрансляцию» команд контроллеру, не так ли? Недавно я рассмотрел много новых кадров на эту тему; моим фаворитом явно является подход Магеллана (при кодексе). Счастливое кодирование!

http://en.wikipedia.org/wiki/Model_View_ViewModel#References







design-patterns dependency-injection