dinsdag 19 mei 2026

SOLID is te veel, POM is te weinig


Ik heb al aardig wat testautomatiseringsframeworks opgezet en aangepast. En ik heb altijd al veel aandacht besteed aan begrijpelijkheid en onderhoudbaarheid. Maar sinds ik in de detachering ben gegaan, is dit onderwerp nog meer gaan leven. Je hoort opeens in korte tijd veel meer meningen over wat de ideale code is. Waarbij woorden als SOLID en POM regelmatig langskomen.

Wat SOLID betreft zie ik grotendeels twee kampen: het kamp dat de best practices altijd toepast en het kamp dat SOLID helemaal niet van toepassing vindt op testautomatisering. Ik merk dat ik hier tussenin val.

Ik heb deze best practices zelf geprobeerd toe te passen en ik merkte dat vaak testautomatiseringscode hierdoor in begrijpelijkheid en onderhoudbaarheid afneemt. De code is te eenvoudig om de best practices consistent op toe te passen. Hierdoor krijg je extra code lagen, die weinig toevoegen, maar wel zorgen dat je code nu op 2 of meer plaatsen moet aanpassen, in plaats van een. Bijvoorbeeld door het toevoegen van interfaces, die slechts een maal in de code gebruikt worden. Een ander voorbeeld is het opsplitsen van paginacode in een invoer- en een validatieklasse vanuit de S van SOLID. In de praktijk betekent dit dat een aanpassing aan één veld je dwingt twee bestanden aan te passen in plaats van één.

Maar dat betekent niet dat ik vind dat je het zomaar moet negeren. Het argument “Het is geen productiecode”, dat ik vaak hoor, vind ik niet terecht. Juist testautomatiseringscode heeft behoefte aan een goede onderhoudbaarheid. En daar kunnen principes als SOLID wel degelijk  aan bijdragen.

Over POM ben ik al veel langer ontevreden. Het is een goede structuur, zeker. Maar ik heb nooit gesnapt waarom we als testautomatiseerders regelmatig stoppen bij POM, helpers en datadriven programmeren. Qua data kan ik dit het snelste duidelijk maken: als een bedrijf besluit om in plaats van ‘Groot-Brittanië’ voortaan ‘United Kingdom’ te gebruiken, op hoeveel plaatsen in je code moet je dit dan aanpassen? Wie heeft zijn code zo geschreven dat het antwoord hierop ‘1 keer’ is?

Hoe doe ik het dan wel? Ik zal twee recente voorbeelden geven. Ik heb verschillende datasets gemaakt in mijn code, waarmee je op basis van een landcode (volgens internationale standaard) data horende bij dat land op kan halen. De data is op 1 plek vastgelegd. En bij aanpassen wordt automatisch het invoeren en controleren aangepast, omdat de landcode gelijk blijft. Daarnaast geeft dit de mogelijkheid om bij het testen eenvoudig testsets te maken van naar wens 1 land of juist een testset met data van verschillende landen.

Als extraatje heb ik de landcode zo vastgelegd, dat als ik er een toevoeg elke dataset niet meer te compileren is. Allemaal geven ze aan dat er nu een landcode mist. Dit is een variant op het L van SOLID, die je vraagt om bij een afgeleide van een interface er altijd voor te zorgen dat alle functies van die interface goed blijven werken. Door mij vertaald: door het toevoegen van een land moeten alle datasets goed opvraagbaar blijven. Een ontwikkelaar moet zich niet hoeven afvragen of standaardgebruik leidt tot een ongewenste uitkomst.

Een ander voorbeeld: een veelvoorkomend testautomatiseringsprobleem is comboboxen die niet als combobox werken. Je testtool kan in een combobox niet op de standaard manier een waarde selecteren. Dus haal je trucjes uit met klikken, invoeren of zoiets om toch maar de waarde geselecteerd te krijgen. En zo’n combobox komt vaak vaker terug. Deze code heb ik altijd gecentraliseerd, vaak in een functie. Maar nu heb ik er iets langer over nagedacht. Het eindresultaat waren twee nieuwe combobox classes. Een voor elk type dat ik in mijn code tegenkwam. Beiden hebben een selectOption() en een nth(), precies als Playwright. En beiden zijn gebaseerd op een abstracte klasse, die een eventuele nieuwe comboboxvariant dwingt dezelfde functies ook te implementeren. Deze oplossing zorgt dat ik een eventuele aanvulling zo toe kan voegen. Zo had de eerste versie alleen selectOption. De nth() is later toegevoegd. Als ik later een derde comboboxvariant tegenkom, voeg ik een nieuwe klasse toe zonder de bestaande twee aan te raken. Precies wat de O van SOLID beoogt.

In testautomatisering is onderhoudbaarheid belangrijk, net als begrijpelijkheid. Deze eisen moeten in mijn ogen altijd gaan boven SOLID, POM of welk design principe dan ook. Dat houdt in dat je geen enkel design principe pertinent moet afwijzen, omdat het de onderhoudbaarheid wel kan vergroten. Ook betekent het niet dat je elk design principe blind moet toepassen, omdat dat de onderhoudbaarheid en begrijpelijkheid kan verkleinen. En evenmin dat alleen het toepassen van design principes je code onderhoudbaar en begrijpelijk maakt, zeker niet in testautomatisering.

De vragen die ik mezelf blijf stellen zijn vragen als: wordt deze code of data op meerdere plekken herhaald? En hoe foutgevoelig is een aanpassing? Die vragen leiden soms tot een design principe als oplossing, soms tot een andere oplossing. Maar ik wil deze afweging elke keer opnieuw maken, alles om onderhoudbaarheid en begrijpelijkheid te blijven verhogen.

Geen opmerkingen:

Een reactie posten

Opmerking: Alleen leden van deze blog kunnen een reactie posten.