Рекомендации по интеграции контейнера DI / IoC в существующее приложение

10

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

Вот немного предыстории некоторых проблем, с которыми нужно столкнуться:

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

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

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

Калеб Педерсон
источник
3
Я должен спросить причину сделать это сейчас ... что движет этим изменением? Ремонтопригодность? Масштабируемость, поскольку она будет расти в геометрической прогрессии? Разработчикам скучно?
Аарон Макивер
1
Я только недавно присоединился к компании и пытаюсь представить «лучшие практики». Моя главная цель - повысить тестируемость и уменьшить сцепление. Мы можем легко использовать DI / IoC для нового кода и не собираемся пытаться изменить весь существующий код сразу, но я хотел бы получить рекомендации о том, как мы можем лучше изменить существующий код в лучшую сторону в следующий раз, когда мы делаем изменения в этой области. Пока единственное, что я нашел в Интернете, это следующее: code.google.com/p/autofac/wiki/ExistingApplications
Калеб Педерсон
3
Если не имеется большого количества автоматизированных модульных / интеграционных тестов; модификация существующей инфраструктуры, если проблема не существует ради лучших методов, просит проблем. Даже если ваш пакетный / интеграционный тестовый пакет был надежным, у меня все еще были сомнения.
Аарон Макивер
1
@ Аарон Надеюсь, это не похоже на то, что мы делаем это ради лучших практик. Мы вносим изменения, потому что сложно и медленно работать с существующим кодом и делать это по частям, поскольку мы работаем в этой конкретной области. К счастью, у нас есть ряд разумных интеграционных тестов и несколько модульных тестов для поддержки внесения изменений.
Калеб Педерсон

Ответы:

8

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

  1. Определите основные подсистемы приложения и interfaceдля каждой из них. Этот интерфейс должен определять только те методы, которые другие части системы будут использовать для общения с ним. ПРИМЕЧАНИЕ: вам может потребоваться сделать больше одного прохода.
  2. Предоставьте реализацию-оболочку для этого интерфейса, который делегирует существующий код. Цель этого упражнения - избежать массового переписывания , но реорганизовать код для использования новых интерфейсов, т. Е. Уменьшить связь в вашей системе.
  3. Настройте контейнер IoC для построения системы, используя созданные вами интерфейсы и реализации. На этом этапе вы хотите позаботиться о создании экземпляра контейнера IoC, чтобы он мог запустить приложение. Т.е., если вы находитесь в среде сервлета, убедитесь, что вы можете получить / создать контейнер в init()методе сервлета .
  4. Проделайте то же самое в каждой подсистеме снова, на этот раз, когда вы проводите рефакторинг, вы превращаете реализацию заглушки в реальную вещь, которая, в свою очередь, использует интерфейсы для взаимодействия с ее компонентами.
  5. Повторяйте по мере необходимости, пока у вас не будет хорошего баланса размера компонента и функциональности.

Когда вы закончите, единственными статическими методами, которые вы должны иметь в своей системе, являются те, которые действительно являются функциями - например, посмотрите на Collectionsкласс или Mathкласс. Никакой статический метод не должен пытаться получить прямой доступ к другим компонентам.

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

Берин Лорич
источник
Хорошие предложения. Я также обращаю внимание
Калеб Педерсон
7

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

Майкл Браун
источник
Люблю эту книгу !!
Мартейн Вербург
Хорошая рекомендация. Хотя я читал половину этого года назад, я представляю, что теперь я смогу извлечь из этого гораздо больше пользы, потому что я нахожусь в глубине ситуации.
Калеб Педерсон
Забавно, выбранный ответ в основном резюмирует книгу;) Конечно, «Перья» углубляются в детали.
Майкл Браун
5

Основной причиной введения IoC является разделение модулей. Проблема, особенно с Java, заключается в необычайно сильной привязке, которую newдает оператор, в сочетании с тем, что это означает, что вызывающий код точно знает, какой модуль он будет использовать.

Фабрики были введены для того, чтобы переместить эти знания в центральное место, но, в конце концов, вы все еще либо жестко newсвязываете модули с помощью / singleton, который сохраняет жесткую привязку, либо читаете в файле конфигурации и используете отражение / Class.forName, которое является хрупким при рефакторинге. ,

Если у вас нет модульной цели, IoC ничего не даст вам.

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


источник