Боязнь использования фреймворка Dependency Injection

Я читал об основах внедрения зависимостей. Я действительно влюбился в идею разделения проблем и позволения объектам выполнять свою основную работу - это, несомненно, превосходный и давний принцип проектирования!

Однако чем больше я читаю на платформах DI, тем больше я волнуюсь: 1) в том, как они "автоматически" разрешают зависимости 2) об экстремальных сложностях, вносимых в файлы конфигурации

Что касается пункта № 2, я видел, как мои клиенты тратили миллионы долларов на обучение людей продуктам, значительная часть которых заключалась в том, как "не" прикасаться к файлам конфигурации. Администраторы теперь боятся этих файлов конфигурации.

Тем не менее, я вижу другой шаблон, называемый локаторами сервисов, где я мог бы собрать все "глобальные" сервисы, которые мне нужны в начале моего приложения (может быть хост приложения или контекст приложения или что-то еще). Сделайте этот сервис локатором по всему миру и вуаля!

Однако я вижу, что при использовании подхода "Поиск сервисов" будет меньше гибкости, когда мне потребуется более одного типа "глобального" сервиса, основанного на каком-то критерии (известно кому?)!

Итак, здесь я более запутан, чем прежде, в каком направлении идти. Хотя мне очень нравится принцип дизайна, сложность существующих фреймворков меня отталкивает!

Являются ли мои опасения подлинными? Кто-нибудь еще чувствует то же самое? Если так, есть ли хорошая альтернатива для таких огромных "рамок"?

6 ответов

Решение

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

Первоначально (или навсегда!) Я бы избегал файлов конфигурации и настраивал контейнер в коде. Это, как правило, гораздо легче читать и поддерживать. Большую часть времени вам не нужны оперативные изменения конфигурации. Клиенты не могут трогать файлы конфигурации, потому что они не существуют.

У сервисных локаторов есть свои минусы; с одной стороны, они имеют тенденцию связывать ваши классы с локаторным классом / фреймворком. Хорошая структура DI позволит вам использовать Plain Old Objects; у вас может быть только один класс в вашем проекте, который фактически использует структуру DI/IoC.

StructureMap и Unity довольно просты; дать им попытку. Начните с малого.

Вот действительно простой пример с Unity (включая встроенную конфигурацию):

using Microsoft.Practices.Unity;

static void Main()
{
    using (IUnityContainer container = new UnityContainer())
    {
        container.RegisterType<IRobot, MrRoboto>();

        Console.WriteLine("Asking Unity container to give us a Model...");

        Model model = container.Resolve<Model>();
        model.MoveRobot();
    }
}

// class Model

public Model(IRobot robot)
{
    // Unity will hand the constructor an instance of MrRoboto!
}

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

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

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

Основным принципом классов с поддержкой DI является то, что они не ссылаются на код инфраструктуры. Это противоположность паттерну сервис-локатора. Основным недостатком Service Locator является то, что, помимо добавления сложности к классам, которые ссылаются на контейнер, нет возможности изменить, какая версия зависимости разрешена.

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

Если вы действительно хотите пойти по пути внедрения зависимостей, я настоятельно рекомендую прочитать превосходную статью Мартина Фаулера о внедрении зависимостей:

http://martinfowler.com/articles/injection.html

Я сейчас работаю над проектом Java с большим количеством конфигурационных файлов. Мы заранее выбрали шаблон Singleton для представления нашей конфигурации (несколько аналогично глобальному решению). Вот то, что сводит меня с ума и заставляет меня желать, чтобы вместо этого у нас был паттерн Dependency Injection:

  1. Модульное тестирование с глобализованными шаблонами - отстой. Шаблоны внедрения зависимостей легко поддаются простому модульному тестированию и особенно тестированию фиктивных объектов. В случае одноэлементного типа у вас теперь есть все эти модульные тесты, для работы которых все еще требуется глобальное состояние. С помощью внедрения зависимостей вы можете создавать фиктивные объекты конфигурации для конкретного теста, которые вы передаете в свои тесты. Я не могу преувеличить, насколько легче это делает модульное тестирование. Еще одна отличная статья под названием "Эндотестирование: модульное тестирование с использованием фиктивных объектов": http://connextra.com/aboutUs/mockobjects.pdf

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

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

В любом случае, надеюсь, что статья и опыт помогут вам принять решение. Я далеко иду по пути, по которому ты думаешь идти вниз, и мне хотелось бы, чтобы вместо этого мы выбрали путь внедрения зависимости:-D

Ни один из них не является "обязательным" для DI - это опции, предоставляемые некоторыми структурами DI. Лично мне не нравится "автоматическая" инъекция - я вижу, что она работает для действительно небольших проектов, но вызывает проблемы в более крупных проектах. Что касается пункта № 2 - я не уверен, что понял - я в основном использовал Spring. Spring предоставляет опции конфигурации XML и Java. Предоставляет вложенные конфигурации. Если есть часть конфигурации, которую вы не хотите, чтобы кто-либо изменял, и есть часть, которую вы делаете - разделяете их на отдельные файлы конфигурации - или делаете "изменяемый" один XML и другой Java. Spring также поддерживает использование значений из файлов свойств, и это все, что я ожидаю от администраторов - администраторы не программисты - они не должны "перемонтировать" ваше приложение - просто предоставляя соответствующие опции.

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

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

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

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

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

Spring имеет хорошую настройку для DI, хотя он и не легкий.

Я обнаружил, что Unity Framework не является тривиальным для изучения, но как только вы используете его, довольно легко добавлять новые классы для инъекций.

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

Другие вопросы по тегам