Lietuvių

Praktiškas vadovas apie pasenusio kodo refaktorinimą: identifikavimas, prioritetai, metodai ir gerosios modernizavimo bei palaikymo praktikos.

Pabaisos sutramdymas: pasenusio kodo refaktorinimo strategijos

Pasenęs kodas. Jau pats terminas dažnai sukelia vaizdinius apie išsiplėtusias, nedokumentuotas sistemas, trapias priklausomybes ir didžiulį siaubą. Daugeliui programuotojų visame pasaulyje tenka susidurti su iššūkiu prižiūrėti ir tobulinti šias sistemas, kurios dažnai yra gyvybiškai svarbios verslo operacijoms. Šiame išsamiame vadove pateikiamos praktinės pasenusio kodo refaktorinimo strategijos, kurios padės nusivylimo šaltinį paversti galimybe modernizuoti ir tobulinti.

Kas yra pasenęs kodas?

Prieš pradedant gilintis į refaktorinimo metodus, būtina apibrėžti, ką vadiname „pasenusiu kodu“. Nors šis terminas gali tiesiog reikšti senesnį kodą, tikslesnis apibrėžimas sutelktas į jo palaikymo galimybes. Michaelas Feathersas savo esminėje knygoje „Working Effectively with Legacy Code“ pasenusį kodą apibrėžia kaip kodą be testų. Dėl testų trūkumo sunku saugiai keisti kodą neįdiegiant regresijų. Tačiau pasenęs kodas gali turėti ir kitų savybių:

Svarbu pažymėti, kad pasenęs kodas savaime nėra blogas. Jis dažnai atspindi didelę investiciją ir įkūnija vertingas srities žinias. Refaktorinimo tikslas – išsaugoti šią vertę, kartu pagerinant kodo palaikymą, patikimumą ir našumą.

Kodėl verta refaktorinti pasenusį kodą?

Pasenusio kodo refaktorinimas gali būti nelengva užduotis, tačiau nauda dažnai nusveria iššūkius. Štai keletas pagrindinių priežasčių investuoti į refaktorinimą:

Kandidatų refaktorinimui nustatymas

Ne visą pasenusį kodą reikia refaktorinti. Svarbu refaktorinimo pastangas suskirstyti pagal šiuos veiksnius:

Pavyzdys: Įsivaizduokite pasaulinę logistikos įmonę su pasenusia siuntų valdymo sistema. Modulis, atsakingas už siuntimo išlaidų apskaičiavimą, dažnai atnaujinamas dėl besikeičiančių taisyklių ir degalų kainų. Šis modulis yra pagrindinis kandidatas refaktorinimui.

Refaktorinimo metodai

Yra daugybė refaktorinimo metodų, kurių kiekvienas skirtas konkretiems kodo „kvapams“ šalinti arba konkretiems kodo aspektams gerinti. Štai keletas dažniausiai naudojamų metodų:

Metodų komponavimas

Šie metodai skirti didelių, sudėtingų metodų skaidymui į mažesnius, lengviau valdomus metodus. Tai pagerina skaitomumą, sumažina dubliavimąsi ir palengvina kodo testavimą.

Funkcijų perkėlimas tarp objektų

Šie metodai skirti klasių ir objektų dizaino gerinimui, perkeliant atsakomybes ten, kur jos priklauso.

Duomenų organizavimas

Šie metodai skirti duomenų saugojimo ir prieigos būdų gerinimui, kad juos būtų lengviau suprasti ir keisti.

Sąlyginių išraiškų supaprastinimas

Sąlyginė logika gali greitai tapti paini. Šie metodai skirti jai paaiškinti ir supaprastinti.

Metodų iškvietimų supaprastinimas

Darbas su apibendrinimu

Tai tik keletas pavyzdžių iš daugybės galimų refaktorinimo metodų. Kurį metodą naudoti, priklauso nuo konkretaus kodo „kvapo“ ir norimo rezultato.

Pavyzdys: Didelis metodas Java programoje, kurią naudoja pasaulinis bankas, skaičiuoja palūkanų normas. Taikant Metodo iškėlimą (Extract Method), kad būtų sukurti mažesni, labiau sufokusuoti metodai, pagerinamas skaitomumas ir palengvinamas palūkanų normos skaičiavimo logikos atnaujinimas nepaveikiant kitų metodo dalių.

Refaktorinimo procesas

Refaktorinimą reikėtų vykdyti sistemingai, siekiant sumažinti riziką ir padidinti sėkmės tikimybę. Štai rekomenduojamas procesas:

  1. Nustatykite kandidatus refaktorinimui: Naudodamiesi anksčiau minėtais kriterijais, nustatykite kodo sritis, kurioms labiausiai praverstų refaktorinimas.
  2. Sukurkite testus: Prieš darydami bet kokius pakeitimus, parašykite automatizuotus testus, kad patikrintumėte esamą kodo elgseną. Tai labai svarbu norint užtikrinti, kad refaktorinimas neįdiegtų regresijų. Vienetų testams rašyti galima naudoti tokius įrankius kaip JUnit (Java), pytest (Python) ar Jest (JavaScript).
  3. Refaktorinkite palaipsniui: Darykite mažus, laipsniškus pakeitimus ir po kiekvieno pakeitimo paleiskite testus. Tai palengvina bet kokių atsiradusių klaidų nustatymą ir taisymą.
  4. Dažnai įkelkite pakeitimus (Commit): Dažnai įkelkite savo pakeitimus į versijų kontrolės sistemą. Tai leidžia lengvai grįžti prie ankstesnės versijos, jei kas nors nepavyktų.
  5. Peržiūrėkite kodą: Paprašykite kito programuotojo peržiūrėti jūsų kodą. Tai gali padėti nustatyti galimas problemas ir užtikrinti, kad refaktorinimas atliktas teisingai.
  6. Stebėkite našumą: Po refaktorinimo stebėkite sistemos našumą, kad įsitikintumėte, jog pakeitimai neįvedė jokių našumo regresijų.

Pavyzdys: Komanda, refaktorinanti Python modulį pasaulinėje el. prekybos platformoje, naudoja `pytest`, kad sukurtų vienetų testus esamam funkcionalumui. Tada jie taiko Klasės iškėlimo (Extract Class) refaktorinimą, kad atskirtų atsakomybes ir pagerintų modulio struktūrą. Po kiekvieno mažo pakeitimo jie paleidžia testus, kad užtikrintų, jog funkcionalumas išlieka nepakitęs.

Strategijos, kaip įvesti testus į pasenusį kodą

Kaip taikliai pasakė Michaelas Feathersas, pasenęs kodas yra kodas be testų. Testų įvedimas į esamas kodo bazes gali atrodyti kaip didžiulė užduotis, tačiau tai būtina saugiam refaktorinimui. Štai keletas strategijų, kaip spręsti šią užduotį:

Apibūdinimo testai (angl. Characterization Tests, dar žinomi kaip Golden Master Tests)

Kai susiduriate su sunkiai suprantamu kodu, apibūdinimo testai gali padėti užfiksuoti esamą jo elgseną prieš pradedant daryti pakeitimus. Idėja yra parašyti testus, kurie patvirtintų dabartinį kodo rezultatą tam tikram įvesties duomenų rinkiniui. Šie testai nebūtinai tikrina teisingumą; jie tiesiog dokumentuoja, ką kodas *šiuo metu* daro.

Žingsniai:

  1. Nustatykite kodo vienetą, kurį norite apibūdinti (pvz., funkciją ar metodą).
  2. Sukurkite įvesties verčių rinkinį, atspindintį įvairius įprastus ir kraštutinius scenarijus.
  3. Paleiskite kodą su tomis įvestimis ir užfiksuokite gautus rezultatus.
  4. Parašykite testus, kurie patvirtintų, kad kodas sukuria būtent tuos rezultatus toms įvestims.

Atsargiai: Apibūdinimo testai gali būti trapūs, jei pagrindinė logika yra sudėtinga ar priklausoma nuo duomenų. Būkite pasirengę juos atnaujinti, jei vėliau reikės pakeisti kodo elgseną.

„Daiginimo“ metodas ir klasė (angl. Sprout Method and Sprout Class)

Šie metodai, taip pat aprašyti Michaelo Featherso, skirti naujam funkcionalumui įvesti į pasenusią sistemą, minimalizuojant riziką sugadinti esamą kodą.

„Daiginimo“ metodas (Sprout Method): Kai reikia pridėti naują funkciją, kuri reikalauja keisti esamą metodą, sukurkite naują metodą, kuriame būtų nauja logika. Tada iškvieskite šį naują metodą iš esamo metodo. Tai leidžia izoliuoti naują kodą ir jį testuoti atskirai.

„Daiginimo“ klasė (Sprout Class): Panašiai kaip „daiginimo“ metodas, bet klasėms. Sukurkite naują klasę, kuri įgyvendina naują funkcionalumą, ir tada integruokite ją į esamą sistemą.

Izoliavimas (angl. Sandboxing)

Izoliavimas apima pasenusio kodo atskyrimą nuo likusios sistemos, leidžiant jį testuoti kontroliuojamoje aplinkoje. Tai galima padaryti sukuriant priklausomybių maketus (mocks) ar pakaitalus (stubs) arba paleidžiant kodą virtualioje mašinoje.

Mikado metodas

Mikado metodas yra vizualus problemų sprendimo būdas, skirtas sudėtingoms refaktorinimo užduotims. Jis apima diagramos, vaizduojančios priklausomybes tarp skirtingų kodo dalių, sukūrimą, o tada kodo refaktorinimą taip, kad būtų kuo mažesnis poveikis kitoms sistemos dalims. Pagrindinis principas yra „pabandyti“ pakeitimą ir pamatyti, kas sugenda. Jei sugenda, grįžkite į paskutinę veikiančią būseną ir užrašykite problemą. Tada spręskite tą problemą prieš bandydami atlikti pradinį pakeitimą iš naujo.

Įrankiai refaktorinimui

Keletas įrankių gali padėti atlikti refaktorinimą, automatizuojant pasikartojančias užduotis ir teikiant gaires dėl geriausių praktikų. Šie įrankiai dažnai integruojami į integruotas kūrimo aplinkas (IDE):

Pavyzdys: Programuotojų komanda, dirbanti su C# programa pasaulinei draudimo bendrovei, naudoja „Visual Studio“ integruotus refaktorinimo įrankius automatiškai pervadinti kintamuosius ir iškelti metodus. Jie taip pat naudoja „SonarQube“, kad nustatytų kodo „kvapus“ ir galimus pažeidžiamumus.

Iššūkiai ir rizikos

Pasenusio kodo refaktorinimas nėra be iššūkių ir rizikų:

Geriausios praktikos

Norėdami sušvelninti iššūkius ir rizikas, susijusias su pasenusio kodo refaktorinimu, laikykitės šių geriausių praktikų:

Išvada

Pasenusio kodo refaktorinimas yra sudėtingas, bet naudingas darbas. Laikydamiesi šiame vadove aprašytų strategijų ir geriausių praktikų, galite sutramdyti pabaisą ir paversti savo pasenusias sistemas palaikomais, patikimais ir našiais turtais. Nepamirškite sistemingai artėti prie refaktorinimo, dažnai testuoti ir efektyviai bendrauti su savo komanda. Kruopščiai planuodami ir vykdydami, galite atskleisti paslėptą potencialą savo pasenusiame kode ir nutiesti kelią ateities inovacijoms.