Du har sikkert sett det. Kode som gaper over for mye, som bruker tilstand og egenskaper om hverandre — kode som ikke gjør annet enn å forvirre.Slike kodesnutter har mange navn. Kall de gjerne “gudkomponenten”, “det monolittiske gudobjektet”, eller ganske enkelt “Monolittkomponenten”. I sin ypperste form oppfører koden seg som en singleton, selv om den ikke er det.

En monolittisk klasse eller funksjon inneholder flerfoldige komponenter som ikke er logisk koblet sammen, eller som er koblet sammen på en meningsløs måte.

Monolittkoden er altså en komponent, klasse eller funksjon som i prinsipp vet alt, som delegerer og viser nye ting basert på mer eller mindre forståelige logiske grener.

Merk, jeg lemper komponenter, klasser og funksjoner sammen i denne artikkelen, men det er selvfølgelig distinkte forskjeller på klasser og funksjoner — men disse hensyn er ikke spesielt relevant for denne diskusjonen.

Her er en ting du kanskje ikke visste om slike komponenter. De kan oppstå på alle nivåer i komponenthierarkiet ditt. Dette gjør dem farlige, for har du flere slike nøstet sammen så har du et ganske stort problem for hånden.

Monolittkode kan manifestere seg på mange måter. Den starter gjerne med en eller flere skjermhøyder med import-erklæringer.

<script src="https://gist.github.com/TechDuckCGI/c05d05837834277bbf3fbd94a99a26f0.js"></script>

Så fortsetter den gjerne med å bygge opp logiske strukturer som den har bruk for.

<script src="https://gist.github.com/TechDuckCGI/25980d269ffa12e0bbc33cf96326f0f2.js"></script>

Som deretter gjenbrukes i visningen.

<script src="https://gist.github.com/TechDuckCGI/2932830907e9f687767faa9678e84647.js"></script>

Hvis dette ser søkt ut, så skal jeg skuffe deg og si at dette er ganske likt kode jeg har sett ute i det fri.

Hvordan identifiserer du monolitter?

Her er noen ting du kan se etter:

Antall imports

Antall avhengigheter og grad av kobling til funksjonen du jobber med

Antall parametre du jobber med (både de som sendes til funksjonen, og de instansvariablene du oppretter selv)

Bygger du logiske strukturer i funksjonen som påvirker resultatet?

Hva gjør du med dem?

En funksjon skal bare importere ting den absolutt må ha for å gjøre jobben den skal gjøre.

Hvis funksjonen gjør mer enn en ting, så gjør den for mye. Skrell alle funksjoner ned til benet og lag heller flere av dem.

Fjern all forgrenet logikk. Dersom funksjonen ikke skal gjøre noe basert på logikk i inndataparametre, så stopp den tidlig.

Refaktor-vurderinger

Første iterasjon kan se slik ut:

<script src="https://gist.github.com/TechDuckCGI/17b92cfd7ca3d85722f96a09f59c00be.js"></script>

Dette er mer forståelig, men det er ikke ideelt, for den som leser dette må ha en forståelse av hva isLoggedIn betyr, og hvor denne kommer fra. Det er også et fakta at med en gang du introduserer boolsk logikk i render-metoden, så øker du den syklomatiske kompleksiteten.

Det betyr at render ideelt sett bør se slik ut:

<script src="https://gist.github.com/TechDuckCGI/c47e5e71488eaef6e93d6bff4d923b4d.js"></script>

Hvor ble isLoggedIn av?

Saken er at dette komponentet sannsynligvis ikke bør ha kunnskap om brukeren er logget inn eller ei. Vi vil fortsatt sjekke om brukeren er logget inn, men det bør ligge et annet sted. Det er nesten helt sikkert at applikasjonen skal gjøre noe annet når brukeren ikke er logget inn, og det behøver ikke dette komponentet ha noe forhold til. Det at vi skal presentere to ulike velkommen-meldinger betyr at ikke nødvendige at Welcome-komponentet må være ansvarlig for både innlogget og anonym bruker.

Det kan vise seg at dette fører til flere refaktoreringer lenger opp i kjeden, men hensikten er å gjøre hele kodekjeden lesbar og forståelig, og da er dette noe som er verdt å gjøre.

Et mer komplisert eksempel

La oss ta et eksempel fra “ute i det fri” — altså en kodesnutt jeg fant ved et tilfeldig søk på Github.

<script src="https://gist.github.com/TechDuckCGI/2bd8c77427b2c7f6cd85ce242c95462c.js"></script>

Jeg skal ikke forsøke å refaktorere hele denne koden, men jeg skal påpeke hva som kunne blitt endret for å gjøre den mer leselig.

Det første jeg gjør er å skrive om alle metodeklasser ({this.renderHeader…} etc.) til separate komponenter.

<script src="https://gist.github.com/TechDuckCGI/f833cc7fd6f077150b31d8e158395e7c.js"></script>

Merk at Table er en ny komponent som returnerer <table className=”table”>{props.children}</table> slik at vi slipper å forholde oss klassenavnet nå vi leser dette komponentet med friske øyne. Alt vi nå trenger å tenke på er columns, sort-funksjonen og dataView.

Men dette er ganske dårlige navn. Variabelnavn er viktig, så la oss endre komponentet ytterligere.

<script src="https://gist.github.com/TechDuckCGI/6947927a6603dee3cf830b263b7e7798.js"></script>

I TableHead trenger vi bare en liste med navn, og en måte å sortere dem. I TableGroups (som vi endrer til det mer idiomatisk korrekte TableRows) trenger vi strengt tatt bare listen med data.

Neste forbedring er å gå inn i TableHead og kode opp en mer forståelig kobling mot sorteringsfunksjonen, og dernest en mer leselig kode i TableRows-komponentet. Dette lar jeg imidlertid være en hjemmeoppgave for leseren.

Add new comment

Comment editor

  • No HTML tags allowed.
  • Lines and paragraphs break automatically.
Blog moderation guidelines and term of use