Er din kode rustet?

Når man udvikler på et omfattende produkt med 10 år på bagen, så må man nogle gange erkende, at der er dele af koden, som ærlig talt trænger til en opdatering. Især når man er i den lykkelige situation, at man tager nye udviklere ind, som skal lære kodebasen at kende, konfronteres man med steder, hvor koden ikke (længere) er så hensigtsmæssig.

Eksempelvis:

  • Der ligger kode med tilsvarende funktionalitet andre steder i kodebasen, så ved at konsolidere til ét fælles stykke kode kan man øge overskueligheden og forhåbentlig sørge for at det er den bedste version af det pågældende kode, der er i brug alle steder.
  • Inkonsistent terminologi i forhold til de udtryk, man benytter i brugergrænsefladen, eller andre steder i koden. Det gør det uhyggeligt svært at finde den klasse eller modul, der udfører en bestemt opgave.
  • Nogle moduler bliver måske slet ikke brugt længere, fordi dele af produktet er blevet udfaset, eller man har fået standardbiblioteker til at løse samme opgave. Så er det egentlig bare 'støj' for udviklerne.
  • Utilities eller datamodeller, som ikke benytter sig af nyere features, der kan hjælpe med at gøre koden mere overskuelig og robust, f.eks. generics i java. Det er godt nok irriterende at have metoder, der returner utypede collections, så man med 'tankens kraft' under udviklingen eller på runtime er nødt til at validere, om objekter nu også er instanser af de klasser, man tror, de er.

For 10 år siden skrev Joel Spolsky et blogindlæg om Netscapes eklatante fiasko med at skrive hele browseren om fra grunden, hvilket endte med at koste dem den dominerende position på browsermarkedet. Et af de citater, jeg husker fra blogindlægget, var 'Code does not rust.', altså: 'Kode ruster ikke.'

Hans pointe var, at gammel, snørklet kode nok ser sådan ud, fordi den inkorporerer en masse fejlrettelser og viden om undtagelsestilfælde, så man skal lade være med at skrive den forfra i en mere overskuelig og klar version. Jeg har egentlig svært ved at følge argumentet - hvem ville da skrive den nye og overskuelige version uden at forsøge at sætte sig ind i, hvad den gamle version gør?

At noget én gang er kodet er ikke nogen garanti for, at den virker som den skal. I det produkt, jeg arbejder med til daglig, er det faktisk især de nyere dele af koden, der er mest intensivt testet, fordi der i starten af produktets historie ikke var samme fokus på regressionstests mv. som vi har i dag. Man må også have modet til at erkende, hvor og hvornår forbedringer, oprydninger eller omskrivninger kan være nødvendige.

Jeg har hørt om steder, hvor udviklingsafdelingen får bonus for, hvor mange linjer kode, de skriver. Jeg håber, at det bare er en vandrehistorie. For nogle gange ville det faktisk være mere meningsfuldt at måle sig på, hvor meget kode, man får fjernet.

Kommentarer (12)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
Torben Mogensen Blogger

Selv om man med en vis ret kan sige, at når kode kører rigtigt nu, så vil den blive ved med at køre rigtigt i fremtiden, så holder det ikke helt:

  • Sprog og operativsystemer kan ændre sig, så gamle programmer ikke længere kører.

  • Når datamængderne vokser, kan man løbe ud over grænser, der er hårdt kodet i det gamle program.

Man kan selvfølgelig ruste sin kode imod rust (jeg antager, at det er det, din overskrift hentyder til), men det kan ofte koste en masse, og der vil nok alligevel være noget, man overser. Så det vigtigste råd er nok at skrive sin kode så tilpas enkel og overskuelig, at det er muligt at opdatere den, når rusten bliver for tyk.

Peter Makholm Blogger

Der er intet som barnets udbrud 'Men han har jo ikke noget tøj på'. På samme måde bør vi se velvilligt på vores nye udvikler når han udbryder 'Hvorfor fanden gør I sådan?'

For jo, gammel kode har ofte været udsat for mange smårettelser igennem tiden og lever sjældent op til den nuværende best practice for teknologibrug og kodestandard.

Men jeg tror let at op imod halvdelen af de gange jeg lige laver en lille ændrig, så er det mere som work-around for et problem et andet sted end en engentlig fejl i koden og dens antagelser. Dermed bliver koden uigennemsigtig uden intern grund og den bliver ikek rydet op når den oprindelige fejl forsvinder.

Hvis du ikke tør omskrivet et hvilket som helst stykke kode du ikke forstår ud fra konteksten, så skal man overveje om man har det korrekte niveau af test, kode-kommentare og specifikation.

(Ok, jo mere jeg får styr på vores specifikation, jo mere opdager jeg at folk er ligeglade)

I øvrigt, jeg er langt fra at turde omskrive et hvilket som helst stykke kode i min kodebase.

Nicholas Clarke

Da jeg i sidste århundrede startede med at arbejde med ASP, var noget af det første, jeg gjorde, når jeg skiftede projekt, at indentere og omskrive folks kode.

Jeg har masser af store assembler-projekter, som er 15-20 år gamle, og som stadig er "rustfrie". Dem har jeg så nok også kælet alt for meget for og omskrevet, til de var perfekte. At de så er ubrugelige på andet end Amiga'er, er så en anden sag. :)

De eneste projekter, jeg har, som er rustet, er projekter, hvor jeg endnu ikke er nået til det punkt, hvor der ikke er noget, jeg vil omskrive. Og det punkt når man nok aldrig, med mindre man har så mange penge, at man kan tage sig den tid, eller det er på hobbyplan.

Så mit postulat er: Dårlig kode ruster exponentielt mere end god kode. (Man fristes til at sige, at det meste produceret kode ruster kort tid efter, det er skrevet ;))

Nok selvpromovering for denne gang. Så her er afslutningvist en opfordring, jeg fandt for noget tid siden.

"Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live." -- Rick Osborne

Nikolaj Brinch Jørgensen

Meget kode er ikke specielt hensigtsmæssigt, og det som jeg ofte ser er, at der udvikles alt for meget kode til at løse konkrete problemer. Der implementeres ting som allerede er løst indtil flere gange i open source verdenen. Det implementeres bare vældigt meget dårligere.

Det at modulopbygge sine programmer (ved f.eks. at benytte sig af OSGi), er en uhyre god praksis, som letter overskueligheden. Alt for ofte ser jeg de her monolitiske klodser af programmer som tager op mod 30 min for en velbestykket CI server at tygge sig igennem (og vi tale Java kode!!!).

Så derfor, skal man betale de dygtige udviklere der kan sanere programmer for dårlig og overflødig kode, samtidig med at de rent faktisk tilføjer robust funktionalitet.

God kode kommer med alderen, hvor man med sin erfaring ved hvad der er gode enkle løsninger på problemer, og samtidigt magter at afkoble de eneklte dele af løsningen på en hensigtsmæssig måde. Hermed mener jeg f.eks. at kunne sondre hvornår den funktionalitet man er ved at implementere ikke ligger inden for den klasse man implementerer den i's ansvar. Det er ofte nogle af problemerne.

Derudover er unit tests et must alle henseender. Vi startede med unit tests i Java omkring 2000, så det er 10 år siden. Hvis man vil skrive noget gammel kode om, må man starte med unit tests, der verificerer at man har fattet hvad koden gør. Hvis koden er uoverskuelig og det er uforståeligt hvad den gør, repræsentere den et "black hole" i systemet, og er det er derfor væsenligt, at man netop ikke går udenom denne kode, for tænk hvis man kal rette i den senere.

Det med indarbejdelsen af en masse undtagelser og fejlrettelser, er ofte noget der sker, når folk får den dårlige vane at udvikle efter hvad de kan se i deres debugger. Så notere de variables indhold og laver undtagelser for netop denne situation, noget som kan have fatale konsekvenser for andre dele af programmet, men måske ikke ligger ligefor at se. Et godt råd, brug debuggeren så lidt som muligt, da den kan være en kilde til utroligt dårlig og meget kode.

Kode bliver ikke rustent, det er noget det enten er eller ikke er. Der er udviklere der skriver rusten kode.

Anders Poulsen

De bedste stykker kode jeg har været med til at skrive er opstået når vi i et projekt har været enige om at omskrive hinandens eller bare gammel kode HVER eneste gang vi støder på noget man synes kunne gøres bedre på en anden måde. Også selvom man egentlig var i gang med noget andet. Også selvom man man ikke kan påpege nogen fejl i den "gamle" kode. Også selvom man ikke har "spurgt om lov" først.
I øvrigt er det også langt mere tilfredsstillende at arbejde sådan, end når man ender med at bruge al sin tid på at få egen kode til at fungere sammen med andres uforståelige spaghetti.
Det sker selvfølgelig en gang imellem at man får fjernet noget funktionalitet som faktisk var tilsigtet, men min erfaring er at daglige standups (som f.eks. SCRUM bruger), medfører at man bliver gjort opmærksom på sin fejl inden den får konsekvenser.

Esben Nielsen

På baggrund af erfaringer i forskellige virksomheder, er min holdning, at man løbene skal skrive kode om. Der er meget kode, som er skrevet for hurtigt, med for lav kvalitet fra starten, og/eller er blevet ændret og tilføjet funktionalitet uden rigtigt at blive renoveret hen over tid.

På den anden side skal man ikke lave en "Netscape" og starte forfra med det hele (medmindre platformen/sproget tvinger én til det). Istedet bør man skrive tingene om i overskuelige dele: Et lille hold udviklere laver en gren, hvori de omskriver noget af koden. Efter nogle få måneder skal de være færdige - også med test! - og grenen flettes ind på stammen.

Argumenter mod at skrive det hele om:

-At skrive alt koden om vil indeholde meget stor risici, som en virksomhed kan have svært ved at acceptere.

-De udviklere, som skal arbejde videre med den gamle kode indtil den nye er færdig, kan nemt blive demotiveret.

-Det nye system vil være langt fra det gamle, så brugerne skal også lære forfra.

-Man får ikke løbende testet koden i marken.

Argumenter for at skrive det hele om:

  • Sprog/kompiler/hardware er ikke længere til rådighed.

  • På papiret er man hurtigere i mål (man glemmer dog den løbene test i dette argument)

  • Man kan få opbygger unit tests undervejs.

  • Den gamle kode er så ubrugelig, at intet kan genbruges (meget sjældent sandt: Hvordan har man så kunnet levere tidligere?)

Selv hvis man vil skifte sprog fra f.eks C++ til Java, skal man kraftigt overveje at bibeholde noget at det gamle C++ kode i et heterogent miljø, og omskrive moduler til Java, når man skal lave større ændringer i dem alligevel. Det skal selvfølgelig opvejes mod den mængde kode man skal skrive, teste og vedligeholde for at have et heterogent miljø.

Nikolaj Brinch Jørgensen

Jeg har lige et spørgsmål til den som downratede mit indlæg, hvad er det som gør det irrelevant for diskussionen?

Jeg er iøvrigt enig i flere af ovenstående, man skal skrive om isoleret til små dele af koden, og ikke lave big bang (aka. Agile/Iterativ udvikling).

Martin Bøgelund

Et af de citater, jeg husker fra blogindlægget, var “Code does not rust.”, altså: “Kode ruster ikke.”

Hans pointe var, at gammel, snørklet kode nok ser sådan ud, fordi den inkorporerer en masse fejlrettelser og viden om undtagelsestilfælde, så man skal lade være med at skrive den forfra i en mere overskuelig og klar version. Jeg har egentlig svært ved at følge argumentet - hvem ville da skrive den nye og overskuelige version uden at forsøge at sætte sig ind i, hvad den gamle version gør?

Jeg tror din (og andres) fortolkning af "gammel kode ruster ikke" er skæv ift hvad Joel Spolsky egentlig mente.

I et andet af Joel Spolskys indlæg, der rent faktisk blev skrevet [i]før[/i] det indlæg du linker til, skriver han:
http://www.joelonsoftware.com/articles/fog0000000069.html

These problems can be solved, one at a time, by carefully moving code, refactoring, changing interfaces. They can be done by one programmer working carefully and checking in his changes all at once, so that nobody else is disrupted. Even fairly major architectural changes can be done without [i]throwing away the code[/i].

Han anerkender altså nødvendigheden af at kode skal nusses, opdateres og plejes. Hans firma sælger jo også software til styring af softwareprojekter og distribueret versionsstyring. Han lever altså af at ny kode skrives, og gammel kode opdateres.

Tro mig, han er enig i at gammel kode ikke er hellig og urørlig.

Men den ruster altså ikke - den er præcis som den er, medmindre man selv aktivt gør noget for at ændre den. I modsætning til en rustproces, der typisk indfinder sig og accelererer, hvis man [i]intet[/i] gør.

Hans hovedpointe er at man ikke skal smide hele kodebasen væk og starte fra scratch, for der er tit en masse guldkorn gemt i den gamle kodebase - guldkorn man meget svært vil kunne analysere sig frem til, og derfor vil have svært ved at inkorporere i den nye version.

En iterativ tilgang til kodeforbedring ser nemlig ud til at klare sig bedre end en tilgang, hvor man [i]nuker[/i] gammel kode, og starter helt fra bunden. Hans eksempel med Netscape viser jo, at hvis et softwarefirma gør det, kan det blive fanget på det forkerte ben, og miste initiativet på markedet.

Når du har forladt din gamle kodebase, og er 2/3 færdig med din genskrivning af applikationen, hvad kan du så gøre, når dine konkurrenter sender nye versioner på markedet? Hvad kan du skibe ud? Den gamle kode uden nogen forbedringer, eller den nye, der kun er 2/3 færdig? Nej, vel?

Men rust-metaforen er ganske rigtigt meget let at misforstå, og er derfor nok ikke velvalgt.

Peter Makholm Blogger

Jeg ved ikke hvem der har givet dig tommelfingeren nedad, men jeg brugere den langt bredere end bare at et indlæg er irrelevant for debatten.

Et indlæg kan godt være relevant, men hvis jeg ikke mener at argumentationen hænger sammen eller at indlæget udviser åbenbar faktaresisten, så får det også tommelfingeren nedad.

Jeg tror at der er en del der bruger tommelfingeren som en enig/uenig-angivelse uanset om man mener at argumentationen hænger sammen. Og hvis man er fast uenig i konklussionen vil man selvfølgelig også have en tendens til at mene at argumentationen er usammenhængende, så det er ikke altid tydeligt for en selv om man har givet et minus af den ene eller anden årsag.

Men personligt kan jeg nu godt lide et velformuleret indlæg der går min egen holdning imod. Hellere det en hjernedød Micorsoft-bashing der når til en konklussion jeg tilfældigvis er enig i. (Men det eksempel er vist ikke relevant for den aktuelle debats emne).

... men jeg har ikke nærlæst dit indlæg.

Nikolaj Brinch Jørgensen

@Peter
Nej det er også mig ligegyldigt hvem det er, jeg kunne bare godt tænke mig, at vedkommende uddybede sin uenighed, for på den måde kan vi have en konstruktiv debat.

Jeg er iøvrigt ellers helt enig med dig. Det kunne være rart hvis Microsoft bashingen kunne holde op her på version 2 (jeg er ikke selv Microsoft bruger, men den bashing der foregår her grænser til fanatisk modstand).

Log ind eller Opret konto for at kommentere