Повторяющийся код - это термин компьютерного программирования для последовательности исходного кода которое происходит более одного раза, либо в программе, либо в разных программах, принадлежащих или поддерживаемых одним и тем же лицом. Дублирование кода обычно считается нежелательным по ряду причин. Минимальное требование обычно применяется к количеству кода, который должен появиться в последовательности, чтобы он считался дублирующим, а не случайно подобным. Последовательности повторяющегося кода иногда называют клонами кода или просто клонами, автоматизированный процесс поиска дубликатов в исходном коде называется обнаружением клонов.
Две кодовые последовательности могут быть дубликатами друг друга, не будучи идентичными посимвольно, например, будучи идентичными посимвольно, только когда символы пробела и комментарии игнорируются, или будучи токен в обмен на токен идентичен, или токен в обмен на токен идентичен с редкими вариациями. Даже кодовые последовательности, которые идентичны только функционально, могут считаться повторяющимся кодом.
Вот некоторые из способов создания дублирующего кода:
. Также может случиться так, что потребуется функциональность, очень похожая на ту в другой части программы, и разработчик независимо пишет код, очень похожий на то, что существует в другом месте. Исследования показывают, что такой независимо переписанный код обычно синтаксически не похож.
Автоматически сгенерированный код, когда дублирование кода может быть желательным для увеличения скорости или простоты разработки, является еще одной причиной дублирования. Обратите внимание, что фактический генератор не будет содержать дубликатов в своем исходном коде, а будет только вывод, который он производит.
Дублирующийся код чаще всего исправляется перемещением кода в его собственный модуль (функцию или модуль) и вызовом этого модуля из всех мест, где он изначально использовался. Использование более открытого стиля разработки, при котором компоненты находятся в централизованном расположении, также может помочь с дублированием.
Код, который включает повторяющиеся функции, труднее поддерживать,
С другой стороны, если одна копия кода используется для разных целей, а она не должным образом задокументированный, существует опасность, что он будет обновлен для одной цели, но это обновление не будет требоваться или соответствовать его другим целям.
Эти соображения не имеют отношения к автоматически сгенерированному коду, если в исходном коде есть только одна копия функциональности.
В прошлом, когда объем памяти был более ограничен, дублированный код имел дополнительный недостаток, заключающийся в том, что занимал больше места, но в настоящее время это вряд ли станет проблемой.
При копировании кода с уязвимостью программного обеспечения уязвимость может продолжать существовать в скопированном коде, если разработчик не знает о таких копиях. Рефакторинг дублированного кода может улучшить многие показатели программного обеспечения, такие как строк кода, цикломатическая сложность и сцепление. Это может привести к сокращению времени компиляции, снижению когнитивной нагрузки, меньшему количеству человеческой ошибки и меньшему количеству забытых или пропущенных фрагментов кода. Однако не все дублирование кода можно отредактировать. Клоны могут быть наиболее эффективным решением, если язык программирования предоставляет неадекватные или слишком сложные абстракции, особенно если они поддерживаются такими методами пользовательского интерфейса, как. Более того, риски взлома кода при рефакторинге могут перевесить любые преимущества обслуживания. Исследование, проведенное Вагнером, Абдулхалеком и Кайей, пришло к выводу, что, хотя необходимо проделать дополнительную работу, чтобы синхронизировать дубликаты, если задействованные программисты знают о дублированном коде, не было бы значительно больше ошибок, чем в недублированном коде.
Для обнаружения повторяющегося кода был предложен ряд различных алгоритмов. Например:
Рассмотрим следующий фрагмент кода для вычисления среднего массив из целых чисел
extern int array_a; extern int array_b; int sum_a = 0; for (int i = 0; i < 4; i++) sum_a += array_a[i]; int average_a = sum_a / 4; int sum_b = 0; for (int i = 0; i < 4; i++) sum_b += array_b[i]; int average_b = sum_b / 4;
Два цикла можно переписать как одну функцию:
int calc_average_of_four (int * array) {int sum = 0; for (int i = 0; i < 4; i++) sum += array[i]; return sum / 4; }
или, обычно предпочтительно, путем параметризации количества элементов в массиве.
Использование вышеуказанной функции даст исходный код без дублирования цикла:
extern int array1; extern int array2; int average1 = calc_average_of_four ( array1); int average2 = calc_average_of_four (array2);
Обратите внимание, что в этом тривиальном случае компилятор может выбрать inline для обоих вызовов функции, так что результирующий машинный код будет идентичен для обоих дублированные и не дублированные примеры выше. Если функция не встроена, то дополнительные накладные расходы на вызовы функций, вероятно, потребуют больше времени (порядка 10 инструкций процессора для большинства высокопроизводительных языков). Теоретически это дополнительное время для выполнения может иметь значение.
Пример исправления повторяющегося кода с помощью кода, замененного методом