window.pipedriveLeadboosterConfig = { base: leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster on juba olemas') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() thecodest, autor aadressil The Codest - Page 8 of 18

Seetõttu on mõnede jaoks arusaamatu, et refaktooring on tegelikult üks programmeerimise valdkond ja see on ka väga oluline osa programmeerija tööst. Kood on pidevalt arenev, seda muudetakse niikaua, kuni on võimalus lisada uusi funktsioone. Samas võib see võtta sellise kuju, mis ei võimalda enam tõhusalt uusi funktsionaalsusi lisada ja lihtsam oleks kogu programm ümber kirjutada.

Mis on refaktooring?

Tavaliselt on vastus, mida te kuulete, et tegemist on koodi struktuuri muutmisega, rakendades rea refaktooring-transformatsioone, ilma et see mõjutaks koodi jälgitavat käitumist. See on tõsi. Hiljuti puutusin ma ka kokku määratlusega, mille autor on Martin Fowler oma raamatus "Olemasoleva koodeksi kujunduse parandamine" kus ta kirjeldab refaktooring kui "suurte muudatuste tegemine väikeste sammudega". Ta kirjeldab refaktooring koodimuudatusena, mis ei mõjuta selle toimimist, kuid ta rõhutab, et seda tuleb teha väikeste sammude kaupa.

Raamat toetab ka seda, et refaktooring ei mõjuta koodi toimimist ja juhib tähelepanu sellele, et see ei mõjuta mingil juhul testide läbimist. Selles kirjeldatakse samm-sammult, kuidas ohutult teostada refaktooring. Mulle meeldis tema raamat, sest selles kirjeldatakse lihtsaid nippe, mida saab kasutada igapäevatöös.

Miks me vajame refaktooringut?

 Kõige sagedamini võib seda vaja minna siis, kui soovite võtta kasutusele uue funktsionaalsuse ja kood oma praeguses versioonis seda ei võimalda või oleks see ilma koodi muutmata keerulisem. Samuti on see kasulik juhtudel, kui uute funktsioonide lisamine ei ole ajaliselt tasuv, st oleks kiirem kirjutada kood nullist ümber. Ma arvan, et mõnikord unustatakse, et refaktooring võib muuta koodi puhtamaks ja loetavamaks. Martin kirjutab oma raamatus, kuidas ta teeb refaktooringut, kui ta tunneb koodis ebameeldivaid lõhnu ja kuidas ta seda väljendab, "see jätab alati ruumi paremale". Ja ta üllatas mind siin, nähes refaktoorimist kui igapäevase kooditöö elementi. Minu jaoks on koodid sageli arusaamatud, selle lugemine on natuke kogemus, kuna kood on sageli ebatäpne.

Hästi kavandatud programmi eripäraks on selle modulaarsus, tänu millele piisab enamiku muudatuste tegemiseks vaid väikese osa koodi tundmisest. Modulaarsus lihtsustab ka uute inimeste sisseelamist ja tõhusamat tööle asumist. Modulaarsuse saavutamiseks peavad omavahel seotud programmi elemendid olema grupeeritud, kusjuures seosed peavad olema arusaadavad ja kergesti leitavad. Ei ole olemas ühtset rusikareeglit, kuidas seda teha. Kui te teate ja mõistate üha paremini, kuidas kood peaks toimima, saate elemente rühmitada, kuid mõnikord tuleb ka testida ja kontrollida.

Üks refaktooringu reeglitest on YAGNI, see on akronüüm sõnast "You Aren't Gonna't Need It" ja tuleneb eXtreme programmeerimine (XP) kasutatakse peamiselt Agiilne tarkvaraarendus meeskonnad. Pikk lugu lühidalt, YAGNI ütleb, et teha tuleks ainult ajakohaseid asju. See tähendab põhimõtteliselt seda, et isegi kui midagi võib tulevikus vaja minna, ei tohiks seda praegu teha. Kuid me ei saa ka edasisi laiendusi maha suruda ja siinkohal muutub modulaarsus oluliseks.

Rääkides refaktooringtuleb mainida ühte kõige olulisemat elementi, st teste. Veebilehel refaktooring, peame teadma, et kood ikka veel töötab, sest refaktooring ei muuda selle tööd, vaid selle struktuuri, nii et kõik testid tuleb läbida. Kõige parem on pärast iga väikest ümberkujundamist käivitada testid selle koodi osa jaoks, millega me töötame. See annab meile kinnituse, et kõik töötab nii, nagu peab, ja lühendab kogu toimingu aega. Sellest räägib Martin oma raamatus - käivitage testid nii tihti kui võimalik, et mitte astuda sammu tagasi ja raisata aega, et otsida transformatsiooni, mis midagi rikkus.

Koodide refaktooring ilma katsetamiseta on valus ja on suur võimalus, et midagi läheb valesti. Kui see on võimalik, oleks parem lisada vähemalt mõned põhilised testid, mis annavad meile väikese kindlustunde, et kood töötab.

Allpool loetletud teisendused on ainult näited, kuid need on tõesti kasulikud igapäevases programmeerimises:

Näide

See on artikkel, mis käsitleb refaktooring ja vaja on näidet. Ma tahan näidata allpool lihtsat refaktooringu näidet, mille puhul on kasutatud Sisestatud avalduse ületamine ja Tingimusjuhiste polümorfismi asendamine. Oletame, et meil on programmifunktsioon, mis tagastab hashi, mis sisaldab teavet selle kohta, kuidas taimi reaalselt kasta. Selline teave oleks tõenäoliselt mudelis, kuid selle näite puhul on see meil funktsioonis.

def watering_info(plant)
     result = {}
     if plant.is_a? Suculent || plant.is_a? Kaktus
         result = { water_amount: ", how_to: "Altpoolt", kastmise_kestus: "2 nädalat" }
     elsif plant.is_a? Alocasia || plant.is_a? Maranta
         result = { water_amount: "Big amount", how_to: "Nagu soovite", kastmise_kestus: "5 päeva" }
     elsif plant.is_a? Peperomia
         result = { water_amount: "Dicent amount",
             how_to: "Altpoolt! neile ei meeldi vesi lehtedel",
             watering_duration: "1 week" }
     else
         result = { water_amount: "Dicent amount",
             how_to: "Nagu soovite",
             watering_duration: "1 nädal"
             }
     end
     return result
 end

Mõte on muuta, kui naasta:

if plant.isa? Suculent || plant.isa? Cactus

     result = { wateramount: ", howto: ",

aadressile

return { water_amount: ", how_to: "Altpoolt",watering_duration: "2 nädalat" } if plant.is_a? Suculent || plant.is_a? Kaktus

return { vesisumma: "Natuke " , kuidasto: "altpoolt", kastminekestus: "2 nädalat" } if plant.isa? Suculent || plant.is_a? Kaktus

Ja nii edasi, kuni jõuame funktsioonini, mis näeb välja selline:

def watering_info(plant)

return result = { wateramount: ", howto: "Altpoolt", wateringduration: "2 weeks" } if plant.isa? Suculent || plant.is_a? Cactus

return result = { wateramount: "Big amount", howto: "As you prefer", wateringduration: "5 päeva" } if plant.isa? Alocasia || plant.is_a? Maranta

return result = { water_amount: "Dicent amount",

          howto: "Altpoolt! nad ei armasta vett lehtedel",
          wateringduration: "1 nädal" } if plant.is_a? Peperomia

return result = { water_amount: "Dicent amount",

          how_to: "Nagu soovite",

          kastmise_kestus: "1 nädal"

          }

end

 Kõige lõpus oli meil juba tagastustulemus. Ja hea harjumus on teha seda samm-sammult ja testida iga muudatust. Selle if ploki võiks asendada switch case'iga ja see näeks kohe paremini välja ning ei peaks iga kord kõiki if'e kontrollima. See näeks välja nii:

def watering_info(plant)

swich plant.class.to_string

case Suculent, Cactus

     { wateramount: "Natuke " , howto: "Altpoolt", watering_duration: "2 nädalat" }

case Alocasia, Maranta

     { wateramount: "Big amount", howto: "Nagu soovite", watering_duration: "5 päeva" }

case Peperomia

     { water_amount: "Dicent amount",

          how_to: "Altpoolt! neile ei meeldi vesi lehtedel",

          kastmise_kestus: "1 nädal" }

else

     { water_amount: "Dicent amount",

            how_to: "Nagu soovite",

       kastmise_kestus: "1 nädal" }

end

end

Ja siis saate rakendada Tingimuslike juhiste polümorfismi asendamine. See on luua klass koos funktsiooniga, mis tagastab õige väärtuse ja lülitab need õigetele kohtadele.

klass Suculent

...

def watering_info()

     return { wateramount: ", howto: "Alalt", watering_duration: "2 weeks" }

end

end

klass Cactus

...

def watering_info()

     return { wateramount: ", howto: "Alalt", watering_duration: "2 weeks" }

end

end

klass Alocasia

...

def watering_info

     return { wateramount: "Big amount", howto: "Nagu soovite", watering_duration: "5 days" }

end

end

klass Maranta

...

def watering_info

     return { wateramount: "Big amount", howto: "Nagu soovite", watering_duration: "5 days" }

end

end

klass Peperomia

...

def watering_info

     return { water_amount: "Dicent amount",

      how_to: "Altpoolt! neile ei meeldi vesi lehtedel",

      kastmise_kestus: "1 nädal" }

end

end

klass Plant

...

def watering_info

     return { water_amount: "Dicent amount",

              how_to: "Nagu soovite",

              kastmise_kestus: "1 nädal" }

end

end

Ja põhilises watering_infofunction'is näeb kood välja selline:

def watering_info(plant)

    plant.map(&:watering_info)

end

Loomulikult võib selle funktsiooni eemaldada ja asendada selle sisuga. Selle näitega tahtsin esitada üldise refaktooringu muster.

Kokkuvõte

Refaktooring on suur teema. Ma loodan, et see artikkel oli ajendiks rohkem lugeda. Need refaktooringu oskused aitab teil leida oma vigu ja parandada oma puhta koodi töökoda. Soovitan lugeda Martini raamatut (Improving the Design of Existing Code), mis on üsna põhiline ja kasulik reeglistik refaktooring. Autor näitab erinevaid ümberkujundusi samm-sammult koos täieliku selgituse ja motivatsiooniga ning nõuandeid, kuidas vältida vigu refaktooring. Tänu oma mitmekülgsusele on see meeldiv raamat frontendile ja backend arendajad.

Hakka Junior Ruby arendajaks

Loe edasi

GraphQL Ruby. Kuidas on tulemuslikkus?

Rööpad ja muud transpordivahendid

Railsi arendamine TMUX, Vim, Fzf + Ripgrep abil

etEstonian