Mjukvaruutvecklare är duktiga på att känna igen mönster. Kanske är det en inneboende förmåga som lockar oss till detta yrke. Eller kanske är det processen att skriva programvara som utvecklar denna förmåga. Hur som helst är ”upprepa inte dig själv” (DRY) en naturlig tillämpning av denna förmåga.
Hursomhelst är upprepning i sig själv inte den fiende som denna princip gör den till.
- Don’t Repeat Yourself
- Ibland upprepar du dig själv
- Frågor att ställa
- Är det här en enskild del av kunskapen som har duplicerats, eller är det bara infrastruktur som råkar se likadan ut?
- Hur många gånger har den här saken upprepats?
- Kommer det att minska dupliceringen nu att göra det svårare att anpassa enskilda fall i framtiden?
- Om jag minskar denna duplicering, vad är då förhållandet mellan abstraktionens storlek och antalet parametrar som den kommer att ta?
- Slutsats
Don’t Repeat Yourself
Så intuitivt som ”upprepa inte dig själv” kan vara, så sammanfattar The Pragmatic Programmer det på följande sätt:
Varje del av kunskapen måste ha en enda, otvetydig, auktoritativ representation inom ett system.
Det är inte svårt att föreställa sig fördelarna med att minska eller eliminera upprepning.
- Mindre upprepning innebär mindre kod att underhålla. Och om den bästa koden är ingen kod alls, låter detta som en bra sak.
- En enda sanningskälla eliminerar möjligheten att saker och ting blir osynkroniserade. Har någon affärsregel ändrats? Uppdatera den på ett ställe, och det är klart.
- Koden kan återanvändas. Har du en process som delas av tre saker och du ska lägga till en fjärde? Det mesta av arbetet har redan gjorts.
Ibland upprepar du dig själv
Om du blir för ivrig när det gäller att minska uppenbart dubbelarbete kan det skapa fler problem än det löser. Jag säger ”skenbart dubbelarbete” eftersom saker som ser likadana ut ibland egentligen inte är besläktade. Till exempel kan två datastrukturer med identiska egenskaper och typer vara samma strukturellt men inte semantiskt.
En vanlig strategi för att minska dubblerad kod är att faktorisera ut de gemensamma delarna och gömma dem bakom en abstraktion. Men en oönskad bieffekt av detta är att det kopplar ihop allt som använder abstraktionen. Varje förändring i abstraktionen påverkar alla dess konsumenter. Och på samma sätt kan abstraktionen behöva böjas för att passa kraven hos en enda konsument.
Denna ökning av kopplingen kommer också med en minskning av flexibiliteten. Säg att du har en process som används på tre ställen. Den är nästan likadan på alla tre ställen, med bara några få viktiga skillnader. Så du implementerar processen som en enda modul som tar några parametrar för att täcka skillnaderna.
Det är nu omöjligt att justera processen för bara ett enda av dessa användningsfall: varje ändring av ett påverkar alla tre. Visst kan man lägga till fler parametrar (eller specialfall!) när användningsfallen skiljer sig åt. Men det blir snabbt omöjligt att skilja de viktiga delarna av processen från den infrastruktur som skiljer användningsfallen åt.
Frågor att ställa
När jag refaktoriserar befintlig kod eller skriver ny kod som potentiellt kan dupliceras frågar jag mig själv:
Är det här en enskild del av kunskapen som har duplicerats, eller är det bara infrastruktur som råkar se likadan ut?
Då har du rottat dig fram i CSS och hittat en klass som råkar ha de stilar du vill ha. Det är förmodligen inte ett tillräckligt bra skäl för att undvika att definiera ytterligare en klass.
Hur många gånger har den här saken upprepats?
Inte förrän en verkligt överflödig sak dyker upp minst tre gånger skulle jag vara mycket skeptisk till alla upprepningsminskningar som ökar komplexiteten.
Kommer det att minska dupliceringen nu att göra det svårare att anpassa enskilda fall i framtiden?
Det finns något tillfredsställande med att refaktorisera en massa kopiera-och-klistra-kod till något mer strömlinjeformat och återanvändbart. Men att låsa koden så hårt att varje ändring skulle introducera specialfall är ingen bra kompromiss.
Om jag minskar denna duplicering, vad är då förhållandet mellan abstraktionens storlek och antalet parametrar som den kommer att ta?
Bibliotek och ramverk är bra eftersom de tillhandahåller återanvändbar kod med relativt få parametrar för anpassning. Men tänk dig en applikationsspecifik funktion för att presentera en dialogruta som har vuxit och nu tar emot 20 parametrar. Den fördel som fanns för att minska upprepningar när den hade 2 parametrar finns inte längre.
Slutsats
Som med många principer för mjukvaruutveckling är ”upprepa inte dig själv” mer en riktlinje än ett mantra.