Технички дуг (Technical Debt) — метафора која описује цену компромиса у развоју: што се брже доносе неоптималне одлуке, то више камате се акумулира. Термин је увео Уорд Канингем 1992. године, поредивши лош код са финансијским дугом. Према Martin Fowler, технички дуг је неизбежан, али свесно управљање њиме разликује професионални тим од хаотичног.
Главно
Технички дуг (Technical Debt) — је метафора коју је први пут предложио Уорд Канингем 1992. године на OOPSLA. Он је упоредио програмирање са инвестирањем: немарни код је узети кредит. Камата се плаћа у виду додатног времена за одржавање, исправку багова и прилагођавање новим захтевима. Важно је разумети да дуг није увек лош; стратешки дуг може бити оправдан.
Финансијска аналогија ради готово дословно. Ако тим узме кредит (изда неидеалан код да би се уклопио у рок), мора да плаћа камату. Камата — успоравање развоја, багови при промени кода, тешкоћа онбординга нових програмера. Ако камата постане већа од цене рефакторисања — време је за отплату дуга. Главни проблем: за разлику од банкарског кредита, програмери нису увек свесни да су направили дуг.
Важно појашњење: технички дуг ≠ лош код. Лош код — последица некомпетентности. Технички дуг — свестан компромис. Тим разуме да ради нешто неидеално, бележи то у техничкој документацији и планира да се врати на побољшање. Разлика између дуга и лошег кода је у свесности одлуке. Зато је први корак ка управљању дугом — признати његово постојање.
Класификација техничког дуга помаже да се разуме његова природа и одабере права стратегија отплате. Мартин Фаулер је предложио квадрантни модел са две осе: намерни/ненамерни и непромишљени/опрезни. Свака комбинација захтева другачији приступ. Погледајмо основне врсте дуга са којима се суочава тим мобилног развоја.
Намерни дуг — тим свесно одлучује да изда неоптималан код да би се уклопио у рок. Пример: покретање MVP-а са једним монолитним ViewModel-ом, знајући да ће након валидације хипотезе ViewModel бити подељен на више према доменима. Такав дуг се бележи у беклогу и има планирани рок отплате. Без плана, намерни дуг постаје хронични.
Ненамерни дуг — код чији је квалитет нижи од очекиваног због недостатка знања, непостојања прегледа кода или лоших процеса. Пример: програмер није знао најбоље праксе за рад са Room DB и писао упите у UI нити, изазивајући ANR. Овакав дуг је најподмуклији — тим га не схвата док се не суочи са критичним проблемима перформанси.
Архитектурални дуг — неправилан избор образаца или структуре пројекта. Пример: апликација без слоја апстракције над мрежом, где се Retrofit користи директно из ViewModel-а. Замена Retrofit-а са Ktor-ом захтеваће промену свих ViewModel-а. Исправка архитектуралног дуга је најскупља, зато се одлуке на нивоу архитектуре доносе са максималним опрезом.
Дуг кода — локалне неоптималности унутар једне класе или метода. Пример: дугачак метод са 200 линија где су помешани UI, пословна логика и рад са подацима. Исправља се Extract Method за 15 минута. Дуг кода је мање критичан, али његово нагомилавање у размерама пројекта успорава развој не мање од архитектуралног.
Дуг тестирања — недостатак Unit тестова, UI тестова или интеграционих тестова. Свако ручно покретање регресије је камата на овај дуг. Ако у пројекту нема аутотестова, свака промена захтева сате ручног тестирања. Према Google Testing Blog-у, пројекти са покривеношћу тестова >70% 2 пута ређе испуштају багове у продукцију.
Дуг документације — недостатак или застарелост архитектуралне документације, коментара за сложене делове кода, readme за онбординг. Нови програмер губи недеље на урањање без документације. Решење: одржавати Architecture Decision Records (ADR) и учинити документацију делом Definition of Done за сваки задатак.
| Врста дуга | Пример | Сложеност исправке |
|---|---|---|
| Архитектурални | Неправилан избор обрасца | Висока (недеље) |
| Кода | Дугачак метод, дуплирање | Ниска (сати) |
| Тестирања | Недостатак Unit тестова | Средња (дани) |
| Документације | Застарела ADR | Ниска (сати) |
Ефекат сложене камате — главна опасност техничког дуга. Сваки нови слој неоптималног кода повећава сложеност система не линеарно, већ експоненцијално. Једноставан пример: ако модул А зависи од модула Б и оба садрже дуг, онда промена у А захтева разумевање дуга у Б. Након 10 итерација, програмер проводи 80% времена на распетљавање зависности и само 20% — на нову функционалност.
Успоравање time-to-market — директна последица дуга. Тим проводи све више времена на одржавање и све мање — на нове функције. Истраживање Stripe (2023) показало је да програмери проводе у просеку 17 сати недељно на рад са техничким дугом, а не на стварање вредности за бизнис. У мобилном развоју ово се погоршава потребом за подршком две платформе — свака са својим платформским ажурирањима.
Изгарање тима — неочигледна, али разорна последица. Рад у коду где свака промена ломи три друге изазива хронични стрес. Програмери престају да буду поносни на производ, мотивација опада, флуктуација кадрова расте. Према Stack Overflow Survey 2024, рад са legacy-кодом је други најчешћи разлог незадовољства послом после ниске плате.
Квадрант Фаулера — практични алат за приоритизацију дуга. Две осе: намерни/ненамерни и непромишљени/опрезни. Непромишљени намерни дуг: „немамо времена за тестове, пуштамо без њих". Опрезни намерни: „знамо да су тестови потребни, али сад је важније покренути функцију — отворићемо задатак за тестове у следећем спринту". Први захтева хитну интервенцију, други — контролу.
Стратегија Boy Scout Rule — „остави камповалиште чистијим него што си га затекао". Једноставно правило: при промени метода потроши 10% више времена да га учиниш мало бољим — преименуј променљиву, подели блок од 50 линија на два. У размерама тима, овај приступ даје постепено смањење дуга без издвајања посебних спринтова за рефакторисање. Побољшање треба да буде микроскопско, али редовно.
Издвајање времена за управљање дугом — маркер зрелости тима. Препоручује се резервисање 15–20% спринта за техничка побољшања. То не значи да тим 1 дан недељно не ради ништа осим рефакторисања. Технички задаци се равномерно распоређују: побољшање метрика, рефакторисање врућих тачака, ажурирање зависности. Без издвојеног времена, дуг расте непрекидно.
// Стратегија Boy Scout Rule у акцији
// Било: нечитљив метод са магичним бројевима
fun calc(a: Int): Int = a * 60 * 1000
// Постало: читљив метод са константама
private const val SECONDS_IN_MINUTE = 60
private const val MILLIS_IN_SECOND = 1000
fun minutesToMillis(minutes: Int): Int =
minutes * SECONDS_IN_MINUTE * MILLIS_IN_SECOND
Аутоматизација откривања дуга — трећи стуб управљања. Подесите обавештења за детекцију дугачких метода (>30 линија), класа (>500 линија), прекомерне угнеждености (>5 нивоа). Користите Danger или аналоге за аутоматске коментаре на пул-реквестима: ако метод прелази праг сложености, бот пише „Овај метод има цикломатску сложеност 12 — молимо размотрите поделу". Аутоматизација смањује оптерећење прегледа кода.
SonarQube — најпопуларнија платформа за анализу техничког дуга. Израчунава „број дана за исправку" — метрику разумљиву менаџерима. SonarQube подржава Kotlin, Swift, Java, Python и друге језике. Интегрише се у CI/CD пајплајн и не пропушта пул-реквест ако дуг прелази праг. За мобилне тимове ово је де-факто стандард.
За Android тимове такође се користе Detekt (статичка анализа Kotlin) и Android Lint. Detekt рачуна метрике кода и проналази Code Smell обрасце. Gradle додатак SonarQube Android обједињује резултате у један извештај. За iOS тимове — SwiftLint за статичку анализу и Periphery за проналажење неискоришћеног кода. Xcode Organizer приказује метрике перформанси које често корелирају са архитектуралним дугом.
CodeClimate и CodeFactor — облачна решења која анализирају GitHub/GitLab репозиторијуме и приказују динамику дуга. Оцењују сваки комит, омогућавајући праћење тренутка када је дуг почео да расте. График Maintainability — разумљив алат за комуникацију са менаџментом: „видите врх у марту? Тада смо форсирали издање и нагомилали дуг од 3 дана исправки".
Често постављана питања
Користите метафору кредита: „Можемо пустити функцију за 2 недеље сад, али сваки следећи спринт ћемо трошити 20% више времена на одржавање. Ако не отплаћујемо дуг, за 6 месеци спринт ће трајати 3 недеље уместо 2". Менаџери разумеју финансијску аналогију интуитивно.
За MVP и експерименте — да, ако је утврђен план отплате. За стартап који сутра мора да покаже прототип инвеститору — да. За производ са милион корисника — не, цена грешке је превисока. Кључни услов: свесна одлука са планираним датумом исправке.
SonarQube показује „Debt Ratio" — однос времена исправке према времену развоја. Нормалним се сматра Debt Ratio < 5%. За код: Lines of Code per Method, Cyclomatic Complexity, Duplication Rate. За процесе: однос времена на багове према времену на функције.
Не — ово је крајња мера. Практика показује да је издвајање 15–20% спринта за техничка побољшања ефикасније од „спринта рефакторисања". Рефакторисање без пословне вредности перципира се као губљење времена. Боље је уткати побољшања у сваки производни задатак.
Не — стратешки дуг може бити алат. Ако тим свесно узима дуг за покретање функције која ће донети приход, а затим га отплаћује — то је ефикасно управљање. Проблем почиње када се дуг нагомилава неконтролисано и нико не зна колико „камате" је већ натекло.
Закључци
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође