Анализ зависимостей программно? NDepend!
Как поддерживать качества код на должном уровне? Есть много способов – культура написания кода, регулярное code review, всевозможные договорённости внутри команды (convensions), парное программирование и прочие практики XP, TDD, BDD, DDD… Список можно продолжать, и в него будут попадать все более страшные слова :) Но на самом деле каждый выбирается для себя свой способ.
А как следить за качеством кода в большой команде или нескольких команд? А если вы ими руководите и не можете уследить за всем кодом, т.е. участвовать в его написании, или кода настолько много что его ревью отнимает много времени? Тут нужно что-то придумать. Нужна лакмусовая бумажка которая укажет нам какие участки большой code base пересматривать а какие можно упустить. Такой лакмусовой бумажкой могут стать утилиты статического анализа и метрики кода. Тогда, по метрикам кода можно определить участки требующие внимания.
А одна из таких утилит, достаточно навороченная, с возможностью просматривать большое число метрик – NDepend. Помимо всего прочего основной акцент NDepend – это анализ зависимостей, поэтому прежде всего он поможет для анализа и разрешения проблем с зависимостями в коде.
Основное применение для себя в NDepend, я нашел в том чтобы проверять зависимости между сборками, типами, методами и т.п.
И тут вступает в игру одна из самых красочных фич NDepend – Граф зависимостей (dependency graph).
Причем смотреть зависимости можно между сборками, типами, методами и т.п.
Линии между блоками имеют определенное значение и если навести на них можно получить описание. Например зависимость между классами Step и Workflow которые показаны на Графе зависимостей на картинке выше.
Причем тут следует сказать что NDepend работает как с solution файлами так и со сборками, поэтому можно анализировать сборки даже без исходного кода.
Еще одним графиком который умеет отображать NDepend – матрица зависимостей (dependency matrix)
Матрица зависимостей это другой вариант представления зависимостей между элементами кода. Она находиться в синхронизируемом состоянии с графом зависимостей.
Например на матрице зависимостей мы видимо такую метрику как dependency cycles в виде красных квадратов. Что за метрика можно посмотреть также в контекстной помощи.
Еще один визуализатор – это Метрики (Metrics)
Он просто визуализирует метрики кода в виде такой вот матрицы:
Между метриками можно переключатся и соотвественно определять наиболее большой элемент. Например если нас интересует количество строк код то нам небходимо выбрать метрику lines of code (LOC) и проанализирвоать самые большые по площади элменты матрицы метрик.
CQL (Code Query Language)
В NDepend включена такая фича как CQL. CQL – это похожий на SQL синтаксис для того чтобы делать запросы на анализируемый код и получать на выходе результат в виде соответствия или не соответствия метрик.
Например, запрос на картинке ниже выводит не используемые типы:
CQL полезен для написания собственных запросов на анализируемый код. Но NDepend содержит большой набор уже построенных запросов. На основании которых он выводит определенные рекомендации к коду.
На картинке ниже показаны запросы которые отработали на анализируемом кода, например есть неиспользуемые методы и типы.
Интересно также что NDepend может проверять покрытие, это если мы анализируем solution из Visual Studio:
Или запросы связанные с производительностью, в данном случае boxing/unboxing и размер объектов:
В NDepend можно просто и быстро строить новые запросы на CQL, например простенький запрос на картинке ниже:
Метрик, которые анализирует NDepend, очень много и сразу наверное все не понять. Но к примеру может помочь этот постер про метрики кода (взят отсюда, картинка кликабельная и можно загрузить):
Из наиболее полезных метрик можно выделить, кроме привычных нам по типу Lines of Code:
- Afferent coupling (Ca) Метрика описывает число типов или методов из внешних сборок, которые используют заданный тип или метод. Чем выше это значение – тем важнее заданный тип или метод для внешней сборки.
- Efferent coupling (Ce) Прямая противоположность Ca: описывает число внешних методов и типов сборки, которые использует определенный тип или метод. Чем выше значение, тем более зависимый указанный тип или метод от внешней сборки.
- Relational cohesion (H) Метрика описывает насколько сильно соотносятся типы внутри одной сборки. Обычно, типа внутри сборки могут быть сильно связаны, но не ооочень сильно (всему есть придел).
- Instability (I) Описывает насколько чувствительна определенная сборки относительно изменения в зависимых сборках. Измеряется как частное от efferent coupling (Ce) и total coupling (Ca+Ce).
- Abstractness (A) Описывает соотношение абстрактных типов в сборке.
- Distance from main sequence (D) Нестабильность (І) и абстрактность (А) должны быть сбалансированы. Другими словами сборка с высокой степеью абстрактности должна быть стабильной, так как она скорее всего используется другими сборками. Если сборка нестабильна (I), то скорее всего рано или поздно в нее будут внесены изменения и это повлечет собой необходимость вносить изменения в зависимые от нее сборки. С другой стороны, от от более “конкретной” сборка чаще всего не зависят другие сборки, в так случае допускается нестабильность (I) сборки в той или иной степени.
- Lack of cohesion (LCOM) В связанных классах большинство методов имеют дело с членами таких классов. Если окажется что большинство методов класса работают только с какой то частью методов связанных классов – это может стать индикатором того что ответственность (responsibility) класса слишком широкая и нужно произвести его декомпозицию (например разбить на классы).
- Cyclomatic complexity (CC) По этой метрике есть статья в википедии написанная сложным языком :) Можно понимать ее как анализ вложенностей метода. Описывает сколько возможных ветвлений и вложенностей, циклов, имеет метод. Метод с высоким CC сложно поддерживать.
Еще можно посмотреть определения всех метрик на сайте NDepend.
NDepend интегрируется с билд процессом – TFS, Cruise Control.NET, FinalBuilder, TeamCity. Для этого есть документация на сайте. Также есть консольный вариант. Так что автоматизируется задачи NDepend – “на ура”. Также в конце билда или анализа кода NDepend предоставляет сводный HTML отчет.
У NDepend есть возможность интегрироваться с Visual Studio 2008, 2010 (и наверное 2005, не проверял). Но к сожалению на загрузку дается только zip архив со всем необходимым. Мне кажется что им стоит все таки сделать простенький msi инсталлер и давать пользователю на выбор что загружать архив или его.
Также для NDepend есть определенный порог входа, и он достаточно не низкий. Метрик, графиков достаточно много и нужно уметь в них разбираться, анализировать и принимать решения. Для обучения на сайте есть неплохая документация, но к сожалению с “инсталляцией” самого продукта она не идет. Я думаю также можно найти подкасты или вебкасты в интернете. Например есть неплохое видео демо и туториал – Getting started
NDepend продукт не бесплатный, его стоимость порядка 400$ на 2 разработчика, и порядка 600$ на 2 билд компьютера. Это не дешево, поэтому каждому разработчику такой продукт не поставишь. К тому же в Trail/Open source/Academic лицензиях нет возможности зумирования на Графике зависимостей что весьма достает и делает анализ сложных и больших проект очень сложным. Мне бы хотелось чтобы зумирование разрешили в этих лицензиях.
NDepend продукт с достаточно захватывающими возможностями. Причем его сила не только в визуальной стороне. Визуальные графики – скорее для быстрого охвата и просмотра, а вот интеграция с билд процессом, и результаты CQL, и метрики покажут на что смотреть. Но малым командам, или индивидуальным разработчикам , или тем у кого небольшая code base такой продукт наверное не нужен – слишком дорог для этого. А вот большим командам, возможно с одним или несколькими архитекторами и большой code base – он пригодится. В таком сценарии визуальная часть устанавливается на компьютеры архитекторов плюс обязательная интеграция в билд процесс для остальных участников команды.
http://regfordev.blogspot.com/2011/02/ndepend.html