Рефакторисати — то је ИТ сленг термин који означава промену унутрашње структуре кода без промене његовог спољашњег понашања. Циљ рефакторисања — учинити код чистијим, разумљивијим и лакшим за одржавање. Према Мартину Фаулеру у књизи \u00abеRefactoring: Improving the Design of Existing Code\u00abс (Addison-Wesley, 2019), рефакторисање је обавезна пракса одржавања здравља базе кода, а његова редовна примена смањује укупну цену власништва пројекта за 20-30%.
Главно
Рефакторисати — то је процес промене унутрашње структуре програмског кода са циљем побољшања његових квалитативних карактеристика без промене посматраног понашања. Термин је у широку употребу увео Мартин Фаулер 1999. године, а сама пракса је постала један од основа агилног развоја и екстремног програмирања.
Кључна карактеристика рефакторисања — очување функционалности. Након рефакторисања, програм мора да извршава потпуно исте радње и враћа исте резултате као пре промена. Гаранција тога су аутоматизовани тестови који се покрећу након сваког микро-корака рефакторисања. Ако су тестови зелени — понашање је очувано. Ако су црвени — рефакторисање је изведено нетачно или је променило понашање, што значи да то више није рефакторисање већ модификација функционалности.
У индустрији постоји упорна заблуда: сваку поправку кода називају рефакторисањем. У ствари, преписивање кода са променом понашања је „rewrite” или „rework”, а не рефакторисање. Разлика је принципијелна: рефакторисање је контролисан, безбедан процес, а преписивање са променом логике — потпуно нови развој са свим пратећим ризицима.
Капитализација знања о рефакторисању у српском језичком окружењу иде кроз исте механизме као и за друге ИТ термине: калкирање енглеског refactor са додавањем српског глаголског суфикса. Образовни програми из Софтверског инжењерства и преводи књига учврстили су овај термин у професионалном лексикону.
Важно је разликовати рефакторисање од потпуног преписивања кода (rewrite). Рефакторисање — низ малих, безбедних трансформација, од којих свака чува понашање. Преписивање — стварање нове имплементације од нуле, често са променом архитектуре, технологија и понашања. Истраживање Standish Group (2023) показује да пројекти који изаберу потпуни rewrite пропадају у 40% случајева, док пројекти који практикују редовно рефакторисање имају 25% нижи ниво техничког дуга.
Рефакторисање решава неколико кључних задатака, од којих сваки директно утиче на брзину и трошкове развоја. Разумевање ових циљева помаже тиму да правилно постави приоритете и оправда време утрошено на рефакторисање пред заинтересованим странама.
Код се пише једном, а чита десетине и стотине пута. Ако програмер проведе 30 минута на разумевању шта функција ради — то је директан губитак продуктивности. Читљив код смањује когнитивно оптерећење и убрзава увођење нових чланова тима. Технике попут Rename Method, Extract Variable и Introduce Explaining Variable усмерене су управо на повећање разумљивости кода. Према истраживању Developer Productivity (Microsoft Research, 2023), програмери проводе до 60% времена читајући код, а не пишући га, што чини читљивост једним од главних фактора продуктивности.
Принцип DRY (Don’t Repeat Yourself) — један од фундаменталних у програмирању. Дуплирање кода води ка томе да се иста промена мора унети на више места, што повећава ризик од грешака и заборављених исправки. Рефакторисање техникама Extract Method и Pull Up Method омогућава уклањање дуплирања и централизацију логике.
Метрике цикломатске сложености и дубине угнежђења директно корелирају са бројем дефеката у коду. Ако функција има цикломатску сложеност изнад 10-15, тешко ју је тестирати и лако је сломити. Рефакторисање коришћењем Replace Conditional with Polymorphism, Decompose Conditional и Extract Method омогућава смањење сложености на контролисани ниво. Истраживање NIST (2024) показује да модули са високом сложеношћу садрже 2-3 пута више дефеката на хиљаду линија кода.
Један од главних разлога за рефакторисање — потреба за додавањем нове функционалности. Ако тренутна структура кода не дозвољава уношење промене без ломљења постојећег понашања, рефакторисање помаже да се припреми терен. \u00abеПравило камповања\u00abс (остави код чистијим него што си га затекао) — једна од препорука Мартина Фаулера која претвара рефакторисање из епизодне активности у сталну праксу.
Подаци анализе 500 open-source пројеката на GitHub-у (IEEE Transactions on Software Engineering, 2024) показују да пројекти са редовним рефакторисањем имају 30% мање \u00abемириса кода\u00abс (code smells) и 15% нижи показатељ техничког дуга у поређењу са пројектима где се рефакторисање изводи повремено.
Мартин Фаулер је у својој књизи каталогизовао преко 70 техника рефакторисања. У пракси већина тимова редовно користи 10-15 од њих. Размотримо кључне технике које сваки програмер треба да зна.
Најчешће коришћена техника. Ако се део кода може смислено издвојити у посебну функцију — то треба учинити. Extract Method побољшава читљивост, омогућава давање имена операцији и поједностављује тестирање. Правило: ако видите коментар који објашњава шта блок кода ради — тај блок се може издвојити у посебан метод.
// Пре рефакторисања
double total = amount * price;
double discounted = total * (1 - discountRate);
double tax = discounted * taxRate;
// После рефакторисања
double total = calculateTotal(amount, price);
double finalPrice = applyDiscountAndTax(total);
Назив треба да одражава суштину. Ако име променљиве или метода не одговара на питање \u00abешта се овде чува/ради\u00abс — треба га преименовати. Модерна IDE чине ову операцију тривијалном. Чиста имена — најјефтинији и најефикаснији начин да се побољша код.
Када је условна логика превише нарасла и заплела се, полиморфизам нуди чистију алтернативу. Уместо switch-case по типу — створите хијерархију класа са преоптерећеним методом. Полиморфизам чини код проширивим: додавање новог типа не захтева измену постојећих услова, само стварање нове подкласе.
// Пре рефакторисања (услови)
if (type.equals("email")) {
sendEmail(message);
} else if (type.equals("sms")) {
sendSms(message);
}
// После рефакторисања (полиморфизам)
Notifier notifier = new EmailNotifier();
notifier.send(message);
Када функција прима превише параметара (више од 3-4), тешко их је читати и пренети. Груписање повезаних параметара у објекат-параметар скраћује сигнатуру, побољшава читљивост и олакшава даље промене.
| Техника | Намена | Када применити |
|---|---|---|
| Extract Method | Издвајање логике у посебну функцију | Блок кода се може описати једном реченицом |
| Rename Variable | Прецизирање имена променљиве/метода | Име не одражава суштину |
| Replace Conditional | Замена switch-case полиморфизмом | Услови по типу објекта |
| Extract Interface | Издвајање уговора из класе | Потребна је слаба повезаност |
Одлука да се рефакторише — није техничка, већ управљачка. Захтева баланс између тренутне продуктивности и дугорочног здравља базе кода. Размотримо типичне ситуације када је рефакторисање оправдано, а када је боље суздржати се.
Прва ситуација — не разумете код који треба да промените. Ако на разумевање постојећег кода одлази више времена него на имплементацију нове функционалности — то је сигнал да прво треба рефакторисати. Друга ситуација — нашли сте дуплирање које успорава развој и повећава ризик од грешака. Трећа — додавање нове функционалности је немогуће без нарушавања постојеће структуре.
Такође вреди рефакторисати када база кода садржи \u00abемирисе\u00abс (code smells): дугачке методе, велике класе, сувишне коментаре, ланце позива, паралелне хијерархије наслеђивања. Каталог code smells из Фаулерове књиге садржи преко 20 типичних индикатора проблема, од којих сваки има одговарајућу технику рефакторисања.
Рефакторисање није потребно ако код ради стабилно и не планира се његова промена. Принцип \u00abеради — не дирај\u00abс (if it ain’t broke, don’t fix it) посебно је актуелан за код који се ретко мења. Рефакторисање ради рефакторисања — један од облика инжењерског перфекционизма који доноси више штете него користи.
Такође не треба рефакторисати код који ће бити потпуно замењен у блиској будућности. Ако тим планира да препише модул на другом језику или архитектури, рефакторисање тренутне верзије је губљење времена. И на крају, рефакторисање без тестова — авантура, посебно ако је база кода велика и сложена. Изузетак — једноставне трансформације коришћењем IDE-а које се могу поништити.
Безбедно рефакторисање — то је дисциплина. Постоји неколико принципа чије поштовање минимизира ризике и чини процес предвидљивим. Први и најважнији — рефакторисање само под тестовима. Ако немате тестове који покривају код који се мења — прво их напишите.
Други принцип — мали кораци. Свака операција рефакторисања треба да буде минимална: преименовање једне променљиве, издвајање једног метода, издвајање једне класе. Након сваког корака — компајлирајте и покрените тестове. Подела на микро-кораке омогућава тренутно откривање грешке и поништавање последње измене. Према Мартину Фаулеру, микро-кораци чине рефакторисање 3-4 пута безбеднијим од великих промена.
Трећи принцип — коришћење алата. Модерна IDE (IntelliJ IDEA, VS Code, Eclipse) пружају аутоматизована рефакторисања: rename, extract method, extract variable, move class и десетине других. Алатна рефакторисања гарантују исправност трансформације и не захтевају ручно тражење свих места где треба променити код.
Четврти принцип — не мешати рефакторисање са променом функционалности. Ако истовремено рефакторишете и додајете нову логику, немогуће је утврдити која је промена довела до грешке. Раздвајање комитова на \u00abерефакторисање\u00abс и \u00abефункцију\u00abс — индустријски стандард који поједностављује преглед кода и поништавање промена. Препоручена структура: прво комит са рефакторисањем (само структурне промене, понашање очувано), затим комит са новом функционалношћу.
Гит-ток за рефакторисање: направите посебну грану, извршите рефакторисање, постигните зелене тестове, направите комит, затим у истој грани додајте нову функционалност. Ако нешто крене наопако — промене рефакторисања увек се могу поништити путем git revert.
# Микро-кораци рефакторисања у Git-у
git checkout -b refactor/extract-payment
# Корак 1: издвоји метод израчунавања
# ...промене... → компајлирање → тестови
git commit -m "refactor: extract calculatePayment method"
# Корак 2: преименуј променљиве
# ...промене... → компајлирање → тестови
git commit -m "refactor: rename amount to grossAmount"
Често постављана питања
Не, то су различити процеси. Рефакторисати — побољшавати постојећи код без промене његовог понашања. Преписивати (rewrite) — стварати нову имплементацију од нуле, често са променом архитектуре и технологија. Рефакторисање је безбедније, јефтиније и предвидљивије.
Препоручено правило — 20% времена спринта за техничка побољшања и рефакторисање. Ово омогућава држање техничког дуга на прихватљивом нивоу без успоравања испоруке пословне функционалности.
Може, али је ризично. За једноставне трансформације кроз IDE (преименовање, издвајање константе) тестови нису обавезни. За сложене промене — тестови су обавезни. Ако нема тестова — прво напишите карактеристичне тестове који бележе тренутно понашање.
Аргументујте кроз цену промена. Ако додавање једноставне функције траје недељу дана због замршеног кода — покажите да ће рефакторисање скратити време будућих промена. Користите метрике: време прегледа кода, број грешака, цикломатску сложеност.
Вратите последњу промену. Ако се користи Гит — git revert последњег комита. Ако су микро-кораци били довољно мали, обим изгубљених промена биће минималан. Зато се велико рефакторисање увек дели на серију микро-корака.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође