Etikettarkiv: programmeringsliv

Safety net tests?

För ett par dagar sedan höll jag en liten informell presentation på jobbet om en metod jag brukar luta mig mot när jag refaktorerar kod. Metoden beskrivs i boken Working Effectively With Legacy Code av Michael Feathers och kallas för The Legacy Code Change Algorithm. Den består av dessa fem enkla steg:

1. Identify change points.
2. Find test points.
3. Break dependencies.
4. Write tests.
5. Make changes and refactor.

Egentligen är väl tanken att algoritmen ska användas för att angripa legacykod utan att riskera land och rike, men om man för en stund bortser från ”make changes” i punkt 5 återstår ju faktiskt ”refactor”.

Nu vore det kanske på sin plats att definiera ”legacy code”. Menar man en stor hög med spagettikod från antiken? Eller betyder det helt enkelt att koden är dammig och bortglömd? Det finns säkert många definitioner där ute, men egentligen behöver vi bara bry oss om hur Feathers definierar begreppet för att förstå hans algoritm. Hans definition är som följer:

”Legacy code is simply code without tests.”

Plain, simple och kanske lite brutalt. Oavsett vad man tycker innebär definitionen alltså att koden kan ha författats igår – utan tester klassar Feathers den som legacy.

Tillbaka till min presentation (och poängen med detta inlägg). I en av mina slides hade jag ställt upp algoritmen för Test-Driven Development (TDD) jämte The Legacy Code Change Algorithm för att på så sätt kunna resonera om hur vi kan förhålla oss till tester som skrivs i respektive algoritm. Här tycker jag att det finns en intressant skillnad som hänger ihop med testernas syften.

I TDD ingår författandet av tester som en del i utvecklingen. Syftet med tester som skrivs här är att öka kvalitén på koden som skrivs och att via tester skapa en slags dokumentation över hur koden används. Om vi sedan tittar på The Legacy Code Change Algorithm syftar testerna istället till att skapa förutsättningar för att genomföra förändringar utan att ta sönder saker. Det betyder också att testerna i sig inte nödvändigtvis behöver vara en naturlig del av koden (som i fallet med TDD).

För mig blir det med ovanstående resonemang mycket enklare att motivera användandet av mocking frameworks såsom Mockito eller PowerMock när jag refaktorerar legacykod. Med sådana frameworks tillämpar man en slags White-box testing där testerna till stor del lutar sig mot hur implementationen ser ut. Helt vanligt refaktoreringsarbete kan då ta sönder sådana tester – trots att kodens beteende fortfarande mycket väl kan vara alldeles riktigt och rätt – eftersom implementationens utformning förändras.

Jobbigt, jobbigt.

Men i en galet komplex kodmassa kan ramverk som Mockito göra hela skillnaden för att få en ärlig chans att refaktorera på ett säkert sätt. Om testerna blir väldigt svårförvaltade kan jag tycka att de på sätt och vis har spelat ut sin roll och kan tas bort. Koden som refaktorerades när testerna skrevs bör i vilket fall vara i ett bättre tillstånd än tidigare, vilket också var det vi ville uppnå.

Kanske vore det läge för en ny benämning för tester som skrivs i detta syfte? Vad sägs om Safety net tests? 😉

Person och sak

Idag hade jag en stund över på jobbet och ägnade då lite tid åt att förkovra mig i mitt ämbete som systemutvecklare. Den virtuella surfbrädan tog mig så småningom fram till Programmers Stack Exchange där användaren kmote i ett inlägg hade ställt frågan:

I’ve inherited 200K lines of spaghetti code — what now?

I det svar som hade fått flest röster (467 stycken när jag var inne på sajten) bjöd på en gedigen genomgång av tekniker och rekommendationer över hur man kan handskas med ett sådant scenario. I denna mäktiga textmassa hittade jag ett citat direkt kopplat till Imposter Syndrome som jag fastnade för och tänkte dela med mig av här. Användaren haylem skriver såhär:

Make developers conscious of the quality of their code, BUT make them see the code as a detached entity and not an extension of themselves, which cannot be criticized. It’s a paradox: you need to encourage ego-less programming for a healthy workplace but to rely on ego for motivational purposes.

Jag tycker att haylem på ett väldigt bra sätt formulerar ett viktigt dilemma vi har i vårt yrke, ett yrke där allt vi producerar synas och granskas. Minsta incheckning i versioneringssystemet kan vem som helst av de andra utvecklarna i projektet ta del av. Byggservern sprutar ut felmail till gud och alla människor om något inte fungerar som det ska. Kodgranskning är ett givet steg i utvecklingsprocessen i vilken en utvecklare tar sig an att granska och bedöma hur vettig en annan utvecklares kod är.

Med så mycket fokus på individuell prestation gäller det att bygga upp en sund relation mellan person och sak. Inte minst för att tillvaron på arbetsplatsen ska bli dräglig, både för sig själv och sina kollegor.

Bedragare

Under min tid som systemutvecklare har jag upptäckt att det inom branschen finns en hel del människor som ger sken av att kunna allt. Ett slags supermänniskor of sorts som alltid har lösningen på alla problem. De behöver aldrig fråga eller undra när man pratar med dem för de vet ju redan allt. De tar stor plats på möten – gärna på andras bekostnad – och får med sin övertygelse allt som oftast igenom sina idéer. Det är liksom ingen som orkar ge sig in i den lönlösa debatten och argumentera emot.

Naturligtvis är det så att dessa personer inte kan allt. Det kan ingen. Och förmodligen finns det någon annan i mötesrummet som vet mer om ämnet i fråga när Superman (eller Wonderwoman för att vara PK) håller låda. Men det spelar liksom ingen roll; i denna svärm av fräcka och moderna buzzwords är det lätt att känna sig stressad, att få känslan av att alla i rummet verkar fatta utom jag. Det är ju ingen som ställer frågor?

Stressen över att inte räcka till kompetensmässigt kunde jag känna mer förr än nu. Jag minns speciellt som konsult att det i och med min roll fanns en förväntan på mig att jag skulle kunna både ditten och datten. Även som doktorand fanns det inslag av denna känsla, av att jag aldrig visste tillräckligt hur mycket jag än lärde mig.

Idag läste jag om något som kallas för Imposter Syndrome, vilket tydligen är vanligt inom yrken där ens arbete granskas. Med denna åkomma har man, trots bevisligen god kompetens, svårt att koppla samman de bra saker man gör med sin förmåga. Man ser sig nästan som en bedragare och inväntar den dagen någon kommer avslöja att ens förmåga inte lever upp till omvärldens förväntan.

Kanske har jag en lindrig släng av denna åkomma? Jag vet i vilket fall med mig att jag har höga krav på mig själv och att jag som sagt fortfarande kan känna att jag borde kunna mer för att känna mig tillräcklig. Här hjälper supermänniskorna jag inledde mitt inlägg med verkligen inte till utan bidrar istället i högsta grad till att arbetsklimatet blir prestigeladdat, att folk blir rädda för att säga fel saker eller ställa konstiga frågor.

Men vad är det för fel att fråga?

Bra fråga. För om det är något som jag har lärt mig att uppskatta så är det människor som vågar fråga, som vågar säga ”Kan du ta det där en gång till, jag hängde inte med?” eller ”Kan du berätta lite mer om X, det har jag inte koll på”. Och jag tänker att människor som vågar fråga rimligen också lär sig mer.

Ortogonalitet

Igår kväll satt jag och bläddrade lite i den gamla goda Pragmatic Programmer, mest för att jag inte hade så mycket annat för mig just då. Ganska tidigt i boken springer man på begreppet – låt oss se om jag lyckas stava det rätt – Orthogonality, eller Ortogonalitet som det så fint heter på svenska, och jag passade på att fräscha upp min förståelse av innebörden.

Jag visste sedan tidigare att det inom systemutveckling används för att säga huruvida ändringar i en komponent – allt ifrån enstaka klasser till större logiska indelningar – påverkar andra komponenter i systemet. Det man eftersträvar inom systemutveckling är att göra systemets komponenter ortogonala för att på så sätt minska bieffekter vid förändring av dessa. Även om man inte är bekant med termen i sig genomsyrar ändå andemeningen väldigt många saker av det vi som systemutvecklare pysslar med och stöter på dagligen. Vi minimerar synlighet av variabler, vi delar in klasser i paketstrukturer eller komponenter för att logiskt avgränsa dem, vi läser om och försöker eftersträva Single Responsibility Principle (SRP) och Law of Demeter. The list goes on.

Det jag tänkte prata om i det här inlägget är att jag i samma avsnitt i boken lärde mig något nytt. Det visade sig att ortogonalitet från början är ett geometriskt begrepp och att dess innebörd kan representeras som ett diagram. I boken finns en liten bild som för mig lämnade lite att önska. Jag läste, tittade på bilden, läste lite till och bestämde mig för att rita upp diagrammet på mitt sätt, på det sätt det stämde i mitt huvud. Kanske du tänker likadant som jag och är hjälpt av det också?

Ortogonala axlar
Ortogonala linjer

Bilden ovan ska illustrera två linjer som bildar en rät vinkel (jag hittade ingen linjal). Dessa linjer är ur ett matematiskt perspektiv ortogonala. Det låter ju jättefint, men hur hänger det ihop med ordets innebörd inom systemutveckling? För att jag skulle fatta det bättre namngav jag axlarna enligt ”State of component X” respektive ”State of component Y”. Man kan då tänka sig att två komponenter, X och Y, befinner sig vardera i ett visst tillstånd. Om jag förändrar tillståndet i komponent X, till exempel byter bakgrundsfärg från blå till grön, innebär detta enligt diagrammet ovan en strikt horisontell förflyttning utmed X-axeln. Komponenten Y påverkas inte alls av en horisontell förflyttning, den behåller det tillstånd som den var i tidigare. Klart som korvspad!

Det är allt lite coolt att se innebörden av ett begrepp representerat i ett diagram, om inte annat får man en annan infallsvinkel. Kanske är det vardagsmat i en matematikers yrkesliv men i mitt duggar det verkligen inte tätt.

Setters under ansvar

För många systemutvecklare är det jag nu tänker skriva om något vedertaget – bok efter bok förklarar varför man inte ska ägna sig åt det – men för andra verkar det inte vara det vilket ligger till grund för detta inlägg. Det jag pratar om är det där med att peta in setters på attribut i sina klasser bara för att man kan, något som enligt mig (och andra) i de flesta fall är snudd på kriminellt beteende. I vissa avseenden kan det väl vara ok – jag tänker då på primitiva databärare som enkelt ska kunna serialiseras och deserialiseras – men dessa ska ses som undantagsfall.

Varför? Jo, därför att man skapar en state machine från helvetet. Vad menar du nu? Jo, ponera följande klassdefinition. Ni får försöka låta bli att irritera er på den något retarderade klassen och dess attribut – exemplet syftar bara som underlag för att få fram min poäng.

public class Car {
   private String regNumber;
   private String model;
   private Owner owner;
   private Date ownerRegisteredDate;
}

Låt oss säga att vi slänger in publika getters och setters på alla attribut. Om vi nu tänker oss att varje attribut har två möjliga tillstånd – satt eller icke satt – kan vi räkna ut totalt antal möjliga tillstånd som instanser av klassen kan befinna sig i. Med endast fyra attribut landar vi på 2*2*2*2 = 16 möjliga tillstånd. Och nu snackar vi bara om huruvida attributen är satta eller ej. Tänk er att vi kastar in ett attribut till – en enum med fem möjliga tillstånd – och vi landar på 16*5 = 80 möjliga tillstånd. Ja ni ser vart jag är på väg.

Nu pratar jag dessutom bara om möjliga tillstånd vilket inte är samma sak som giltiga tillstånd. Är tillståndet i en instans giltigt om alla attribut har värdet null? Skulle man kunna tänka sig att det alltid bör finnas ett regNumber på en bil? Borde det inte alltid finnas ett ownerRegisteredDate om owner är satt?

Med setters på allt kan man inte dra sådana slutsatser. Designen begränsar därmed domänmodellens potential och man degraderar dess klasser till beteendelösa databärare vars tillstånd man underhåller med logik i servicelager och validatorer. Hela grejen är bara så fel.

I synnerhet som det finns så enkla lösningar med vilka man kan komma ganska långt.

Låt oss säga att ovanstående klass alltid måste ha ett regNumber satt. När en ny bil registreras måste man dessutom ange model. Det finns inga krav på att model någonsin ska ändras. Låt då bli att lägga dit en setter! Vidare kan en bil ha en ägare (owner) med ett startdatum för ägandeskapet (ownerRegisteredDate). Dessa kan komma att ändras över tid. Här behöver vi någon konstruktion som låter oss sätta dessa värden. Vi tittar på hur en enligt mig mer sund klassdefinition skulle kunna se ut:

public class Car {
   private String regNumber;
   private String model;
   private Optional<Owner> owner;
   private Optional<Date> ownerRegisteredDate;

   public Car(String regNumber, String model) {
      this.regNumber = checkNotNull(regNumber);
      this.model = checkNotNull(model);
   }

   public void registerOwner(Owner owner) {
      this.owner = Optional.of(checkNotNull(owner));
      this.ownerRegisteredDate = Optional.of(new Date());
   }

   public void deregisterOwner() {
      this.owner = Optional.<Owner>absent();
      this.ownerRegisteredDate = Optional.<Date>absent();
   }
}

Det ska tilläggas att jag i ovan exempel använder Preconditions från Guava och Optional från Guava/Java 8 för att få koden mer läsbar. Koden är dessutom skriven på frihand så jag reserverar mig för syntaxfel. Jag har även utelämnat eventuella getters. Men min poäng är ändå att vi här endast har två möjliga tillstånd för instanser av denna klass. För att förtydliga detta tittar vi i nedanstående tabell. Varje rad anger ett tillstånd och x markerar att attributet har ett värde.

regNumber model owner ownerRegisteredDate
x x
x x x x

Vi går alltså från 16 möjliga tillstånd till endast två. Dessutom är dessa två tillstånd även giltiga. Vi vet att regNumber och model alltid har ett värde och att de aldrig kommer att ändras. Vi vet också att owner och ownerRegisteredDate endast kan existera och ändras tillsammans. Med enkla medel och avgränsningar på rätt ställe kommer man väldigt långt.

För den intresserade vill jag återigen lobba för Eric Evans bok Domain-Driven Design: Tackling Complexity in the Heart of Software. Alla borde läsa den.