Собираются бананы со слабой связью и инъекцией зависимости - PullRequest
16 голосов
/ 09 января 2009

С последними дополнениями к нашей структуре внедрения зависимостей (весенние аннотации) предельные затраты на создание управляемых DI компонентов, похоже, достигли некоторого критического нового порога. В то время как ранее были издержки, связанные с пружиной (тонны XML и дополнительные косвенные ссылки), внедрение зависимостей, похоже, начало идти туда, где происходит множество шаблонов; они уходят под капот и «исчезают».

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

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

В нашей команде есть два основных направления мысли: зависимости реализации ограничивают группировку; любая функциональность в одном классе предпочтительно должна быть клиентом с всеми внедренными зависимостями. Мы являемся проектом DDD, а другая часть считает, что домен ограничивает группировку (CustomerService или более мелкий CustomerProductService, CustomerOrderService) - нормализованное использование внедренных зависимостей неважно.

Итак, в слабо связанной вселенной DI, почему мы группируем логику в классах?

edit: duffymo, отметьте, что это может привести к функциональному стилю программирования; что поднимает вопрос о гос. У нас есть довольно много «State» объектов, которые представляют (маленькие) части соответствующего состояния приложения. Мы внедряем их в любой сервис, который имеет законную потребность в этом состоянии. (Причина, по которой мы используем объекты «State» вместо обычных объектов домена, заключается в том, что Spring создает их в неуказанное время. Я рассматриваю это как небольшой обходной путь или альтернативное решение, позволяющее Spring управлять фактическим созданием объектов домена. Могут быть и более эффективные решения. здесь).

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

Ответы [ 4 ]

8 голосов
/ 13 марта 2011

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

Высокая когезия

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

Сплоченность уменьшается, если:

* The functionality embedded in a class, accessed through its methods,
  have little in common.
* Methods carry out many varied activities, often using coarsely-grained or 
  unrelated sets of data.

Недостатками низкой когезии (или "слабой когезии") являются:

* Increased difficulty in understanding modules.
* Increased difficulty in maintaining a system, because logical changes in 
  the domain affect multiple modules, and because changes in one module 
  require changes in related modules.
* Increased difficulty in reusing a module because most applications
  won’t need the random set of operations provided by a module.

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

4 голосов
/ 27 ноября 2009
  • Почему мы группируем вещи в классах и какими должны быть принципы?

Вы подчеркиваете "Группирование" или "Классы?"

Если вы спрашиваете, почему мы группируем вещи, то я бы добавил слова Медельта «Ремонтопригодность», хотя я бы перефразировал его как «Чтобы уменьшить потенциальную стоимость волновых эффектов».

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

Существует теорема, которая показывает, что при заданной цепочке компонентов a - b - c - d - e, такой, что a зависит от b, и т. Д., Вероятность того, что изменение e затем изменит компонент c, не может быть больше чем вероятность того, что изменение е затем изменит d. А в реальных программных системах вероятность того, что изменение e повлияет на c, обычно меньше вероятности того, что изменение e повлияет на d.

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

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

Теперь вернемся к потенциальной связи. Можно показать, что в контексте абсолютной инкапсуляции (например, Java или C #, где рекурсивная инкапсуляция не используется широко) все компоненты потенциально связаны друг с другом либо прямой, либо косвенной зависимостью с одним промежуточным компонентом. По статистике, система, которая сводит к минимуму прямую потенциальную связь между ее компонентами, сводит к минимуму потенциальную стоимость эффекта ряби из-за любого обновления.

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

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

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

Вот почему мы, "группировка", вещи.

Что касается того, почему мы используем классы для группировки вещей:

A) Классы предоставляют поддерживаемый языком механизм для инкапсуляции.

B) Мы не просто используем классы: мы также используем пространства имен / пакеты для инкапсуляции.

С уважением,

Ed.

3 голосов
/ 09 января 2009

Я могу придумать две причины.

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

Состояние и идентичность: объекты не только содержат логику, но и поддерживают состояние. Логика, которая является частью интерфейса работы с состоянием определенного объекта, должна быть определена для этого объекта. Объекты также поддерживают идентичность, объект, который моделирует один объект в проблемной области, должен быть одним объектом в вашем программном обеспечении.

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

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

2 голосов
/ 09 января 2009

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

Факторы стоимости

  • Накладные расходы DI. Раскрутка всех базовых и связанных базовых элементов для одного метода стоит дорого. Группировка в класс позволяет нам компенсировать это.
  • Навыки - DI является новым для многих (я ОСОБЕННО), поэтому трудно понять, как это сделать лучше или выбраться из старого / привычного дизайна
  • Коричневые полевые приложения, в которых они уже есть, с ними легче / дешевле / быстрее жить и беспокоиться об этом в будущих приложениях для зеленых полей

Надеюсь, мой новичок (да, я полон выдуманных слов) с DI не сделал меня совершенно не правым в этом.

...