Refactoring — dastur kodining tashqi xatti-harakatini saqlagan holda uning ichki tuzilishini yaxshilash jarayoni.
Refactoring yangi funksiya qo‘shish yoki bugni ataylab tuzatish emas. Uning maqsadi kodni tushunarli, o‘zgartirishga qulay, testlanadigan va takrorlanishi kam holatga keltirishdir.
Amalda refactoring ko‘pincha yangi imkoniyat yoki bugfix bilan ishlashni osonlashtirish uchun bajariladi.
Tashqi xatti-harakat
Refactoringdan oldin va keyin:
- bir xil input;
- bir xil muhim output;
- bir xil API contract;
- bir xil side effect;
- bir xil xato semantikasi
saqlanishi kerak.
Performance yoki log formati o‘zgarishi ham ayrim tizimlarda tashqi xatti-harakat hisoblanishi mumkin.
Kichik qadamlar
Refactoring katta qayta yozishdan farq qiladi.
Jarayon kichik, tekshiriladigan qadamlar bilan bajariladi:
- mavjud testlar ishlaydi;
- bitta strukturaviy o‘zgarish qilinadi;
- test qayta ishlaydi;
- commit yoki keyingi qadamga o‘tiladi.
Xato paydo bo‘lsa, qaysi qadam sabab bo‘lganini topish oson.
Rename
Variable, function, class yoki module nomini ma’noli nomga almashtirish eng oddiy refactoringlardan biri.
Yaxshi nom:
- vazifani ifodalaydi;
- scopega mos;
- qisqartmasi tushunarli;
- type ma’lumotini takrorlamaydi;
- eskirgan terminni saqlamaydi.
IDE symbol asosida barcha reference’larni xavfsiz yangilashi mumkin.
Extract method
Uzoq function ichidagi mantiq alohida methodga chiqariladi.
Oldin:
validate
calculate
save
notify
hammasi bitta functionda.
Keyin har bosqich alohida nomlangan methodga ajratiladi.
Bu code reading va unit testni yengillashtiradi.
Inline method
Juda kichik va nomi qo‘shimcha ma’no bermaydigan method caller ichiga qaytarilishi mumkin.
Refactoring har doim ko‘proq function yaratish degani emas.
Keraksiz qatlam kodni tushunishni qiyinlashtiradi.
Extract class
Bitta class bir-biridan farqli bir nechta vazifani bajarsa, mas’uliyatlar alohida classlarga ajratiladi.
Masalan:
- hisoblash;
- database saqlash;
- notification yuborish
bitta class ichida bo‘lsa, dependency va test murakkablashadi.
Move method
Method ishlatayotgan data boshqa classga ko‘proq tegishli bo‘lsa, o‘sha classga ko‘chiriladi.
Bu feature envy deb ataladigan code smellni kamaytiradi.
Encapsulate field
Public field to‘g‘ridan-to‘g‘ri ochiq bo‘lsa, keyin validation qo‘shish qiyin.
Field private qilinib, method yoki property orqali boshqariladi.
Bu invariantni bir joyda saqlaydi.
Replace conditional with polymorphism
Katta if yoki switch type bo‘yicha turli xatti-harakatni tanlasa, har type o‘z implementationiga ega bo‘lishi mumkin.
Bu har yangi type qo‘shilganda markaziy conditionalni o‘zgartirishni kamaytiradi.
Biroq kichik va barqaror conditional uchun polymorphism ortiqcha murakkablik bo‘lishi mumkin.
Remove duplication
Bir xil mantiq bir nechta joyda takrorlansa, umumiy abstractionga chiqariladi.
Takrorlanish:
- aynan bir xil matn;
- bir xil algorithm;
- bir xil business rule;
- bir xil error handling
ko‘rinishida bo‘lishi mumkin.
Faqat tashqi ko‘rinishi o‘xshash, lekin kelajakda turlicha o‘zgaradigan kodni majburan birlashtirish noto‘g‘ri abstraction yaratadi.
Code smell
Code smell bugning o‘zi emas, ammo dizayn muammosiga ishora.
Misollar:
- uzun method;
- katta class;
- ko‘p parameter;
- duplicate code;
- global state;
- primitive obsession;
- shotgun surgery;
- dead code;
- deep nesting.
Har smell avtomatik refactoring talab qilmaydi; kontekst tahlil qilinadi.
Test
Refactoring xavfsizligi testlarga tayanadi.
Kerakli testlar:
- unit;
- integration;
- contract;
- regression;
- end-to-end.
Test mavjud bo‘lmasa, avval joriy xatti-harakatni qayd etuvchi characterization test yozilishi mumkin.
Characterization test
Legacy kodning nima qilishi hujjatda aniq bo‘lmasligi mumkin.
Characterization test mavjud outputni qayd etadi.
Bu output ideal bo‘lmasa ham, refactoring vaqtida tasodifiy o‘zgarishni aniqlaydi.
Keyin xatti-harakat alohida talab asosida o‘zgartiriladi.
Refactoring va rewriting
Refactoring — mavjud kodni bosqichma-bosqich yaxshilaydi.
Rewriting — katta qismini yangidan yozadi.
Rewrite’da eski tizimdagi yashirin business rule va edge case yo‘qolishi mumkin.
Refactoring esa ishlayotgan tizimni doimiy ishlaydigan holatda saqlashga intiladi.
Database refactoring
Schema o‘zgarishi application kodidan tashqari migration va data compatibility talab qiladi.
Misollar:
- column rename;
- table split;
- type o‘zgarishi;
- normalization;
- constraint qo‘shish.
Zero-downtime jarayonda eski va yangi application versiyasi vaqtincha bir schema bilan ishlashi kerak.
API refactoring
Public API signature’ini to‘g‘ridan-to‘g‘ri o‘zgartirish clientlarni buzadi.
Bosqichlar:
- yangi method qo‘shish;
- eski methodni deprecated qilish;
- adapter;
- migration davri;
- major version.
Ichki refactoring public contractni saqlaydi.
Performance
Strukturaviy o‘zgarish performance’ni tasodifan o‘zgartirishi mumkin.
Masalan:
- loop ichida yangi allocation;
- qo‘shimcha database query;
- cache yo‘qolishi;
- reflection;
- network call.
Benchmark va profiler muhim yo‘llarni tekshiradi.
Version control
Refactoring va funksional o‘zgarishlarni alohida commit qilish review’ni yengillashtiradi.
Reviewer:
- behavior change;
- file move;
- rename;
- formatting
ni ajrata oladi.
Katta avtomatik formatlash refactoring diffidan alohida qilinadi.
IDE refactoring
IDE parser, type system va symbol index orqali xavfsiz refactoring bajaradi.
Biroq dynamic reflection, string ichidagi class nomi, template va external config avtomatik topilmasligi mumkin.
Natija test va qidiruv bilan tekshiriladi.
Behaviorni tekshirish
Refactoringdan keyin faqat test natijasi emas, public API, database query soni, log contracti va external side effect ham solishtiriladi. Snapshot yoki golden master murakkab legacy outputni vaqtincha qayd etishi mumkin. Keyinchalik ortiqcha bog‘lanishlar maqsadli testlarga ajratiladi.
Bog‘liq tushunchalar
Code smell, Rename, Extract method, Encapsulation, Polymorphism, Technical debt, Regression test, Legacy code, API contract