Джанк (junk code) — това е код и зависимости, които не носят полза на проекта, но увеличават неговия обем, времето за изграждане и когнитивното натоварване на екипа. За разлика от мъртвия код, който никога не се изпълнява, джанкът може да работи, но го прави неефективно или излишно: дублиращи се библиотеки, неизползвани импорти, коментирани блокове, остарели polyfill-и и декоративни абстракции. Според доклада CodeScene Code Health Report (2025), средно 15 процента от зависимостите в мобилните проекти не се използват директно, а само теглят транзитивни пакети. Junk-кодът е допълнителното тегло на проекта: прави кодовата база по-дебела, но не по-силна. Редовният одит на зависимостите и премахването на излишни абстракции пряко подобряват скоростта на изграждане и качеството на кода.
Основни точки
Джанк (junk code) — сборен термин за код, конфигурации и зависимости, които съществуват в проекта, но нямат функционална стойност. Джанкът не е непременно счупен или неизползван — проблемът е, че присъствието му влошава метриките на проекта без адекватно оправдание.
Джанкът се дели на четири категории. Първа — излишни зависимости: библиотеки, добавени за една функция, която може да се реализира със стандартни средства. Втора — мъртъв товар: коментирани блокове, TODO без билети, празни методи и класове-заглушки. Трета — дублиращи се решения: две библиотеки, които правят едно и също нещо (например Gson и Kotlin Serialization в един проект). Четвърта — over-engineering: архитектурни слоеве, които не се използват, но се поддържат за в бъдеще.
Според изследване на Stripe Engineering Productivity (2025), премахването на 10 процента джанк от типичен проект намалява времето за пълно изграждане средно с 22 процента. Причина: всяка допълнителна зависимост увеличава графа за изграждане, всяка празна абстракция изисква време за разбиране, всеки коментиран блок отклонява вниманието.
Основната трудност в борбата с джанка е липсата на незабавни последици. Проект с junk-код се компилира и работи. Проблемите се натрупват постепенно: изграждането се забавя, броят на транзитивните зависимости расте, а след една година добавянето на нова функция отнема два пъти повече време, отколкото трябва.
Junk-зависимости — това са библиотеки и пакети, които са свързани към проекта, но не се използват директно в кода, или се използват само в една функция, която може по-лесно да се реализира със стандартни API-та.
Типични примери: библиотека за работа с JSON, когато проектът вече използва Kotlin Serialization (два парсера — това е джанк); библиотека Apache Commons Lang за един метод StringUtils.isEmpty, който се заменя от Kotlin extension isNullOrBlank; библиотека за DI, която се използва в един от десет модула, а останалите получават зависимости ръчно чрез конструктор.
Всяка допълнителна зависимост не е само допълнителен код в бинарния файл. Това е и увеличаване на повърхността за атака за уязвимости: според GitHub Advisory Database (2025), 40 процента от критичните CVE в мобилни проекти идват от транзитивни зависимости, които разработчиците не контролират. Колкото по-малко зависимости — толкова по-малка повърхност за атака.
// Преглед на Gradle дървото на зависимостите
./gradlew app:dependencies --configuration releaseRuntimeClasspath
// Намиране на неизползвани зависимости (Gradle плъгин)
plugins {
id "com.autonomousapps.dependency-analysis" version "2.0.0"
}
// Генериране на доклад за неизползвани библиотеки
./gradlew buildHealth
За iOS използвайте командата swift package show-dependencies, която показва пълното дърво на зависимостите. Инструментът Xcode Build Timeline показва колко време всяка библиотека добавя към изграждането. Ако библиотека заема 30 процента от времето за компилация, но се използва на един екран — тя е кандидат за премахване или замяна.
За Node.js (React Native) използвайте depcheck — инструмент, който намира неизползвани зависимости в package.json, и npm-check, който допълнително показва остарели версии. Въведете правило: всяка нова зависимост преминава през code review с обосновка защо не може със стандартни средства.
Мъртви импорти — най-разпространеният вид джанк. Те не влияят на времето за изпълнение, но увеличават времето за компилация: компилаторът обработва всеки импорт, дори и да не се използва. В големи проекти премахването на неизползвани импорти намалява времето за изграждане с 5–10 процента.
Съвременните IDE автоматично подчертават неизползваните импорти в сиво. Настройте автоматично почистване при запазване на файл: в IntelliJ IDEA — Optimize Imports on the fly, в Xcode — Editor > Remove Unused Imports. В CI добавете проверка: линтерът трябва да блокира комити с неизползвани импорти.
Коментиран код — друг вид джанк. Разработчиците коментират блокове, за да не загубят функционалност при рефакториране. Но git съхранява пълната история на промените: всеки изтрит код може да бъде възстановен с една команда git revert или git log -S
Правило: в хранилището няма коментиран код. Ако кодът не е необходим — изтрийте го завинаги. Ако кодът е необходим, но временно изключен — използвайте feature toggle с билет и срок. Коментари от типа // TODO: remove after migration — не ги оставяйте без срок. Поставете дата и задайте напомняне в календара.
Over-engineering — създаване на архитектурни слоеве, които не решават текущи проблеми, но изискват поддръжка. Това е един от най-трудните видове джанк, защото формално кодът е правилен: следва SOLID, покрит е с тестове и съответства на архитектурата. Проблемът е, че не е необходим.
Класически пример — абстрактен клас UseCase с един метод invoke, който просто извиква хранилището. Ако UseCase не добавя логика (кеширане, retry, трансформация), а само препредава повикването — това е излишна същност. Увеличава навигацията в проекта: разработчикът отваря UseCase, вижда invoke → repository — и затваря. Време загубено, полза нула.
Друг пример — излишна параметризация. Родов интерфейс с шест параметъра на типа, използван на едно място. Всеки параметър на типа е когнитивно натоварване: при четене на кода трябва да държите шест типа в ума си, въпреки че реално се използват само два. Ако абстракцията не се преизползва — тя е излишна.
Критерий за отсичане: ако абстракцията не се преизползва в три различни контекста — премахнете я. Абстракцията е оправдана, когато реално решава проблем с дублиране, а не когато прогнозира хипотетични бъдещи сценарии. YAGNI (You Ain't Gonna Need It) — най-добрият принцип за превенция на over-engineering.
Одитът на джанк изисква комбинация от статичен анализ, анализ на зависимости и ръчна проверка. Пълното автоматизиране на търсенето на излишни абстракции не е възможно, но техническият джанк (мъртви импорти, неизползвани библиотеки, коментиран код) се намира с инструменти.
| Категория | Инструмент | Какво проверява |
|---|---|---|
| Неизползвани зависимости | dependency-analysis (Gradle) | Библиотеки, които не се използват в кода |
| Неизползвани зависимости | depcheck (Node.js) | Пакети от package.json без импорти |
| Неизползвани зависимости | swift package --show-dependencies | Дърво на зависимостите SwiftPM |
| Мъртви импорти | IDE (Optimize Imports) | Неизползвани import изрази |
| Коментиран код | grep -r "//" / rg "^\s*//" | Блокове коментари с код |
| Празни методи/класове | SonarQube / CodeClimate | Методи без тяло или с празно тяло |
| Дублиращи се библиотеки | Gradle lint (duplicate classes) | Конфликти на класове от различни библиотеки |
За пълен одит стартирайте buildHealth (Android) или depcheck (Node.js) веднъж на спринт. Създайте табло в CI, което показва динамиката на броя зависимости в спринтовете. Ако броят расте, а функционалността не расте пропорционално — екипът натрупва джанк.
Обърнете внимание на duplicate classes — грешка, когато две библиотеки съдържат един и същ клас. Това не е само джанк, но и пряк източник на конфликти при изграждане. В Gradle такива конфликти се разрешават чрез force или exclude, но всяко такова разрешаване е сигнал, че една от библиотеките е излишна.
Почистването на джанк не е еднократна акция, а редовен процес. Без регламент джанкът се връща в рамките на два до три спринта. Най-добрата практика — отделяйте 10–15 процента от капацитета на всеки спринт за техническо почистване, включително одит на джанк.
Процесът се състои от четири стъпки. Първа — диагностика: стартиране на инструменти, получаване на доклад, приоритизиране. Висок приоритет — зависимости с известни CVE и дублиращи се библиотеки. Среден — мъртви импорти и коментиран код. Нисък — излишни абстракции (изискват ръчен анализ).
Втора — почистване: премахване на мъртви зависимости, замяна на дублиращи се библиотеки с една, премахване на коментиран код. Всяка промяна се прави в отделен комит с разбираемо съобщение: remove unused dependency: gson (replaced by kotlinx.serialization), delete commented code in LoginViewModel.
Трета — верификация: изграждане на проекта, стартиране на тестове, проверка на UI. Ако след премахване на зависимост тестовете минават — зависимостта наистина не е била необходима. Ако тестовете се провалят — значи някъде е останала скрита референция, която статичният анализатор не е открил.
Четвърта — превенция: актуализиране на списъка за проверка на code review, добавяне на правилото без нова зависимост без обосновка в Definition of Done, настройване на автоматична проверка в CI. Превенцията е единственият начин да се предотврати повторното натрупване на джанк.
Често задавани въпроси
Техническият дълг е съзнателно компромисно решение (бързо, но с ниско качество), което се планира да бъде поправено. Джанк не е съзнателно решение, а натрупан боклук: излишни зависимости, коментиран код, празни абстракции, които никой не е планирал и не иска да поддържа.
Оптималният ритъм — всеки спринт отделяйте 10 процента от времето за техническо почистване. Това позволява да държите джанка под контрол, без да натрупвате критична маса. Ако в проекта има много джанк — започнете с един голям спринт за почистване, след което преминете на редовен ритъм.
Измерете и покажете числата: измерете времето за изграждане преди и след премахване на 3–5 излишни зависимости. Икономия от 15–30 секунди на едно изграждане, умножена по броя изграждания на ден, дава часове спестено време за екипа. Числата убеждават по-добре от абстрактни призиви за чистота.
Да, особено ако зависимостта има CVE. Дори ако проектът е стабилен, уязвимост в транзитивна зависимост представлява риск за сигурността. Освен това при актуализация на SDK или език, старата зависимост може да стане несъвместима и нейното премахване преди ъпгрейда спестява часове миграция.
Всяко TODO без билет е джанк. Поставете правило: TODO се пише само във формат // TODO(PROJECT-1234): fix с връзка към задача в тракера. Редовно проверявайте TODO-тата и затваряйте тези, които са загубили актуалност. Просрочените TODO-та изтривайте — ако проблемът не се е появил за половин година, не е критичен.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също