Onlangs heb ik hét boek over Refactoring gelezen, namelijk Refactoring: Improving the Design of Existing Code van Martin Fowler. Dat wil zeggen, ik heb alle hoofdstukken gelezen die de basis leggen voor de refactorings verderop in het boek. Het grootste deel van het boek bestaat namelijk uit een catalogus van refactorings en is zeer geschikt als een naslagwerk: eentje dat vanaf nu dichtbij ligt tijdens mijn werk.
Catalogus
Alle refactorings die Fowler in het boek beschrijft, zijn uitgewerkt om eenvoudig toe te kunnen passen. Om een eenduidige manier te hebben om erover te praten, hebben ze allemaal een naam, heel handig. Daarnaast is de samenvatting - soms met code, soms met UML - heel handig om snel te zien wat de refactoring doet. Vervolgens zijn een stappenplan en voorbeelden uitstekend om de refactorings toe te passen. Maar niet te vergeten wordt de motivatie van elke refactoring ook besproken: waarom zou je de betreffende refactoring wel of niet gebruiken? Zoals je al kunt merken, is dit een uitstekend naslagwerk om in de buurt te hebben liggen.
Refactoring?
De meesten hebben wel een beeld bij wat refactoring is, maar klopt dat beeld wel? Bij mij was dat beeld - zeker een aantal jaar geleden - niet helemaal juist. Ik dacht dat het ging om grote wijzigingen in bijvoorbeeld architectuur en het omgooien van grote delen van je code, maar het gaat juist om vooral hele kleine wijzigingen die de code langzaam beter maken. Leesbaarheid van de code is hierbij een van de belangrijkste speerpunten. Wist je dat code veel vaker wordt gelezen dan geschreven? Lees ook eens Modelleren kun je leren.
Voorbeeld graag
Een voorbeeld is bijvoorbeeld Extract Method, waarbij je van een stukje code een nieuwe methode maakt met een naam die duidelijk maakt wat dat stukje code doet. Dit is iets dat veel mensen al wel doen en wat een goede IDE zelfs voor een groot deel kan automatiseren. Of wat dacht je van Introduce Parameter Object, waar je een reeks van parameters, die eigenlijk samen een concept vormen, samenvoegt tot een nieuw object? Een startdatum en een einddatum als parameters zou je bijvoorbeeld heel goed kunnen samenvoegen tot een periode-object.
Definitie
Refactoring gaat over het aanpassen van de interne structuur van software zonder het observeerbare gedrag ervan te veranderen met als doel om het makkelijker te begrijpen en goedkoper te maken om aan te passen.
Uit deze definitie (vrije vertaling, red.) kun je o.a. halen dat het gaat om leesbaarheid en onderhoudbaarheid, twee zaken die nauw verbonden zijn en waar wij bij Procurios naar streven. Refactoring is een manier om op een relatief eenvoudige manier code aan te passen om dit te bevorderen.
Wat ook onder de aandacht wordt gebracht in het boek, is dat een ontwikkelaar eigenlijk twee petten zou moeten hebben: eentje voor het toevoegen van nieuwe dingen, de andere voor het herstructureren van bestaande code en dat je die twee petten nooit gelijktijdig op zou moeten zetten.
Geurtjes
Om te ontdekken waar refactorings mogelijk en misschien zelfs nodig zijn, zijn er zogenaamde code smells. Dit zijn kenmerken van code, waaraan je kunt ontdekken dat er iets mis is, dat iets beter kan. Je kunt als het ware ruiken dat er iets stinkt. Er worden ruim twintig van deze geurtjes beschreven en aan elk worden bepaalde refactorings gekoppeld die ervoor kunnen zorgen om de code te verbeteren. Voorbeelden zijn Long Method en Large Class, maar ook meer exotische geuren komen langs, zoals Shotgun Surgery en Speculative Generality. Als je meer wilt weten over de details hiervan, dan raad ik je aan om het boek te lezen.
Tips
Ik wil niet te veel ingaan op alle refactorings uit het boek, want dan ben ik het aan het herschrijven. Ik wil wel graag een aantal zaken noemen die ik zelf interessant genoeg vind om te delen.
Is het moeilijk om een feature toe te voegen? Probeer dan eerst te refactoren, zodat het eenvoudiger wordt om de feature toe te voegen.
Zorg ervoor dat je een suite van tests hebt die het gedrag van bestaande code valideert. Dit geeft je meer vertrouwen in de werking van de code tijdens en na een refactoring.
Gebruik kleine stapjes. Met kleine stapjes weet je precies waar een bug zich voordoet en is die eenvoudiger te vinden en op te lossen. Het kost ook weinig om kleine stapjes terug te draaien om opnieuw te beginnen.
Sla hoofdstuk 15 (het laatste hoofdstuk) niet over. Dit is een hoofdstuk vol inspiratie en bemoediging.
Smoesjes
Eigenlijk is er geen excuus om niet te refactoren. Als je zegt geen tijd te hebben, dan is dat alleen voor de korte termijn; refactoring zorgt er juist voor dat features toevoegen eenvoudiger zal worden en code beter leesbaar is. Op de lange termijn zul je er dus alleen maar tijd mee winnen, want wie wil nou een bug zoeken in belabberde code?
Kun je er dan echt nooit voor kiezen om niet te refactoren? Jawel, namelijk als het beter is om de code te herschrijven, bijvoorbeeld als de code een te grote troep is geworden of als er te veel fouten/bugs in zitten. Een ander moment om niet te refactoren, is dicht bij een deadline, waarbij de tijdswinst pas te laat in werking zou treden. Houd er dan wel rekening mee dat je bewust kiest voor technische schuld, die je later, na de deadline, wel weer moet zullen inlossen.
Performance
Opvallend vond ik de stukken over performance. Replace Temp With Query is een refactoring die een tijdeljk variabele vervangt door een methode, op alle plaatsen waar die variabele gebruikt wordt. Mijn eerste gedachte gaat daarbij altijd direct richting performance, want die methode wordt nu dus misschien wel vaker aangeroepen en kost misschien wel veel tijd. Nog erger is het als de tijdelijke variabele in een loop gevuld wordt; dan zou je dus de hele loop moeten overnemen in de methode en als er meer dan één tijdelijke variabele wordt gevuld in de loop, dan maak je dus een aantal keer de hele loop in een nieuwe methode. Mijn nekharen gaan automatisch overeind staan. En toch wordt geadviseerd om dit zo te doen, omdat het verdere refactoring eenvoudiger maakt, de code leesbaarder maakt en 9 van de 10 gevallen de performance niet tot nauwelijks slechter wordt. Performance is dan dus een zaak van later zorg. Vaak is het met betere (refactored) code juist eenvoduiger om optimalisaties te vinden en de performance te verbeteren indien dat dan nodig blijkt.
Slotwoord
Dit boek is na al die jaren (uitgegeven in 1999) nog steeds het standaardwerk op het gebied van refactoring. De jaren beginnen echter wel te tellen in sommige hoofdstukken. Met name het hoofdstuk over testen is wat verouderd, maar je vind hier en daar wel meer hints over de tijd waarin het is geschreven. Gelukkig maar, want dat betekent dat we niet stil zijn blijven staan. Is dit boek dan niet meer van deze tijd? Zeker wel, voor refactoring hoef je vooralsnog nergens anders te kijken en ik raad dan ook aan om dit boek te lezen en in de buurt te hebben.