window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(funktion () { var w = vindue if (w.LeadBooster) { console.warn('LeadBooster findes allerede') } 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, Author at The Codest - Page 8 of 18

Derfor er det uforståeligt for nogle, at refaktorering er faktisk et område inden for programmering, og det er også en meget vigtig del af programmørens arbejde. Koden er i konstant udvikling, den vil blive ændret, så længe der er mulighed for at tilføje nye funktioner. Men den kan antage en form, der ikke længere giver mulighed for effektivt at tilføje nye funktioner, og det ville være lettere at omskrive hele programmet.

Hvad er refaktorering?

Normalt er svaret, at det er at ændre kodens struktur ved at anvende en række refaktoriseringstransformationer uden at påvirke kodens observerbare adfærd. Det er også rigtigt. For nylig stødte jeg også på en definition af Martin Fowler i sin bog "Forbedring af designet af eksisterende regler" hvor han beskriver refaktorering som "at lave store forandringer med små skridt". Han beskriver refaktorering som en kodeændring, der ikke påvirker driften, men han understreger, at det skal ske i små skridt.

Bogen slår også til lyd for, at refaktorering ikke påvirker kodens funktion og påpeger, at det ikke har nogen effekt på at bestå testene på noget tidspunkt. Den beskriver trin for trin, hvordan man sikkert udfører refaktorering. Jeg kunne godt lide hans bog, fordi den beskriver enkle tricks, der kan bruges i det daglige arbejde.

Hvorfor har vi brug for refaktorering?

 Oftest har du brug for det, når du vil indføre en ny funktion, og koden i sin nuværende version ikke tillader det, eller det ville være sværere uden ændringer i koden. Det er også nyttigt i tilfælde, hvor det ikke er rentabelt tidsmæssigt at tilføje flere funktioner, dvs. at det ville være hurtigere at omskrive koden fra bunden. Jeg tror, at man nogle gange glemmer, at refaktorering kan gøre koden renere og mere læsbar. Martin skriver i sin bog, hvordan han udfører refaktorering, når han føler ubehagelige lugte i koden, og, som han udtrykker det, "Det giver altid plads til det bedre". Og her overraskede han mig ved at se refaktorering som et element i det daglige kodearbejde. For mig er koderne ofte uforståelige, og det er lidt af en oplevelse at læse den, da koden ofte er uintuitiv.

Det, der kendetegner et veldesignet program, er dets ModularitetTakket være det er det nok kun at kende en lille del af koden for at indføre de fleste ændringer. Modularitet gør det også lettere for nye folk at komme ind og begynde at arbejde mere effektivt. For at opnå denne modularitet skal relaterede programelementer grupperes sammen, og forbindelserne skal være forståelige og lette at finde. Der findes ikke en enkelt tommelfingerregel for, hvordan det kan gøres. Efterhånden som du ved og forstår mere og mere af, hvordan koden skal fungere, kan du gruppere elementerne, men nogle gange er du også nødt til at teste og kontrollere.

En af reglerne for refaktorering i YAGNIDet er et akronym for 'You Aren't Gonna Need It' og stammer fra eXtreme programmering (XP) bruges hovedsageligt i Agil softwareudvikling hold. Lang historie kort, YAGNI siger, at kun aktuelle ting skal gøres. Det betyder dybest set, at selv om der kan blive brug for noget i fremtiden, skal det ikke gøres lige nu. Men vi kan heller ikke forhindre yderligere udvidelser, og det er her, modularitet bliver vigtig.

Når man taler om refaktoreringskal et af de vigtigste elementer, nemlig test, nævnes. I refaktoreringer vi nødt til at vide, at koden stadig virker, fordi refaktorering ændrer ikke, hvordan den fungerer, men dens struktur, så alle tests skal bestås. Det er bedst at køre tests for den del af koden, vi arbejder på, efter hver lille transformation. Det giver os en bekræftelse på, at alt fungerer, som det skal, og det forkorter tiden for hele operationen. Det er det, Martin taler om i sin bog - at køre tests så ofte som muligt for ikke at gå et skridt tilbage og spilde tid på at lede efter en transformation, der ødelagde noget.

Refaktorering af kode Uden test er det besværligt, og der er stor risiko for, at noget går galt. Hvis det er muligt, ville det være bedst at tilføje i det mindste nogle grundlæggende tests, der giver os lidt sikkerhed for, at koden fungerer.

De transformationer, der er anført nedenfor, er kun eksempler, men de er virkelig nyttige i den daglige programmering:

Eksempel

Dette er en artikel om refaktorering og der er brug for et eksempel. Jeg vil gerne vise et simpelt refaktoreringseksempel nedenfor med brug af Overstyring af den indlejrede erklæring og Udskiftning af den betingede instruktionspolymorfi. Lad os sige, at vi har en programfunktion, der returnerer en hash med oplysninger om, hvordan man vander planter i det virkelige liv. Sådanne oplysninger ville sandsynligvis være i modellen, men i dette eksempel har vi dem i funktionen.

def vanding_info(plante)
     resultat = {}
     hvis plant.is_a? Suculent || plant.is_a? Kaktus
         result = { water_amount: "En lille smule" , how_to: "Fra bunden", watering_duration: "2 uger" }
     elsif plant.is_a? Alocasia || plant.is_a? Maranta
         result = { water_amount: "Stor mængde", how_to: "Som du foretrækker", watering_duration: "5 dage" }
     elsif plant.is_a? Peperomia
         result = { water_amount: "Bestemt mængde",
             how_to: "Fra bunden! De kan ikke lide vand på bladene",
             watering_duration: "1 uge" }
     ellers
         result = { water_amount: "Dicent mængde",
             how_to: "Som du foretrækker",
             watering_duration: "1 uge"
             }
     slut
     returner resultat
 slut

Ideen er at ændre, hvis man skal vende tilbage:

hvis plant.isa? Suculent || plant.isa? Kaktus

     resultat = { vandmængde: "En lille smule" , howto: "Fra bunden",

Til

return { water_amount: "En lille smule" , how_to: "Fra bunden",watering_duration: "2 uger" } if plant.is_a? Suculent || plant.is_a? Kaktus

return { vandmængde: "En lille smule" , hvordantil: "Fra bunden", vandingvarighed: "2 uger" } if plant.isa? Sukkulent || plant.is_a? Kaktus

Og så videre med alt, indtil vi kommer til en funktion, der ser sådan ud:

def vanding_info(plante)

return result = { wateramount: "En lille smule" , howto: "Fra bunden", vandingsvarighed: "2 uger" } if plant.isa? Suculent || plant.is_a? Kaktus

return result = { wateramount: "Stor mængde", howto: "Som du foretrækker", vandingsvarighed: "5 dage" } if plant.isa? Alocasia || plant.is_a? Maranta

return result = { water_amount: "Dicent mængde",

          howto: "Fra bunden! De kan ikke lide vand på bladene",
          wateringduration: "1 week" } if plant.is_a? Peperomia

return result = { water_amount: "Dicent mængde",

          how_to: "Som du foretrækker",

          vanding_varighed: "1 uge"

          }

slutning

 Til allersidst havde vi allerede et returresultat. Og det er en god vane at gøre det trin for trin og teste hver ændring. Du kunne erstatte denne if-blok med en switch case, og det ville straks se bedre ud, og du ville ikke behøve at tjekke alle if'er hver gang. Det ville se sådan ud:

def vanding_info(plante)

swich plant.class.to_string

case Sukkulente, Kaktus

     { vandmængde: "En lille smule" , howto: "Fra bunden", vanding_varighed: "2 uger" }

tilfælde Alocasia, Maranta

     { vandmængde: "Stor mængde", howto: "Som du foretrækker", watering_duration: "5 dage" }

tilfælde Peperomia

     { water_amount: "Dicent mængde",

          how_to: "Fra bunden! De kan ikke lide vand på bladene",

          vanding_varighed: "1 uge" }

ellers

     { water_amount: "Dicent mængde",

            how_to: "Som du foretrækker",

       vandingsvarighed: "1 uge" }

slutning

slut

Og så kan du anvende Udskiftning af den betingede instruktionspolymorfisme. Det er for at skabe en klasse med en funktion, der returnerer den korrekte værdi og skifter dem på deres rette plads.

klasse Sukkulente

...

def vanding_info()

     return { vandmængde: "En lille smule" , howto: "Fra bunden", watering_duration: "2 uger" }

slut

slut

klasse Kaktus

...

def vanding_info()

     return { vandmængde: "En lille smule" , howto: "Fra bunden", watering_duration: "2 uger" }

slut

slut

klasse Alocasia

...

def vanding_info

     return { vandmængde: "Stor mængde", howto: "Som du foretrækker", watering_duration: "5 dage" }

slut

slut

klasse Maranta

...

def vanding_info

     return { vandmængde: "Stor mængde", howto: "Som du foretrækker", watering_duration: "5 dage" }

slut

slut

klasse Peperomia

...

def vanding_info

     return { water_amount: "Dicent beløb",

      how_to: "Fra bunden! De kan ikke lide vand på bladene",

      vanding_varighed: "1 uge" }

slutning

slut

klasse Plante

...

def vanding_info

     return { water_amount: "Dicent beløb",

              how_to: "Som du foretrækker",

              vandingsvarighed: "1 uge" }

slutning

slut

Og i hovedfunktionen watering_infofunction vil koden se sådan ud:

def vanding_info(plante)

    plante.map(&:vanding_info)

slut

Denne funktion kan selvfølgelig fjernes og erstattes med dens indhold. Med dette eksempel ville jeg præsentere den generelle mønster for refaktorering.

Sammenfatning

Refaktorisering er et stort emne. Jeg håber, at denne artikel var et incitament til at læse mere. Disse færdigheder i refaktorering hjælpe dig med at fange dine fejl og forbedre din workshop med ren kode. Jeg anbefaler at læse Martins bog (Improving the Design of Existing Code), som er et ret grundlæggende og nyttigt sæt regler for refaktorering. Forfatteren viser forskellige transformationer trin for trin med en fuld forklaring og motivation og tip til, hvordan man undgår fejl i refaktorering. På grund af sin alsidighed er det en dejlig bog til frontend og backend-udviklere.

Bliv junior Ruby-udvikler

Læs mere

GraphQL Ruby. Hvad med performance?

Skinner og andre transportmidler

Rails-udvikling med TMUX, Vim, Fzf + Ripgrep

da_DKDanish