Adresvalidatie en -normalisatie worden in de meeste projecten als één activiteit behandeld, en de verwarring kost teams echte tijd. De ene herformatteert een waarde zodat twee spellingen van hetzelfde adres overeenkomen; de andere probeert te beantwoorden of het adres bestaat en bezorgbaar is. Ze gebruiken verschillende gegevens, falen op verschillende manieren, en — in een testsuite — verdienen ze volledig verschillende assertions.
Dit artikel scheidt de twee, legt uit waarom geen enkele autoriteit een complete wereldwijde adreslijst bezit, en beschrijft wat een systeem eerlijk kan beweren nadat het een van beide heeft uitgevoerd.
Wat normalisatie werkelijk doet
Normalisatie is een herschrijving. Het neemt wat een gebruiker typte en produceert een canonieke versie ervan: consistente casing, uitgebreide of afgekorte straattypen volgens één conventie, gestandaardiseerde richtingswoorden, een consistent scheidingsteken, bijgesneden witruimte, en een postcode in één afgesproken vorm. Niets wordt geverifieerd. Een reeks die nooit met een echte locatie overeenkwam, normaliseert net zo netjes als een correcte.
De waarde ervan is vergelijking. Twee records die dezelfde plek beschrijven maar anders zijn getypt, worden na normalisatie byte-identiek, zodat deduplicatie, matching en zoeken gaan werken. Het stabiliseert ook de opslag: één vorm in de database betekent dat downstream-consumenten de regels niet opnieuw implementeren.
Normalisatie is goedkoop, deterministisch en veilig om overal uit te voeren. Die combinatie is waarom het hoort op de vroegste grens die de gegevens overschrijden — de formulierafhandelaar, het importscript, het API-toegangspunt — en slechts één keer. Herhaaldelijk normaliseren in verschillende lagen is hoe een waarde tussen twee spellingen gaat schommelen.
Wat probeert validatie werkelijk te bewijzen?
Validatie vraagt of een waarde aanvaardbaar is, en het eerlijke antwoord hangt volledig af van hoeveel bewijs je hebt. Drie verschillende vragen schuilen achter het ene woord.
De eerste is structureel: bestaan de vereiste velden, zitten de tekens in de toegestane set, is de lengte plausibel. Dit heeft helemaal geen referentiegegevens nodig en kan overal worden gedaan.
De tweede is relationeel: valt de postcode binnen een bereik dat de opgegeven regio gebruikt, is de staatscode daarmee consistent, komt het land overeen met zijn onderindelingscode. Dit heeft referentiegegevens nodig maar geen adresdatabase, en het vangt een groot deel van de echte typefouten op.
De derde is existentieel: staat er werkelijk een gebouw op dit nummer in deze straat. Dit heeft een gezaghebbende lokale dataset nodig, en slechts sommige landen publiceren er een die compleet genoeg is om het te beantwoorden.
De meeste systemen claimen de derde en implementeren de tweede. Dat is niet per se verkeerd, maar het zou een bewuste keuze moeten zijn in plaats van een ongeluk, want het bepaalt wat de foutmelding eerlijk kan zeggen.
| Vraag | Wat ze vraagt | Wat ze nodig heeft |
|---|---|---|
| Structureel | Of de vereiste velden bestaan, de tekens in de toegestane set zitten en de lengte plausibel is | Helemaal geen referentiegegevens |
| Relationeel | Of de postcode binnen een bereik valt dat de opgegeven regio gebruikt, de staatscode daarmee consistent is en het land overeenkomt met zijn onderindelingscode | Referentiegegevens, maar geen adresdatabase |
| Existentieel | Of er werkelijk een gebouw staat op dit nummer in deze straat | Een gezaghebbende lokale dataset, die slechts sommige landen publiceren |
Bestaat er zoiets als een wereldwijde adresdatabase?
Niet één die compleet, gezaghebbend en actueel is. Postoperatoren onderhouden hun eigen bezorggegevens voor hun eigen gebieden, onder hun eigen voorwaarden, en velen publiceren helemaal geen adreslijst op adresniveau. Waar nationale datasets bestaan, dekken ze dat land, in de taal en structuur van dat land. Er is geen enkel register dat een leverancier kan raadplegen om te beslissen of een willekeurig adres ergens op aarde bestaat.
Wat leveranciers werkelijk doen, in verschillende combinaties: hun eigen geaggregeerde referentiegegevens gebruiken, matchen tegen postcodes en bestuurlijke geografieën, plausibiliteitsregels toepassen, en — voor sommige landen — een gelicentieerde lokale dataset gebruiken. Elk daarvan is gedeeltelijk. Een dienst die een adres als geldig rapporteert, rapporteert meestal dat het consistent lijkt met wat de dienst weet, en een dienst die het als ongeldig rapporteert, mist mogelijk simpelweg dekking.
De praktische les is dat “adres geverifieerd” geen claim is die je systeem wereldwijd kan ondersteunen. “Structureel geldig en consistent met de referentiegegevens die ons ter beschikking staan” is een claim die het kan ondersteunen, en het is degene die het waard is in de documentatie te zetten.
Waarom de volgorde ertoe doet: normaliseer, controleer dan
Voer normalisatie eerst uit. Referentiecontroles zijn tegen een canonieke vorm geschreven, dus een niet-genormaliseerde waarde zal ze niet halen om redenen die niets met correctheid te maken hebben: een postcode met het scheidingsteken op een andere plek, een straattype anders afgekort, een casusverschil in een regionaam.
De omgekeerde volgorde is erger dan nutteloos. Als de referentiecontrole eerst loopt en de waarde afwijst, verlies je de kans om een reeks te repareren die slechts slordig was, en de gebruiker ziet een fout waarop hij niet kan handelen. Als ze eerst loopt en accepteert, heb je de normalisatie daarna nog steeds nodig, dus er is niets bespaard.
Een tweede ordeningsregel geldt voor foutafhandeling. Onderscheid “dit kon niet worden geparseerd” van “dit conflicteert met referentiegegevens” van “dit valt niet onder onze dekking”. De drie hebben verschillende berichten en verschillende vervolgacties nodig, en ze in één fout samenvatten is wat adresvalidatie willekeurig laat voelen voor gebruikers.
Voor ontwikkelaars: regels, overschrijvingen en fixtures
Probeer een adres niet met één reguliere expressie te valideren. De variatie zit in de delen waar een reguliere expressie het slechtst in is — straatnamen, unitdetails, niet-Latijnse schriften — en de zekerheid zit in de delen die je tegen een lijst kunt controleren. Bewaar patronen voor de lengte- en tekencontroles, en houd de referentiecontroles in data.
Sta altijd een handmatige overschrijving toe. Referentiegegevens zijn onvolledig en soms fout, en een werkelijk correct adres dat je controleur niet herkent moet leefbaar blijven. Log de overschrijving met de waarde die werd afgewezen, zodat je kunt zien of de controleur verbetert of gewoon mensen irriteert.
Houd normalisatie en validatie als afzonderlijke stappen in je eigen code, met afzonderlijke namen. Een functie die address-check heet en soms zijn invoer herschrijft en soms weigert, is het soort ding dat bugs onnaspeurbaar maakt. Dezelfde scheiding is wat het mogelijk maakt om normalisatie over historische records te draaien terwijl validatie een invoerpoort blijft, een onderscheid dat bekend is voor iedereen die adresgegevens voor testfixtures bouwt.
Beweer voor een testsuite de twee gedragingen onafhankelijk: dat een gegeven rommelige invoer naar een verwachte canonieke reeks normaliseert, en dat een gegeven inconsistent paar velden wordt afgewezen. Wanneer de referentielijst verandert, zou alleen de tweede set tests moeten bewegen.
Volgende stappen
Schrijf in één zin op welke van de drie vragen je systeem vandaag werkelijk beantwoordt, en controleer of je foutmeldingen niet meer claimen dan dat. Voeg daarna een fixture toe voor een correct adres dat je controleur afwijst, en beslis wat ermee moet gebeuren. De adresgenerator produceert waarden die per constructie structureel geldig zijn, wat het een handige positieve basislijn maakt naast de opzettelijk kapotte voorbeelden die je bewaart. Structureel geldig is alles wat ze zijn: die waarden kunnen niet naar een bestemming worden bezorgd en ze bewijzen niets over woonplaats. Voor een doorloop van één makkelijk op te sporen inconsistentie, zie testgevallen voor het afrekenadresformulier.