Чистый код – чистая совесть. Война с клонами кода
Всем привет. В этой статье я бы хотел рассказать о функционале Visual Studio, который поможет держать ваш код в чистоте. Для повторения описанных трюков необходимо поставить Visual Studio Enterprise (пробную версию можно достать тут).
Чем опасны клоны кода
На первый взгляд, клоны кодов не кажутся большой проблемой. Например, если рассмотреть данную проблему с точки зрения производительности приложения, то влияние клонов на нее сводится только к увеличению объема кода, что влечет за собой «раздувание» конечного приложения в собранном виде. Такое «раздувание» грозит дополнительным объемом RAM, необходимым для запуска приложения. Если не вдаваться в крайности (когда 90% вашего кода — бесполезные клоны), то в целом, клоны слабо влияют на конечную производительность приложения.
Но есть и обратная сторона медали: клоны могут негативно влиять на продуктивность вашей работы, как это не странно:). Рассмотрим эту проблему с точки зрения удобства поддержки и развития приложения. Если в вашем приложении есть клоны, то в случае изменения функционала или исправления ошибок, которые затрагивают работу с этими клонами, разработчику необходимо вносить одни и те же изменения. Если разработчик знает, куда в данном случае вносить изменения — это хорошо. А если нет?
Для того, чтоб это понять, давайте поймем природу появления клонов:
— Если разработчик обладает индийским майндсетом. В таком случае, он сам себе создает проблемы. Такого разработчика нужно воспитывать.
— Если над проектом работает команда разработчиков. Даже в случаях, когда фронт работы у каждого четко определен, случается такое, что два разработчика независимо друг от друга напишут одинаковые куски кода. Мы тут можем ввалится в обсуждения необходимости перед стартом проекта прорисовывать UML диаграммы, четко распределять обязанности. Но уверяю вас, даже там, где зрелость с точки зрения управления разработкой высока, клоны все равно встречаются
Так вот, о влиянии на продуктивность работы. Представим себе, что в команду прилетает какой-то баг, связанный, ну к примеру, с тем, что приложение на сервере не может получить доступ к какому-то файлу (из пальца высосал пример, но тем не менее). Прилетает этот баг на тимлида, который перенаправляет решение этой задачи на вас. Вы, зная, что в вашем функционале используется этот файл, пишете правку в методе, который работает с этим файлом, и с чувством выполненного долга отдаете это исправление на тесты. На следующий день вы получаете результаты тестов и с удивлением обнаруживаете, что на сервере все равно возникают ошибки при работе с этим файлом. Оказывается, что ваши исправления только частично решили проблему, так как есть клон, который не был исправлен. Итог: вы потеряли день, а баг не исправлен полностью. Как это повлияло на бизнес? День некорректной работы приложения легко запапить на финансовые потери, недополученную прибыль.
Поиск клонов с помощью Source Control
Решение этой проблемы достаточно простое. Прежде чем запускать сборку и публикацию приложения, проверьте код на наличие клонов. А чтоб не делать это руками, можно выгрузить последнюю версию кода из Source Control и в Visual Studio запустить анализатор кода на наличие клонов:
В результате вы получите табличку с обнаруженными клонами, разгруппированную по блокам Exact Match, Strong match, Middle match, Weak match. В моем случае получилось так:
Выделив два предполагаемых клона можно вызвать контекстное меню «Compare» для просмотра клонов:
Результат отображается в виде Diff-а:
Найденный клон является хорошим кандидатом для рефакторинга.
Механизм работы
Теперь немного о том, как это происходит поиск:
Pre-processing — на этом этапе код партиционируется, и определяется область поиска. Есть три основных цели этого этапа:
— Удаление не интересующих частей кода для поиска клонов. Например: разделение кода по языку программирования;
— Определение source units. Это разбиение кода на несвязанные куски;
— Определение кусков кода для сравнения. Производится над найденными source units.
После этого следует Coarse Matching — трансформация найденных кусков кода для сравнения в вид, удобный для сравнения.
Затем происходит Fine Matching — устранение явных совпадений, типа пробелы, комментариев и т.п.
И, наконец, Pruning — на этом этапе запускается алгоритм поиска клонов и идет ранжирование результатов.
Что касается самого алгоритма поиска клонов, стоит сказать, что это не просто тупое сравнение текста. Движок находит клоны с переименованными параметрами, изменённой последовательностью инструкций или в случае добавления новых инструкций.
Применение программы
Для того, чтоб механизм поиска клонов искал их там, где нужно, его нужно настроить. Идея состоит в том, что, есть стандартные куски кода, например, инициализации окна в WPF, которые не нужно включать в результат поиска клонов. Настройка осуществляется путем подбрасывания в наш проект файла с расширением «.codeclonesettings», в котором мы определяем исключения.
Ниже пример такой настройки:
У данного движка есть ряд ограничений:
— Код, который определяет типы данных, не участвует в сравнении. К примеру, если есть два класса с очень похожим набором полей, они не будут отмечены в результатах анализа.
— В поиске участвуют только инструкции (statements) внутри методов и определении свойств.
— В поиске не участвуют метода, количество инструкций в которых меньше 10. Но если очень хочется, можно поискать клоны конкретного выделенного куска кода:
— В поиске не будут отображены фрагмента с разность более 40%.
— В поиске не будут отображаться исключения, заданные в файле «.codeclonesettings».
Советы по применению данного движка:
— Применяйте анализатор ко всему вашему Code Base. Если ваш проект разбит на несколько Solution, создайте отдельный Solution, который включает все проекты.
— Если вы применяете T4 транформации либо другие способы автоматической генерации кода, исключайте их из анализа путем прописывания в файле «.codeclonesettings» соответствующих настроек. Например, для T4 можно сделать следующее: все сгенерированные файлы складывать в директорию «GeneratedFiles» вашего проекта. А в «.codeclonesettings» исключить эту директорию из поиска добавив «<exclusions> <file>GeneratedFiles\*.cs</file> </exclusions>».
— Запускайте анализатор во время изменения\добавления существующего кода или во время плановой «зачистки» кода.
Если есть вопросы, я всегда готов ответить в комментариях.