6

Я унаследовал решение Visual Studio, которое содержит многочисленные круглые ссылки между проектами.Нужны ли циркулярные ссылки?

Есть ли когда-нибудь ситуация, когда это дистанционно приемлемо?

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

+0

Подозрение подтверждено! – mclark1129

ответ

8

Однажды я прочитал колонку, где они сравнили 3 модели: модель спагетти, модель Лазанья и модель Равиоли.

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

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

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

Около 10 лет назад мне показалось, что модель Равиоли лучше, чем модель Лазанья. В конце концов, в Java у вас также есть модули Java, которые могут легко вызвать друг друга (и у меня сложилось впечатление, что между всеми различными модулями Java не существует реальной структуры). Для меня модель Лазаньи казалась результатом не-объектно-ориентированного старого кода, в то время как модель Равиоли казалась более современной, более объектно-ориентированной.

В настоящее время я, как правило, возвращаюсь к модели Лазанья, но с встроенной моделью Ravioli.Это:

  • Приложение построено с использованием различных слоев, как и в модели Лазанья
  • Но в слоях, код по-прежнему расколото между различными модулями, которые могут получить доступ друг к другу, как в равиоли модель.

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

Обратите внимание, что круговая ссылка в этом примере может уже привести к проблемам (класс FileWriter может вызывать класс Debug при записи строки, но класс Debug использует класс FileWriter для записи отладочной информации, результат: переполнение стека) ,

В этом случае проблему можно легко решить, не используя класс FileWriter в классе Debug, но использовать родные iostreams (если вы разрабатываете на C++). В других случаях проблему можно решить гораздо сложнее.

+4

Отлично, 93 минуты с обеда, и я голоден, и я читал это ... большое спасибо ... – CaffGeek

+1

Вы описываете [сквозные проблемы] (http://en.wikipedia.org/wiki/Cross -cutting_concern) здесь. Хорошая аналогия. – Kilanash

+0

Ницца именования. Пришлось смеяться;) – citronas

1

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

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

2

Хорошее программное обеспечение разработано в виде слоев с четко разграниченными границами между ними. т.е.: если у вас есть слой, вам нужно четко сформулировать, что он делает, почему он есть и от чего он зависит. Циркуляры затрудняют достижение этой цели и, как правило, должны быть удалены. (Microsoft потратила много усилий в Windows 7, чтобы улучшить разбиение Windows, удалив Circularities.)

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

Это определенно поддержит эту теорию, но ИМО, вам понадобится больше, чем просто несколько круговых ссылок, чтобы сделать этот вывод.

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

2

Конкретно я бы посоветовал использовать NDepend для обнаружения и избежания dependency cycles.

alt text

Отрывок из статьи (я писал): Control component dependencies to gain clean architecture

Зависимость от циклов между компонентами приводит к тому, что обычно называют спагетти кода или запутанные код. Если компонент A зависит от B, который зависит от C, который зависит от A, компонент A не может быть разработан и протестирован независимо от B и C. A, B и C образуют неделимую единицу, своего рода суперкомпонент. Этот суперкомпонент имеет более высокую стоимость, чем сумма затрат по сравнению с A, B и C из-за неэффективности масштабного явления (хорошо документировано в Software Estimation: Demystifying the Black Art от Steve McConnell). В основном, это означает, что стоимость разработки неделимой части кода возрастает экспоненциально.

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

Смежные вопросы