Antimønstre du bør unngå i koden din

Hver utvikler ønsker å skrive strukturert, enkelt planlagt og pent kommentert kode. Det er til og med et utall designmønstre som gir oss klare regler å følge, og et rammeverk å huske på.

Men vi kan fremdeles finne antimønstre i programvare som ble skrevet en gang, eller som ble skrevet for raskt.

Et ufarlig grunnleggende hack for å løse et problem raskt kan gi presedens i kodebasen din. Den kan kopieres over flere steder og bli til et antimønster du må adressere.

Så hva er et motmønster?

I programvare er antimønster et begrep som beskriver hvordan IKKE løser tilbakevendende problemer i koden din. Antimønstre regnes som dårlig programvaredesign, og er vanligvis ineffektive eller uklare rettelser.  

De legger generelt også til "teknisk gjeld" - som er kode du må komme tilbake og fikse ordentlig senere.

De seks antimønstrene jeg vil diskutere i denne artikkelen er Spaghetti Code , Golden Hammer , Boat Anchor , Dead Code , Proliferation of Code og God Object .

Spaghetti-kode

Spaghetti Code er det mest kjente antimønsteret. Det er kode med liten til null struktur.

Ingenting er modulert. Det er tilfeldige filer strødd i tilfeldige kataloger. Hele flyten er vanskelig å følge, og er helt sammenflettet (som spaghetti).

Normalt er dette et problem der noen ikke har tenkt nøye gjennom flyt av programmet sitt på forhånd og nettopp begynt å kode.

Hva gjør den?! Jeg kan ikke følge dette

image.png

Dette er ikke bare et vedlikeholds-mareritt, men det gjør det nesten umulig å legge til ny funksjonalitet.

Du vil hele tiden bryte ting, ikke forstå omfanget av endringene dine, eller gi noen nøyaktige estimater for arbeidet ditt, da det er umulig å forutse de utallige problemene som dukker opp når du gjør slik arkeologi / gjetning.

Du kan lese mer her om Spaghetti Code antimønster.

Golden Hammer

"Jeg antar at det er fristende, hvis det eneste verktøyet du har er en hammer, å behandle alt som om det var en spiker." Abraham Maslow

Tenk deg et scenario med meg: Dev-teamet ditt er veldig, veldig kompetent i den splitter nye Hammer-arkitekturen. Det har fungert fantastisk for alle dine tidligere problemer. Du er verdens ledende Hammer-arkitekturteam.

Men nå, på en eller annen måte, ender alt opp med å bruke denne arkitekturen. En flat skrue? Hammer. Phillips hodeskrue? Hammer. Trenger du en skiftenøkkel? Nei det gjør du ikke, hamre det.

Du begynner å bruke en arkitektonisk tilnærming som ikke helt passer det du trenger, men får jobben gjort. Du er over avhengig av ett mønster og trenger å lære det beste verktøyet for den beste jobben.

Hele programmet kan ende opp med å ta en seriøs forestillingshit fordi du prøver å ramme en firkant i en sirkelform. Du vet at det tar dobbelt så lang tid å kode opp, og å utføre et program ved hjelp av hammerarkitekturen for dette problemet, men det er lettere og det er det du er komfortabel med.

Det er heller ikke veldig forutsigbart. Ulike språk har vanlige løsninger på problemene de møter, og deres egne standarder. Du kan ikke bruke hver eneste regel som fungerte bra for deg på ett språk til det neste, uten problemer.

Ikke forsøm konsekvent læring i karrieren din. Velg riktig språk for problemet ditt. Tenk på arkitekturen, og skyv ut komfortsonen din. Undersøk og undersøk nye verktøy og nye måter å nærme seg problemene du står overfor.

Du kan lese mer her om Golden Hammer antimønster.

Båtanker

The Boat Anchor anti-mønster er der programmerere forlate kode i kodebasen fordi de trenger det senere.

De kodet noe litt utenfor spesifikasjonen, og det er ikke nødvendig ennå, men de er sikre på at de vil gjøre det neste måned. Så de vil ikke slette det. Send den til produksjon, og senere når de trenger det, kan de raskt få det til å fungere.

Men dette forårsaker vedlikeholdsmareritt i kodebasen som inneholder all den foreldede koden. Det store problemet er at kollegene deres vil ha vanskelig for å finne ut hvilken kode som er foreldet og ikke endrer flyten, mot koden som gjør det.

Tenk deg at du er i en hot fix, og prøver desperat å finne ut hva som er ansvarlig for å sende kundenes kortinformasjon til API for å ta ut penger fra banken sin. Du kan kaste bort tid på å lese og feilsøke foreldet kode, uten å innse at du ikke engang er på rett sted i kodebasen.

Det siste problemet er at foreldet kode gjør byggetiden lengre, og du kan forveksle fungerende og foreldet kode. Du kan til og med begynne å "slå den på" i produksjonen.

Nå kan du sannsynligvis se hvorfor det kalles båtanker mot mønster - det er tungt å bære (legger til teknisk gjeld), men gjør ikke noe (bokstavelig talt, koden tjener ingen hensikt, det fungerer ikke).

Du kan lese mer her om båt anker anti-mønster.

Død kode

Har du noen gang hatt å se på kode skrevet av noen som ikke jobber lenger hos deg? Det er en funksjon som ikke ser ut som den gjør noe. Men det kalles fra overalt! Du spør rundt og ingen andre er helt sikre på hva det gjør, men alle er for bekymret for å slette det.

Noen ganger kan du se hva den gjør, men konteksten mangler. Du er i stand til å lese og forstå flyten, men hvorfor? Det ser ikke ut til at vi trenger å nå det endepunktet lenger. Svaret er alltid det samme svaret for hver bruker.

Dette blir ofte beskrevet som det døde kode -antimønsteret. Når du ikke kan se hva som er "faktisk" kode som er nødvendig for flyten og vellykket gjennomføring av programmet ditt, mot det som bare var nødvendig for 3 år siden, og ikke nå.

Dette spesielle antimønsteret er mer vanlig i bevis på konsept eller forskningskode som endte i produksjon.

En gang på et teknisk møte møtte jeg en fyr som hadde akkurat dette problemet. Han hadde tonnevis med død kode, som han visste var død, og mye han mistenkte var død. Men han kunne ikke få tillatelse fra ledelsen til å fjerne all død kode.

Han refererte til sin tilnærming som Monkey testing, hvor han begynte å kommentere og slå av ting for å se hva som sprengte i produksjonen. Kanskje litt for risikabelt!

If you don't fancy Monkey testing your production app, try to frame technical debt to management as "technical risk" to better explain why you think it's so important to tidy up.

Or even write down everything your particular module/section does you want to re-write, and take an iterative approach to remove piece by piece the dead code. Checking every time you haven't broken anything.

You don't have to drop a huge rewrite with thousands of changes. But you will either understand why it's so crucial and document why it's needed, or delete the dead code as you desired.

You can read more here about the Dead code anti-pattern.

Proliferation of Code

Objects or modules regularly communicate with others. If you have a clean, modularised codebase you often will need to call into other separate modules and call new functions.

The Proliferation of Code anti-pattern is when you have objects in your codebase that only exist to invoke another more important object. Its purpose is only as a middleman.

This adds an unnecessary level of abstraction (adds something that you have to remember) and serves no purpose, other than to confuse people who need to understand the flow and execution of your codebase.

A simple fix here is to just remove it. Move the responsibility of invoking the object you really want to the calling object.

You can read more here about the Proliferation of Code anti-pattern.

God Object

If everywhere in your codebase needs access to one object, it might be a God object.

God objects do too much. They are responsible for the user id, the transaction id, the customer's first and last name, the total sum of the transaction, the item/s the user is purchasing...you get the picture.

It is sometimes called the Swiss Army Knife anti-pattern because you only really need it to cut some twine, but it also can be a nail file, saw, pair of tweezers, scissors, bottle opener and a cork screw too.

In this instance you need to separate out and modularise your code better.

Programmers often compare this problem to asking for a banana, but receiving a gorilla holding a banana. You got what you asked for, but more than what you need.

The SOLID principles explicitly discuss this in object orientated languages, to help us model our software better (if you don't know what the SOLID principles are, you can read this article).

The S in the acronym stands for Single Responsibility - every class/module/function should have responsibility over one part of the system, not multiple.

You can see this problem over and over again, how about the below interface?

interface Animal { numOfLegs: string; weight: number; engine: string; model: string; sound: string; claws: boolean; wingspan: string; customerId: string; } 

Can you see by even just briefly scanning this interface that the responsibility of this is far too broad, and needs refactoring? Whatever implements this has the potential to be a God object.

How about this?

 interface Animal { numOfLegs: string; weight: number; sound: string; claws: boolean; } interface Car { engine: string; model: string; } interface Bird { wingspan: string; } interface Transaction { customerId: string; } 

Interface segregation will keep your code clear about where the responsibilities lie, and stop forcing classes that only need wingspan to also implement the engine, customerId and model  and so on.

Du kan lese mer her om Guds motstand mot mønster.

Konklusjon

I en hvilken som helst stor kodebase er det en konstant balanse mellom å håndtere teknisk gjeld, starte ny utvikling og administrere en kø med feil for produktet ditt.

Jeg håper denne artikkelen har gitt deg et øye for å få øye på når du kan gå ned i kaninhullet til et antimønster, og noen verktøy for å løse det rent.

Jeg deler skrivingen min på Twitter hvis du likte denne artikkelen, og vil se mer.