window.pipedriveLeadboosterConfig = { base: 'leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', versjon: 2, } ;(function () { var w = vindu if (w.LeadBooster) { console.warn('LeadBooster finnes 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åelig for noen at refaktorisering er faktisk et område innen programmering, og det er også en svært viktig del av programmererens arbeid. Koden er i stadig utvikling, og den vil bli endret så lenge det er mulig å legge til ny funksjonalitet. Det kan imidlertid hende at den tar en form som ikke lenger gjør det mulig å legge til ny funksjonalitet på en effektiv måte, og da er det enklere å skrive om hele programmet.

Hva er refaktorisering?

Vanligvis får du til svar at det dreier seg om å endre strukturen i koden ved å bruke en rekke refaktoriseringstransformasjoner uten å påvirke kodens observerbare atferd. Dette er sant. Nylig kom jeg også over en definisjon av Martin Fowler i sin bok "Forbedring av utformingen av eksisterende kodeverk" hvor han beskriver refaktorisering som "å gjøre store endringer med små skritt". Han beskriver refaktorisering som en kodeendring som ikke påvirker driften, men han understreker at det må gjøres i små skritt.

Boken tar også til orde for at refaktorisering ikke påvirker driften av koden, og påpeker at det ikke har noen innvirkning på bestått test på noe tidspunkt. Den beskriver trinn for trinn hvordan du trygt kan utføre refaktorisering. Jeg likte boken fordi den beskriver enkle triks som kan brukes i det daglige arbeidet.

Hvorfor trenger vi refaktorisering?

 Oftest trenger du det når du ønsker å introdusere en ny funksjonalitet og koden i sin nåværende versjon ikke tillater det, eller det ville være vanskeligere uten endringer i koden. Det er også nyttig i tilfeller der det er ulønnsomt å legge til flere funksjoner, det vil si at det ville være raskere å skrive om koden fra bunnen av. Jeg tror det noen ganger glemmes at refaktorisering kan gjøre koden renere og mer lesbar. Martin skriver i boken sin hvordan han utfører refaktorering når han kjenner ubehagelig lukt i koden, og, som han uttrykker det, "det gir alltid rom for det bedre". Og han overrasket meg her ved å se refaktorering som et element i det daglige kodearbeidet. For meg er kodene ofte uforståelige, det er litt av en opplevelse å lese den fordi koden ofte er uintuitiv.

Det som kjennetegner et godt utformet program, er dets modularitetDet er derfor nok å kunne bare en liten del av koden for å kunne gjøre de fleste endringer. Modularitet gjør det også lettere for nye personer å komme inn og begynne å jobbe mer effektivt. For å oppnå denne modulariteten må beslektede programelementer grupperes sammen, og forbindelsene må være forståelige og lette å finne. Det finnes ingen tommelfingerregel for hvordan dette kan gjøres. Etter hvert som du vet og forstår mer og mer av hvordan koden er ment å fungere, kan du gruppere elementene bedre, men noen ganger må du også teste og sjekke.

En av reglene for refaktorering i YAGNIDet er et akronym for "You Aren't Gonna Need It" og stammer fra eXtreme-programmering (XP) hovedsakelig brukt i Smidig programvareutvikling lag. For å gjøre en lang historie kort, YAGNI sier at bare oppdaterte ting skal gjøres. Det betyr at selv om noe kan bli nødvendig i fremtiden, bør det ikke gjøres akkurat nå. Men vi kan heller ikke knuse ytterligere utvidelser, og det er her modularitet blir viktig.

Når man snakker om refaktoriseringmå et av de viktigste elementene, nemlig testene, nevnes. I refaktoriseringmå vi vite at koden fortsatt fungerer, fordi refaktorisering endrer ikke hvordan den fungerer, men strukturen, så alle tester må bestås. Det beste er å kjøre tester for den delen av koden vi jobber med, etter hver lille endring. Det gir oss en bekreftelse på at alt fungerer som det skal, og det forkorter tiden for hele operasjonen. Det er dette Martin snakker om i boken sin - kjør tester så ofte som mulig for å slippe å gå tilbake og kaste bort tid på å lete etter en transformasjon som ødela noe.

Refaktorisering av kode Uten testing er det vanskelig, og det er stor sjanse for at noe går galt. Hvis det er mulig, er det best å legge til i det minste noen grunnleggende tester som gir oss en liten forsikring om at koden fungerer.

Transformasjonene nedenfor er bare eksempler, men de er svært nyttige i den daglige programmeringen:

Eksempel

Dette er en artikkel om refaktorisering og det er behov for et eksempel. Jeg vil vise et enkelt refaktoriseringseksempel nedenfor med bruk av Overstyring av den nestede setningen og Erstatning av den betingede instruksjonspolymorfismen. La oss si at vi har en programfunksjon som returnerer en hash med informasjon om hvordan man vanner planter i virkeligheten. Slik informasjon ville sannsynligvis ligget i modellen, men i dette eksempelet har vi den i funksjonen.

def vanning_info(anlegg)
     resultat = {}
     if plant.is_a? Suculent || plant.is_a? Kaktus
         resultat = { vann_mengde: "Litt " , how_to: "Fra bunnen", vanning_varighet: "2 uker" }
     elsif plant.is_a? Alocasia || plant.is_a? Maranta
         resultat = { vann_mengde: "Stor mengde", how_to: "Som du foretrekker", vanning_varighet: "5 dager" }
     elsif plant.is_a? Peperomia
         result = { water_amount: "Dicent mengde",
             how_to: "Fra bunnen! de liker ikke vann på bladene",
             vanning_varighet: "1 uke" }
     ellers
         resultat = { vann_mengde: "Dicent mengde",
             how_to: "Som du foretrekker",
             vanning_varighet: "1 uke"
             }
     end
     returner resultat
 end

Tanken er å endre om å vende tilbake:

if plant.isa? Suculent || plant.isa? Kaktus

     resultat = { vannmengde: "Litt " , howto: "Fra bunnen",

Til

return { vann_mengde: "Litt " , how_to: "Fra bunnen",vanning_varighet: "2 uker" } if plant.is_a? Suculent || plant.is_a? Cactus

returnere { vannmengde: "Litt" , hvordantil: "Fra bunnen", vanningvarighet: "2 uker" } if plant.isa? Suculent || plant.is_a? Kaktus

Og så videre med alt, helt til vi kommer til en funksjon som ser slik ut:

def vanning_info(anlegg)

return result = { vannmengde: "Litt " , howto: "Fra bunnen", vanningvarighet: "2 uker" } if plant.isa? Suculent || plant.is_a? Cactus

return result = { vannmengde: "Stor mengde", howto: "Som du foretrekker", vanningvarighet: "5 dager" } if plant.isa? Alocasia || plant.is_a? Maranta

return result = { water_amount: "Dicent mengde",

          howto: "Fra bunnen! de liker ikke vann på bladene",
          vanningvarighet: "1 uke" } if plant.is_a? Peperomia

return result = { water_amount: "Dicent amount",

          how_to: "Som du foretrekker",

          vanning_varighet: "1 uke"

          }

slutt

 Helt til slutt hadde vi allerede et returresultat. Og en god vane er å gjøre dette steg for steg og teste hver endring. Du kan erstatte denne if-blokken med en switch case, og det vil se bedre ut umiddelbart, og du trenger ikke å sjekke alle ifs hver gang. Det ville se slik ut:

def vanning_info(anlegg)

swich plant.class.to_string

case Suculent, Kaktus

     { vannmengde: "Litt " , howto: "Fra bunnen", vanning_varighet: "2 uker" }

case Alocasia, Maranta

     { vannmengde: "Stor mengde", howto: "Som du foretrekker", vanning_varighet: "5 dager" }

case Peperomia

     { water_amount: "Dicent amount",

          how_to: "Fra bunnen! De liker ikke vann på bladene",

          vanning_varighet: "1 uke" }

ellers

     { water_amount: "Dicent amount",

            how_to: "Som du foretrekker",

       vanning_varighet: "1 uke" }

slutt

end

Og så kan du bruke Erstatter den betingede instruksjonspolymorfismen. Dette er for å lage en klasse med en funksjon som returnerer riktig verdi og bytter dem på riktig plass.

klasse Suculent

...

def vanning_info()

     return { wateramount: "Litt " , howto: "Fra bunnen", vanning_varighet: "2 uker" }

end

end

klasse Kaktus

...

def vanning_info()

     return { wateramount: "Litt " , howto: "Fra bunnen", vanning_varighet: "2 uker" }

end

end

klasse Alocasia

...

def vanning_info

     return { wateramount: "Stor mengde", howto: "Som du foretrekker", vanning_varighet: "5 dager" }

end

end

klasse Maranta

...

def vanning_info

     return { wateramount: "Stor mengde", howto: "Som du foretrekker", vanning_varighet: "5 dager" }

end

end

klasse Peperomia

...

def vanning_info

     return { water_amount: "Dicent amount",

      how_to: "Fra bunnen! De liker ikke vann på bladene",

      vanning_varighet: "1 uke" }

slutt

end

klassen Plant

...

def vanning_info

     return { water_amount: "Dicent amount",

              how_to: "Som du foretrekker",

              vanning_varighet: "1 uke" }

slutt

end

Og i hovedfunksjonen watering_infofunction vil koden se slik ut:

def vanning_info(anlegg)

    plant.map(&:vanning_info)

end

Denne funksjonen kan selvfølgelig fjernes og erstattes med innholdet. Med dette eksemplet ønsket jeg å presentere den generelle refaktoriseringsmønster.

Sammendrag

Refaktorisering er et stort tema. Jeg håper denne artikkelen var et insentiv til å lese mer. Disse ferdigheter i refaktorisering hjelpe deg med å fange opp feil og forbedre din "clean code workshop". Jeg anbefaler å lese Martins bok (Improving the Design of Existing Code), som er et ganske grunnleggende og nyttig sett med regler for refaktorisering. Forfatteren viser ulike transformasjoner trinn for trinn med en full forklaring og motivasjon og tips om hvordan du kan unngå feil i refaktorisering. På grunn av sin allsidighet er det en herlig bok for frontend- og backend-utviklere.

Bli junior Ruby-utvikler

Les mer

GraphQL Ruby. Hva med ytelse?

Skinner og andre transportmidler

Rails-utvikling med TMUX, Vim, Fzf + Ripgrep

nb_NONorwegian