De filosofische geschiedenis van een ontwerpkeuze
“Philosophy is a battle against the bewitchment of our intelligence by means of language.” — Ludwig Wittgenstein, Philosophical Investigations
Softwareontwikkelaars schrijven niet slechts code, ze scheppen een model van de werkelijkheid. Wat dat betreft staan ze in een lange filosofische traditie. Oftewel: wat kunnen Plato en Wittgenstein ons leren over het modelleren van een (on)geverifieerd e-mailadres?1
*
Een zeer, zeer, zeer korte geschiedenis van de filosofie
427 v.Chr.: Plato wordt geboren in Athene, Griekenland. Hij zal beroemd worden om zijn Ideeënleer, die stelt dat de zichtbare werkelijkheid slechts een afschaduwing is van eeuwige, universele Ideeën. Hij sterft in 347 v.Chr..
Alfred North Whitehead zei ooit: “The safest general characterization of the European philosophical tradition is that it consists in a series of footnotes to Plato.” Die traditie nemen we nu daarom maar even voor lief.
26 april 1889: Ludwig Wittgenstein wordt geboren in Wenen, Oostenrijk. In 1922 meent hij alle filosofische problemen op te hebben gelost in zijn Tractatus Logico-Philosophicus. De werkelijkheid blijkt echter weerbarstiger. Hij sterft op 29 april 1951. In zijn posthuum verschenen Philosophical Investigations (1953) komt hij iets dichter bij zijn oorspronkelijk gestelde doel. (Het is mijn favoriete boek aller tijden.)
*
Een geverifieerd e-mailadres (1/2)
2024, het heden. Een softwareontwikkelaar ontwerpt de inlogfeature voor een website.2 Hij gaat in gesprek met de business. Ze beschrijven hem de gewenste flow: een gebruiker vult zijn gegevens in, krijgt een e-mail toegestuurd, drukt op de daarin aanwezige bevestigingsknop. Vanaf dat moment is zijn emailadres geverifieerd en heeft de gebruiker toegang tot bepaalde delen van de applicatie.
Onze ontwikkelaar redeneert: ik moet dus een object EmailAddress
creëren, en dat EmailAddress
kan geverifieerd zijn, of niet. De vraag: hoe ziet dat object eruit?
Een voor de hand liggende oplossing is deze:
public class EmailAddress
{
public bool IsVerified { get; set; }
// Other properties...
}
En inderdaad: dat werkt. Maar:
-
Deze oplossing noodzaakt de ontwikkelaar code te schrijven in zijn methods die checkt of het emailadres geverifieerd is of niet. Dat introduceert de mogelijkheid tot bugs. Om na te gaan dat de code werkt zoals bedoeld, zal hij unittests moeten schrijven.
-
Een functie die een geverifieerd e-mailadres nodig heeft, en daarvoor gebruik maakt van een
EmailAddress
met de propertyIsVerified
optrue
, is niet eerlijk. De functiesignatuur zegt eenEmailAddress
te verwachten, maar verwacht eigenlijk maar een subset daarvan. -
De taal van de code weerspiegelt niet langer de taal van het domein. Domeinexperts maken onderscheid tussen geverifieerde en ongeverifieerde e-mailadressen; in de code zijn deze concepten verpakt in één en dezelfde class.
Een geverifieerd e-mailadres (2/2)
Dit is een betere oplossing:
public class EmailAddress
{
// Properties...
}
public class VerifiedEmailAddress : EmailAddress
{
}
Immers:
-
De ontwikkelaar hoeft bij deze oplossing geen checks in te bouwen: de compiler geeft een foutmelding wanneer iemand een
EmailAddress
probeert te gebruiken op een plek waar eenVerifiedEmailAddress
verwacht wordt. Deze subset van bugs is onmogelijk gemaakt, en tests zijn daarom niet nodig. -
De code is eerlijk. Een functie die een geverifieerd e-mailadres verwacht, signaleert die informatie in zijn functiesignatuur.
-
De code weerspiegelt de taal van het domein. Domeinexperts behandelen geverifieerde en ongeverifieerde e-mailadressen anders, en de code ruimt daar dus twee concepten voor in.
*
De filosofische geschiedenis van een ontwerpkeuze (1/2)
Waarom is de eerste oplossing, de minste oplossing, de meest voor de hand liggende? Mijn stelling is: deze oplossing ligt in de lijn van de Europese filosofische traditie (die kan worden gekarakteriseerd als een reeks voetnoten bij Plato), de traditie die ons denken voor een groot deel heeft gevormd.
Een programmeur in de Platoonse traditie bekijkt de wereld vanuit een metafysisch standpunt, vanuit het standpunt van de eeuwigheid. Hij ziet allerlei dingen en vraagt zich af: wat is er essentieel aan die dingen en wat niet?
Bijvoorbeeld: wat is er essentieel aan Socrates? Dat hij in Athene geboren is? Dat hij de leraar was van Plato? Dat hij ter dood werd veroordeeld? Nee: we kunnen ons voorstellen dat Socrates ergens anders was geboren, of iemand anders als leerling had, of dat hij een natuurlijke dood stierf – hij zou nog steeds Socrates zijn. De genoemde eigenschappen van Socrates zijn accidenteel.
Kunnen we ons voorstellen dat Socrates een ezel was? Nee: als Socrates een ezel zou zijn, dan zou hij geen Socrates meer zijn. Mens-zijn is een essentiele eigenschap van de filosoof. (Een volgende vraag is: waarin bestaat de essentie van mens-zijn dan? Gelukkig hoeven we ons daar nu niet over te buigen!)
Net zo werkt het bij een e-mailadres. Wat is er essentieel aan een e-mailadres, zeg socrates@akademeia.gr
? Je zou kunnen zeggen: dat het een lokaal deel bevat (socrates
), een apenstaartje (@
) en een domein (akademeia.gr
). Haal één van deze onderdelen weg, en je houdt geen e-mailadres meer over. Dat is waarom de regular expression om te valideren dat je met een e-mailadres te maken hebt, er als volgt uitziet: ^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$
.
Of het e-maildres geverifieerd is of niet, dat is – let op: vanuit het standpunt van de eeuwigheid bezien! – slechts accidenteel. Het e-mailadres houdt niet op een e-mailadres te zijn als de gebruiker wel of niet op de knop in onze bevestigingsmail drukt.
De filosofische geschiedenis van een ontwerpkeuze (2/2)
Maar: is het de taak van de ontwikkelaar om de metafysische kwaliteiten van een e-mailadres in code vast te leggen? Nee: de ontwikkelaar zou zich moeten bekommeren om het probleemdomein.
Wat heeft hem op dit pad gebracht? Wittgensteins zou waarschijnlijk zeggen: de taal zette hem op het verkeerde spoor. De ontwikkelaar hoort de domeinexperts spreken van een “(ongeverifieerd) e-mailadres” en een “geverifieerd e-mailadres” en concludeert dat het om één entiteit gaat die al dan niet gekwalificeerd wordt. Het woord “e-mailadres” staat in voor het ding e-mailadres, of die nu de eigenschap heeft geverifieerd te zijn of niet.
Dat is een uitdrukking van het idee: de betekenis van een woord is het ding waar het voor staat. Het is een centraal idee in de Europese filosofische traditie – en, volgens Wittgenstein, een misvatting.3 Het is een beeld van hoe taal functioneert dat werkt in enkele paradigmatische gevallen, maar hopeloos tekortschiet als algemene theorie van betekenis.
Hij plaatst daar een ander idee tegenover: betekenis is gebruik. De vraag die we ons zouden moeten stellen is welke rol de begrippen “e-mailadres” en “geverifieerd e-mailadres” spelen in het taalspel van de domeinexperts.
Wanneer we dat in kaart brengen, zullen we zien dat ze een heel andere functie hebben. Een “geverifieerd e-mailadres” heeft als rol bepaalde functionaliteit te ontsluiten. Het is als het ware de sleutel waarmee een gebruiker toegang wordt gegeven tot verborgen delen van de applicatie. Een “(ongeverifieerd) e-mailadres” is daarentegen slechts datgene wat diegene heeft ingevuld in een aanmeldformulier.
Je zou het verschil als volgt kunnen karakteriseren. Er is een chaotische werkelijkheid, met verschillende soorten e-mailadressen. (Twee, in dit geval.) De Platoonse ontwikkelaar probeert met die complexiteit om te gaan door te abstraheren, door het aantal elementen in de werkelijkheid terug te brengen tot één: het ideale e-mailadres.
De Wittgensteiniaan neemt een andere route. Deze ontwikkelaar erkent dat de werkelijkheid chaotisch is en probeert daar recht aan te doen. Hij meent: we kunnen alleen aan die complexiteit omgaan door te erkennen dat er verschillen bestaan tussen de verschillende soorten e-mailadres. Het is onze taak om erachter te komen hoe ze zich tot elkaar verhouden, en ze te plaatsen in hun juiste context.
*
Wittgenstein merkt op: de vragen waar we in de filosofie mee worstelen, zijn in de dagelijkse stroom van het leven volslagen onproblematisch. En hij concludeert op basis daarvan dat filosofische vragen schijnvragen zijn. Het zijn vragen die voortkomen uit het feit dat we bepaalde begrippen gebruiken buiten hun oorspronkelijke context, met alle raadselachtige gevolgen van dien.
Wanneer we de woorden terugbrengen naar hun thuis, verdwijnen de problemen – ze lossen eenvoudigweg op. Wanneer we de dingen juist zien, is een filosofisch problematisch term volstrekt vanzelfsprekend.
Softwareontwikkelaars schrijven niet slechts code, ze scheppen een model van de werkelijkheid. Wat dat betreft verschillen ze niet van filosofen. En net als filosofen, moeten ze de wereld zien zoals ze is, en niet zoals de taal suggereert dat ze is. Oftewel: ook het ontwerp van code is “a battle against the bewitchment of our intelligence by means of language.”
-
Deze blog schreef ik ter voorbereiding op een lightning talk die ik gaf op Nimma Codes. ↩︎
-
Ik ontleen dit voorbeeld aan een praatje van Scott Wlaschin (ik schreef er al eerder over, hier). Zijn boek Domain Modeling Made Functional is overigens een aanrader. ↩︎
-
Kijk daarom uit met versimpelde weergaven van Domain-Driven Design. Deze stellen soms categorisch: vertaal zelfstandige naamwoorden naar classes en werkwoorden naar methods. Dat is op zijn best een aardige heuristiek, maar brengt het risico met zich mee je op een dwaalspoor te brengen. ↩︎
domain-driven design · domeinmodel · filosofie · properties · wittgenstein, ludwig