Clean Code - Hoofdstuk 1 en 2

Ingediend door Dirk Hornstra op 26-nov-2018 17:09

Ik heb dit boek eerder gelezen, maar tijdens ons Back-end-overleg kwam het boek nogmaals ter sprake. Omdat niet iedereen de discipline kan opbrengen (of simpelweg de tijd heeft/neemt) om het boek te lezen hebben we de afspraak gemaakt om voor het volgende overleg de eerste 2 hoofdstukken te lezen. Wat ik de maandag van tevoren dan ook maar even gedaan heb. Één van de stagiaires had trouwens de samenvatting gevonden, mocht je het 30 pagina's doorlezen toch te intensief vinden ;) Link: https://medium.com/@BrunoLM7/a-brief-summary-of-clean-code-c0c557739551

Een boek begin je vanaf pagina 1, dus begonnen met het intro. Een verhaaltje over hoe Uncle Bob en zijn companen tot dit boek gekomen zijn. Zo komen ze op de mantra's uit Japan uit 1951, toen de TPM -aanpak(Total Productive Maintenance) voet aan de grond kreeg. Die aanpak bevat een aantal basisbegrippen, waaronder de 5S principes. Die zijn:

Seiri, dit staat voor sortering/organisatie. Weet waar dingen te vinden zijn. Geef zaken duidelijke namen.

Seiton, dit staat voor opgeruimdheid / systematiek. Er is een plaats voor alles en alles staat/ligt op zijn eigen plek. Een stuk code zou moeten staan op de plaats waar je het verwacht. Als dat niet zo is, moet je de code refactoren om het alsnog daar te krijgen.

Seiso, dit staat voor schoonmaken/schoon houden. Hou je code schoon. Allemaal blokken in commentaar (waarom?), allemaal comments om code toe te lichten. Het zorgt ervoor dat de boel er "onverzorgd" uit ziet.

Seiketsu, dit staat voor standaardisatie. Je houdt de boel schoon, je zorgt voor een standaard code-stijl. Als je de alle classes een methode Add geeft, maar ééntje niet, die heeft een methode Append, maar doet exact hetzelfde, dan hou je je dus niet aan de standaard.

Shutsuke, dit staat voor discipline. De wil en discipline hebben om deze regels/standaarden te volgen, te reflecteren en de wil hebben om je aan te passen.

In 1951 stond dit voor het op een gestructureerde manier in stand houden van een werkplaats/fabriekshal, maar het is uitermate geschikt om code ook onderhoudbaar, inzichtelijk, duidelijk en wat al niet meer te maken. Daarom dit boek. Zo, was je meteen met hoofdstuk 1 begonnen dan weet je dus al niet wat het 5S-principe is.

Intro.
We beginnen met de main-test van je code, het aantal WTF (what-the-f*cks) per minuut. Als dat te hoog is, dan is de code waarschijnlijk niet van het meest hoogstaande niveau. 

Hoofdstuk 1. 
Dat je het boek leest geeft aan dat je programmeur bent. En ook dat je een betere programmeur wilt worden. Om het met het geluidsfragment van Buma uit Zondag met Lubach samen te vatten: "chapeau!". We beginnen met "bad code". Als ervaren programmeur zal het je gauw genoeg duidelijk zijn of iets "slechte code" is. Maar dat je dat weet, zorgt nog niet dat je ook meteen automatisch de oplossing hebt om er "clean code" van te maken. Je hebt slechte code, er moeten zaken bijgebouwd worden, meer knopen op knopen die er al in zaten. Het werkt vlot niet, er worden meer mensen op ingezet (die geen idee hebben dat als ze ergens tegen aan tikken het op 5 andere plekken kapot gaat) en uiteindelijk gaat je productiviteit naar nul. 

Hierna komt de vraag aan wie het ligt. Naar anderen wijzen is makkelijk: het was al zo slecht, ik krijg de tijd niet om het aan te passen, er liggen nog 20 dingen op mij te wachten. Fout. Jij bent de programmeur, jij bent degene die kan beoordelen of de code waar je mee werkt "goed" of "fout" is. Dus doe je best, kaart het aan bij de manager of andere leidinggevende die misschien ten onrechte bepaald heeft dat het maar een uurtje werk is om de feature toe te voegen. Dat er in de huidige code nog wel drie uur werk zit om de boel weer "clean" te maken, dat weet hij/zij niet en als je er niet op wijst/het meldt zal hij/zij het ook niet weten. Als die persoon er dan niets mee doet, dan is dat zijn/haar call, maar niet de jouwe.

Door naar "clean code". Er zijn natuurlijk meerdere interpretaties/aannames wat clean code is. Zo worden een aantal bobo's aan het woord gelaten hoe zij het zien. Bjarne Stroustrup,  dat code moet elegant en efficiënt zijn. Duidelijke/simpele logica waardoor bugs weinig tot geen kans maken. Weinig afhankelijkheden van andere code-onderdelen, goede error afhandeling en zo optimaal dat mensen er geen systeemcalls in gaan hacken om performanceverbeteringen door te voeren (en code weer deels onleesbaar wordt). Grady Booch heeft het over dat code zo goed leesbaar is alsof het een soort verhaal is. En als je zelf in code aan het spitten bent en van functie naar functie gaat, dan kan ik daar wel in mee gaan. Dave Thomas, code kan gelezen worden en aangepast/uitgebreid door een ander dan degene die het gemaakt heeft. Michael Feathers heeft als interpretatie dat de code zo geschreven is dat als jij het bekijkt en denkt over aanpassingen/alternatieven toch steeds uitkomt bij de huidige opmaak van de code. Ron Jeffries komt met dat het alle testen doorstaat, er geen duplicaten in staan, het zo weinig mogelijk classes en functies heeft. Vooral goede naamgeving zodat duidelijk is waar een variabele voor nodig is/bedoeld is. Ward Cunning zijn interpretatie is dat elke functie teruggeeft wat je van tevoren als resultaat verwacht had. 

Uiteindelijk krijgen we nog de Boy Scout Rule:



Leave the campground cleaner than you found it
 

Als je dat moet doen (bug fixen, nieuwe features toevoegen) probeer bij je commits ook meteen zaken op te schonen. Want zoals hier ook ergens in stond, als je zegt "dat ga ik later nog wel eens doen", je hebt de wet van LeBlanc: later = nooit. En ik kom in bepaalde code inderdaad nog wel "todo's" van een aantal jaar geleden tegen... Dat je daar nu niets aan gaat doen, dat komt door de gut-feeling van "het heeft dus de afgelopen jaren altijd gewerkt, als ik het nu ga aanpassen introduceer ik waarschijnlijk bugs die we niet willen".

Aan het eind wordt nog verwezen naar een boek van de schrijver die je als "prequel" van dit boek zou kunnen lezen: Agile Software Development, Principles, Patterns, and Practices ( link ). Dat boek heb ik (nog) niet, wel het vervolg van het boek "Clean Code", namelijk The Clean Coder ( link ).

Hoofdstuk 2.
Titel van dit hoofdstuk is "Meaningful Names", oftewel "betekenisvolle namen". 

Geef variabelen de intentie-uitende naam.
Dus niet int d, maar int fileAgeInDays. 
In een volgend voorbeeld gaan we loopen door een lijst met arrays van integers. Elke keer wordt daar de variabele op positie 0 gecontroleerd op waarde vier. Waarom op die positie? Waarom op die waarde? Dan blijkt dat het hier om minesweeper gaat en op veld 0 de status ingesteld staat en 4 staat voor "flagged". Maak hier constanten van en de functie is in één blik te doorgronden.

Voorkom dis-informatie
Afkortingen voor variabelen (hp, aix), doe het niet (in dit geval unix-namen of hewlet packard?). Maar ook AccountList terwijl het misschien objecten zijn en niet een "list". Ook dan is het volgens de auteur niet aan te raden (klopt, stel dat je er later een Queue of Stack van maakt, dan zou je dus ook de naam aan moeten passen, want dan is je eerste indruk foutief). 

Maak betekenisvolle uniciteiten
Je hebt een functie getActiveAccount, maar ook getActiveAccounts en getActiveAccountInfo. Welke moet je nu gebruiken? Ook een copy-functie met twee parameters, a1 en a2 terwijl als je a1 source noemt en a2 destination het meteen duidelijk is.

Gebruik uitspreekbare namen
In het voorbeeld gaat het om een veld wat genymdhms heet, wat eigenlijk generationTimeStamp zou moeten zijn. 

Gebruik zoekbare namen
Noem een variabele a, wil je die in de code zoeken, dan kan intellisense vast wel veel doen, maar als je NotePad++ laat zoeken wordt het niets. Hetzelfde geldt voor bijvoorbeeld BTWpercentages. Als je overal 21 in plaats van een constante met naam BTWPERCENTAGEHOOG, dan zul je overal op 21 moeten zoeken en vervangen als de regering weer eens een BTW wijziging doorvoert.

Voorkom Encodings
Dus niet het type in de naam opnemen. Vroeger was het nodig om het type inzichtelijk te maken (sVariabele, iVariabele, bVariabele, zodat je weet dat het om een string, int en boolean gaat). Maar met huidige IDE's is het niet meer nodig om dat te doen.

Voorkom mentale mapping
Ik zie een tresQ variabele, oh, dat is altijd 255. Nee, nee, nee. Bij het zien van een naam moet ook iemand die de code voor het eerst ziet inzichtelijk hebben waar iets voor staat.

Namen van classes
Dit moet een naamwoord zijn, niet een werkwoord. Dus Customer, Company en niet Data, Info.

Namen van methodes/functies
Dit moeten juist wel werkwoorden zijn (postPayment, deletePage). Als je een constructor "overload", dan moet je dit met een naam die de argumenten beschrijft doen (Complex.FromRealNumber(23.3)).

Wees duidelijk, niet "leuk"
Noem een functie gewoon Delete() en niet PutItDownTheDrain(), want heb je bij de laatste functie wel door dat alle gegevens verwijderd worden?

Kies één woord per concept
Voorbeeld is get, fetch, retrieve. Zorg dat je bij 1 naam blijft, zodat het uniform door je applicatie heen loopt.

Voorkom woordspelingen
Woordspeling is in dit geval dat je een functie overneemt van de rest, bijvoorbeeld Get. Dat geeft je bij alle classes het item van een lijst of array terug. Maar in deze class van jou gebruik je een stack en doe je eigenlijk een "Pop". Kun je bij de andere functies 20x die Get aanroepen en elke keer hetzelfde item ophalen, zo krijg je bij deze class dus elke keer een ander item terug (of is je stack leeg en kun je niets meer "poppen").

Gebruik oplossingsgerichte namen op jouw vakgebied
Jij bent programmeur en werkt aan een oplossing, andere programmeurs gaan ermee verder. Als jij een EmailQueue maakt, snapt een andere programmeur dat ook.

Gebruik probleem-domein gerelateerde namen
Kom je er met die EmailQueue niet uit en moet je het beestje een andere naam geven, dan kun je een naam gebruiken zoals die bij de klant duidelijk is. Stel dat je een applicatie maakt voor een partij waarbij wederverkopers een eigen korting krijgen. In het vakgebied is dit bekend onder "rabat". In de applicatie kun je dus rabatDiscount gebruiken en zal de klant weten waar het over gaat, terwijl een algemene "discount" ook voor normale klanten zou kunnen gelden.

Gebruik betekenisvolle context
In het voorbeeld hebben we een street, housenumber, zipcode, city. Maar wil je dan het adres maken, is dit alles of moet "state" er ook nog bij (of country)? In het voorbeeld wordt er een prefix voor gezet (addr) zodat duidelijk is dat het bij het adres hoort. Zoals ook al gezegd wordt is het beter om een eigen address-class te maken, zodat je het op die manier kunt afhandelen. 

Voeg geen gratis context toe
Je werkt bij een bedrijf (abc) en voegt bij al je classes de prefix abc toe. Dat is een grote no-no. Want als je vervolgens in je Intellisense een class wilt gebruiken, krijg je alles beginnend met abc.... en kun je niets meer vinden. Stay short. Stay clean.