Насколько строго вы следуете правилу «нет цикла зависимости» (NDepend)

10

Немного предыстории: как руководитель группы, я использую NDepend примерно раз в неделю, чтобы проверять качество нашего кода. Особенно тест-охват, строки кода и показатели цикломатической сложности для меня неоценимы. Но когда дело доходит до циклов выравнивания и зависимости, я немного ... очень обеспокоен. У Патрика Смаккья есть хороший пост в блоге, в котором описана цель выравнивания.

Для ясности: под «циклом зависимости» я понимаю циклические ссылки между двумя пространствами имен.

В настоящее время я работаю над структурой GUI на основе Windows CE для встроенных инструментов - просто подумайте о графической платформе Android, но для инструментов очень низкого уровня. Фреймворк представляет собой единую сборку с около 50 000 строк кода (тесты исключены). Каркас разделен на следующие пространства имен:

  • Базовая подсистема навигации и меню
  • Подсистема экрана (Докладчики / Представления / ...)
  • Управление / Виджет Слой

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

Итак, мой вопрос: насколько строго вы следуете правилу «нет цикла зависимости»? Действительно ли выравнивание так важно?

ollifant
источник
2
Если «нет цикла зависимости» означает отсутствие циклических ссылок, то - никаких оправданий. Это чистое зло.
Арнис Лапса
@ollifant: определите, что именно вы имеете в виду, когда пишете «No Dependency Cycle». Между слоями или между классами внутри слоя?
Док Браун

Ответы:

9

Недавно я написал 2 белые книги, опубликованные на Simple-Talk по теме архитектуры кода .NET (первая книга о сборках .NET, вторая книга о пространствах имен и выравнивании):

Разбиение базы кода с помощью сборок .NET и проектов Visual Studio

Определение компонентов .NET с пространствами имен

Действительно ли выравнивание так важно?

Да, это так!

Цитата из 2-й белой книги:

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

(...)

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

  • В традиционной строительной архитектуре сила тяжести оказывает давление на артефакты низкого уровня. Это делает их более стабильными: «стабильными» в том смысле, что их трудно передвигать.
  • В архитектуре программного обеспечения соблюдение идеи ациклических компонентов оказывает давление на компоненты низкого уровня. Это делает их более стабильными в том смысле, что их рефакторинг болезненно. Эмпирически абстракции реже подвергаются рефакторингу, чем реализации. по этой причине, хорошая идея, что низкоуровневые компоненты содержат в основном абстракции (интерфейсы и перечисления), чтобы избежать болезненного рефакторинга.
Патрик Смаккья - NDepend dev
источник
6

Я никогда не допускаю циклических зависимостей между классами или пространствами имен. В C #, Java и C ++ вы всегда можете нарушить циклическую зависимость от класса, введя интерфейс.

Кодирование test-first затрудняет введение циклических зависимостей.

Кевин Клайн
источник
4

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

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

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

Но если у вас нет веской и понятной причины, избегайте любой зависимости, которую сможете. Зависимый код - ад отладочной сессии.

Klaim
источник
2

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

При этом Джон Лакос очень строго исключил все циклы (время сборки). Боб Мартин, однако, придерживался позиции, что значительными являются только циклы между двоичными файлами (например, DLL, исполняемыми файлами); он полагал, что циклы между классами в двоичном коде не очень важны.

Я лично придерживаюсь мнения Боба Мартина по этому вопросу. Однако я все же уделяю некоторое внимание циклам между классами, потому что отсутствие таких циклов облегчает чтение и изучение кода другими.

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

Брент Ариас
источник
0

Почти полностью, потому что циклы зависимости типа сборки неудобны в Haskell и невозможны в Agda и Coq, и это языки, которые я обычно использую.

Робин Грин
источник