Копи-пейст (copy-paste) — е практиката за копиране на фрагменти от код от едно място на друго без адаптиране към новия контекст. Най-често разработчикът копира блок от съществуващ модул, прави минимални промени и го поставя в новия — заедно с бъгове, остарели коментари и излишни зависимости. Според проучване на TIOBE Code Quality Survey (2025), проектите с високо ниво на копи-пейст съдържат три пъти повече дефекти на хиляда реда код, отколкото проектите с единна абстракция. Дублиране на код — основният доставчик на технически дълг: всяко копие изисква отделна поддръжка, а поправката на бъг на едно място не гарантира поправката му на останалите.
Основни точки
Копи-пейст (copy-paste programming) — е прехвърляне на съществуващ код на ново място с малки промени или без промени. Терминът се използва в унизителен смисъл: предполага, че разработчикът не проектира решението, а механично копира готов блок, често без да разбира напълно как работи.
Копи-пейст бива два вида: оправдан (intentional) и случаен (accidental). Оправдан — когато разработчикът умишлено копира код с план за последващ рефакторинг (но планът често не се изпълнява). Случаен — когато дублирането възниква незабелязано, например двама разработчици независимо пишат една и съща логика за различни екрани.
Според доклада SonarQube State of Clean Code (2025), дублираният код съставлява средно 12–18 процента от общия обем на кода в търговските проекти. В същото време разходите за поправка на бъг в дублиран код са 2,5 пъти по-високи, отколкото в код с единна имплементация, защото разработчикът трябва да намери и поправи всички копия.
Основният инструмент за борба с копи-пейст е принципът DRY (Don't Repeat Yourself). Въпреки това, абсолютизирането на DRY също е опасно: понякога копирането е оправдано, когато две копия трябва да еволюират независимо едно от друго. Важно е да се прави разлика между „случайно дублиране” (което трябва да се премахне) и „необходимо дублиране” (което трябва да се документира).
Първата и най-важна опасност — размножаване на бъгове. Ако в изходния код има дефект, той се копира на всички нови места заедно с кода. Когато дефектът бъде открит и поправен в изходния модул, копията остават непоправени. Разработчикът може дори да не подозира, че бъгът съществува в пет различни файла.
Втората опасност — неравномерна еволюция. Две копия на един и същ алгоритъм с времето придобиват различни промени. В едното копие е добавена валидация на граничните стойности, в другото — променен е изходният формат. След няколко месеца става невъзможно да се определи коя версия е „правилна” и проектът губи консистентност на поведението.
Третата опасност — увеличаване на обема на тестовете. Всяко копи-пейст изисква свои тестове. Ако общата логика бъде извлечена в една функция, тя може да бъде покрита с един набор от тестове и да се използва повторно. При дублиране всяко копие трябва да се тества отделно — това многократно увеличава времето за изпълнение на CI и обема на поддържаната тестова база.
Четвъртата опасност — илюзия за продуктивност. Копи-пейст създава фалшиво усещане за скорост: разработчикът бързо вмъква код и вижда, че екранът работи. Но тази „скорост” се превръща в технически дълг, който ще трябва да се върне с лихвите, когато в дублирания бъде открит бъг или се наложи промяна на бизнес логиката.
Разбирането на причините за копи-пейст помага за изграждане на правилна преванция. Най-често разработчиците копират код не от мързел, а поради натиск от срокове, липса на знания или неудобна архитектура.
Първата причина — срокове. Когато трябва да се направи екран за два дни, а подобен екран вече съществува, разработчикът го копира изцяло и променя само това, което потребителят вижда. За рефакторинг с извличане на общ компонент няма време — клиентът очаква резултат. В резултат се появява втори екран с 80 процента общ код, но с независима история на промените.
Втората причина — липса на единна абстракция. Ако в проекта няма общ компонент за типична задача (например екран за списък с pull-to-refresh), всеки разработчик ще пише своя имплементация или ще копира съседната. Архитектурните решения, взети в началото на проекта, пряко влияят върху количеството бъдещ копи-пейст.
Третата причина — страх от счупване на работещ код. Разработчикът знае, че съществуващият модул работи. Рефакторингът с извличане на общ код може да засегне съществуващата функционалност. Ако тестовото покритие е ниско, рискът от счупване надвишава възприеманата полза от рефакторинга и разработчикът избира безопасния път — копиране.
Премахвайте причините, а не симптомите. Скъсяването на срокове и въвеждането на code review няма да реши проблема, ако в проекта липсва обща архитектурна основа. Инвестирайте време в създаване на компоненти за многократна употреба в ранните етапи — това е единственият начин да намалите изкушението за копи-пейст в бъдеще.
Търсенето на копи-пейст се извършва от автоматични анализатори, които сравняват фрагменти от код и определят съвпадения над зададен праг. Най-добрите инструменти работят на ниво AST (абстрактно синтактично дърво) и игнорират форматирането, имената на променливи и коментарите.
PMD CPD (Copy-Paste Detector) — най-разпространеният инструмент за Java, Kotlin, Swift, JavaScript, Python и C++. CPD анализира токените на изходния код и намира дубликати, по-дълги от зададен минимален брой токени (по подразбиране 100). Настройването на прага е ключът към качествен резултат: твърде нисък праг дава много фалшиви положителни резултати (общи модели като импорти), твърде висок — пропуска реални дубликати.
plugins {
id 'pmd'
}
pmd {
toolVersion = '7.0.0'
ruleSetFiles = files("pmd-rules.xml")
}
tasks.register('cpd') {
doLast {
exec {
workingDir = projectDir
commandLine 'cpd',
'--minimum-tokens', '75',
'--language', 'kotlin',
'--files', 'src/main/kotlin',
'--format', 'xml',
'--failOnViolation', 'true'
}
}
}
SonarQube вгражда детектора за дубликати директно в Quality Gate. Правилото Duplicated Blocks (%) показва дела на дублирания код. Прагът от 5 процента се счита за здравословен за търговски проекти. Превишаването блокира промоцията в release клона. SonarQube допълнително групира дубликатите по тип: точни копия (exact match) и структурни копия (с променени имена).
За JavaScript и TypeScript дубликатите се търсят с ESLint и плъгина eslint-plugin-sonarjs (правило no-duplicate-string) и инструмента jscpd, който поддържа 150+ езика. jscpd е особено удобен за монорепозиториуми: намира дубликати между пакети, а не само в рамките на един модул.
Рефакторингът на копи-пейст се свежда до един принцип: извлечете общото и параметризирайте разликите. Конкретната техника зависи от обхвата на дублиране и контекста.
Най-простият случай — дублиране в един клас (например два метода с една и съща логика, но различни типове). Решение — обобщаване чрез генерици или повторно използване на метода с параметър тип. Ако дублирането обхваща няколко класа — извлечете общия код в клас за помощни функции или extension функция.
По-сложен случай — дублиране на ниво екрани или модули. Тук простото извличане на функция не помага, защото се дублира структурата на UI, логиката на жизнения цикъл и свързването на данни. Решение — създайте общ базов клас за екрана или компонент за композитен изглед, а разликите предавайте чрез параметри или протокол.
// преди - две копия на един и същ UITableViewController
class UserListController: UITableViewController {
private let viewModel = UserListViewModel()
// 40 реда код
}
class ProductListController: UITableViewController {
private let viewModel = ProductListViewModel()
// същите 40 реда, но с Product вместо User
}
// след - споделен общ базов клас
class ListViewController<T: ListViewModel>: UITableViewController {
let viewModel: T
// 40 реда код - само веднъж
init(viewModel: T) {
self.viewModel = viewModel
super.init(style: .plain)
}
}
Най-сложният случай — дублиране между микрослужби или библиотеки. Извличането на общ код може да доведе до циклични зависимости или неоправдано свързване. В такива случаи копи-пейст може да бъде съзнателно решение: два екипа поддържат независими услуги и общата библиотека създава повече проблеми, отколкото решава. Най-важното — документирайте такова решение и редовно проверявайте дали копията не са се разминали толкова много, че е време за унификация.
Преванцията на копи-пейст е по-ефективна от рефакторинга на вече дублиран код. Основните превантивни мерки са в организацията на процеса на разработка, а не в технологиите.
Първата мярка — code review с акцент върху дублирането. Контролният списък за проверка трябва да включва точка: „Има ли в този PR код, който вече съществува в проекта?”. Ако рецензентът види копи-пейст — блокира сливането до извличане на общия компонент. Това изискване трябва да бъде записано в Definition of Done на екипа.
Втората мярка — обща библиотека от компоненти. Всеки UI модел, който се среща на два или повече екрана, трябва да бъде извлечен в общ модул. Създайте споделен модул в проекта и го направете задължителна входна точка за всички UI компоненти. Ако компонентът не съществува — първо го създайте, след това го използвайте на екрана.
Третата мярка — автоматизация в CI/CD. Добавете стъпка към тръбопровода с проверка за дублиран код (PMD CPD, jscpd, SonarQube). Превишаването на прага е грешка при компилация. Разработчикът не може да слее PR, който увеличава дела на копи-пейст над допустимото ниво. Това прехвърля отговорността от code review към автоматизацията и гарантира, че нито един дубликат няма да бъде пропуснат.
Въведете културата „една имплементация — едно място”. Ако видите възможност за повторна употреба — не отлагайте рефакторинга за по-късно. Всяко копи-пейст, оставено „за по-късно”, се умножава и превръща в неконтролируем технически дълг.
Често задавани въпроси
Не, има сценарии на съзнателно дублиране: различни микрослужби, които трябва да еволюират независимо; код, копиран за експеримент с план за премахване; шаблонни DTO за различни API версии. Важното е да документирате причината и да зададете срок за проверка за рефакторинг.
Копи-пейст — когато две части от кода правят едно и също нещо, но нямат обща абстракция. Здравословно повторно използване — когато общият код е извлечен във функция, клас или модул, а разликите са параметризирани. Ако промяната на логиката изисква корекция на три или повече места — това е копи-пейст.
PMD CPD поддържа Swift и Objective-C. За Xcode има плъгини като SwiftCop и вградения детектор за дубликати в AppCode. SonarQube също анализира Swift проекти, показвайки дублирани блокове директно в pull request.
Създайте технически билет за рефакторинг на всяко голямо копие. Определете приоритет: екрани, които често се променят — първо, стабилни — второ. За всеки нов PR, който засяга дублиран код, отделяйте 15–20 процента от времето за постепенна консолидация.
Да, съвременните AI асистенти (GitHub Copilot, Codeium) могат да анализират контекста и да предложат извличане на общ код при откриване на повтарящи се модели. Те обаче не заместват автоматичните анализатори — използвайте Copilot за преванция, а CPD / SonarQube за детекция.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също