Ga naar inhoud

Alle artikelenArchitectuur

Datacontracten voor ERP-exports

Een taalmodel leest een gewijzigde export zonder morren in, en juist daarom hoort het nooit de poortwachter voor binnenkomende data te zijn. Het contract dat we bij elke batch afdwingen, gaat over vorm, betekenis, volledigheid, timing en eigenaarschap. Een afwijkende batch gaat in quarantaine en wordt niet stilletjes gerepareerd, en het contract wordt later de specificatie voor de migratie.

18 maart 20257 min leestijdGeschreven door Subash NatarajanBronnen gecontroleerd 2 oktober 2026

Op een maandagochtend daalde het matchpercentage van een financeworkflow scherp, en er was niets kapotgegaan. Geen foutmelding, geen alert, geen gestopte job. Een weekendupdate van het ERP had in één export het datumformaat veranderd van dag eerst naar maand eerst. De batch besloeg de eerste negen dagen van maart, dus elke datum erin werd nog steeds ingelezen. Verkeerd. Facturen werden gematcht tegen ontvangsten uit de verkeerde maand, rustig en op volle snelheid.

Was de batch verder gegaan dan de twaalfde, dan was elke latere regel bij het inlezen gestrand en had iemand binnen enkele minuten gekeken. De stille variant had een toevalligheid in de kalender nodig. Over genoeg exports en genoeg upgrades zijn zulke toevalligheden niet meer zeldzaam.

Het herstel kostte een uur. Het vinden kostte het grootste deel van een dag, omdat niets in het ontwerp ervan uitging dat een export van betekenis kon veranderen zonder van vorm te veranderen.

Elke AI-workflow in een operatie leunt op data waarvan niemand heeft beloofd dat ze stabiel blijft: exports die jaren geleden zijn ingepland, velden die voor nieuwe doelen zijn hergebruikt, codes die per land verschillen. Het ERP kan geen contract tekenen. Wij schrijven er toch een, en handhaven het bij elke batch.

Met consumer-driven contracts, zoals Ian Robinson ze in 2006 op de site van Martin Fowler beschreef, legt de afnemer van een service vast waar hij op leunt, en test de aanbieder daartegen. Een legacy-ERP zal nooit de tests van iemand anders draaien. De afnemer schrijft het contract dus en handhaaft het alleen, en de ontwerpvraag wordt welk onderdeel streng genoeg is om dat te doen.

Modellen zijn te vergevingsgezind om het te handhaven

Taalmodellen zijn goed in het lezen van rommelige invoer. Een hernoemde kolom, een nieuw datumformaat, een extra veld: het model redt zich wel. Teams zien dat als een voordeel en laten het model formaatwijzigingen opvangen.

Op een datagrens is het een risico. Een traditionele parser die een gewijzigde export tegenkomt, faalt luid, en iemand gaat kijken. Een model dat dezelfde wijziging tegenkomt, geeft een plausibel antwoord en gaat door, en de fout komt weken later boven in een reconciliatie, ver van de oorzaak. De grens hoort het minst vergevingsgezinde onderdeel van het systeem te zijn. Het model krijgt alleen data die haar al is gepasseerd.

Een model mag de inhoud van een document lezen. Het mag niet bepalen wat de kolommen van een systeemexport betekenen.

Engineers herkennen het principe dat hier sneuvelt. De regel van Jon Postel, in 1980 opgenomen in de TCP-specificatie, zegt: wees ruimhartig in wat je accepteert. Die regel liet de eerste netwerken werken, en voor het lezen van vrije tekst is het nog steeds goed advies. Op een grens tussen systemen heeft hij een bekende prijs, die Martin Thomson en David Schinazi beschrijven in RFC 9413 (2023): een tolerante ontvanger verbergt de fouten van de verzender, de fouten worden het feitelijke formaat, en niemand kan ze later nog herstellen. Een taalmodel is de meest tolerante ontvanger die ooit in productie is gezet. Zet het op de grens en elke wijziging die het ERP maakt, wordt een nieuw formaat dat alleen het model begrijpt, tot de dag dat het er een verkeerd begrijpt.

Wat het contract dekt

De meeste teams schrijven het eerste van deze vijf op en vergeten de rest.

Vorm. Velden, types, formaten, verplichte waarden. Datums in één vastgelegd formaat. Bedragen met een vastgelegd decimaalteken en tekenconventie.

Betekenis. Wat een veld per bron voorstelt. Of "boekingsdatum" in deze markt de documentdatum of de invoerdatum is. Of creditnota's binnenkomen als negatieve bedragen of als positieve bedragen met een documenttype. Twee exports kunnen dezelfde vorm hebben en een andere betekenis, en daarom gaat data uit meerdere markten hier stuk.

Volledigheid. Hoeveel records er moeten binnenkomen en waar ze samen op uit moeten komen. De totalen moeten ergens anders vandaan komen dan uit de export zelf: een aantal en een som uit het openstaande-postenrapport van het ERP, of de controletotalen die de bank in haar afschrift zet. Een export die zichzelf controleert, is het met zichzelf eens. Een batch die qua vorm perfect is en honderd regels mist, is de gevaarlijkste soort, en we houden de controle ook aan voor bronnen die "nooit regels kwijtraken". Elke bron raakt ooit regels kwijt, en dat gebeurt op een dag dat niemand kijkt.

Timing. Wanneer de batch binnenkomt, welke periode hij dekt en wat er gebeurt met records die na de cut-off zijn geboekt. Een workflow die een export leest voordat het magazijn zijn ontvangsten boekt, maakt uitzonderingen aan die eigenlijk alleen vertraging zijn.

Eigenaarschap. Wie aan de kant van de klant een wijziging in de export goedkeurt, en hoe wij dat te horen krijgen. Zonder dit is het contract een document dat niemand leest tot na het incident.

In de praktijk is het contract voor één export één pagina: de velden met type en betekenis, de bronnen van de controletotalen, het leveringsvenster, de controlerecords, de eigenaar en een versienummer.

Harde controles stoppen de batch, zachte controles steken een hand op

Controles op vorm en volledigheid zijn hard: een batch die daarop faalt, gaat niet verder. Betekenis is lastiger mechanisch te controleren, dus voegen we twee soorten zachter bewijs toe.

Het eerste is de vorm van de data in plaats van die van het bestand. Elke batch wordt vergeleken met de laatste weken uit dezelfde bron: het aandeel creditnota's, de spreiding van bedragen, het aantal verschillende leveranciers, de verdeling van datums over de maand. Een omschakeling van dag eerst naar maand eerst laat een vingerafdruk achter. Met de dag eerst gelezen viel elke maartdatum in die batch op de derde van een of andere maand, omdat het dagveld nu het maandnummer bevatte. Een controle op de verdeling van de dagen had de eerste batch gemarkeerd voordat er ook maar één match was gemaakt. Deze controles stoppen een batch niet op zichzelf, want echte veranderingen in het bedrijf verschuiven verdelingen ook. Ze leggen de batch voor aan een benoemde persoon voordat hij wordt verwerkt.

Het tweede zijn controlerecords (sentinels): een handvol bekende records waarvan we weten hoe ze gelezen moeten worden, gecontroleerd bij elke run. Als een bekende factuur van een bekende leverancier ineens een andere datum of een ander bedrag oplevert, is de betekenis veranderd, ook al is de vorm gelijk gebleven. Controlerecords komen voor een afnemer het dichtst in de buurt van de tests aan de kant van de aanbieder die Robinson beschreef.

Afgekeurde batches gaan in hun geheel in quarantaine

Het contract is code. Elke binnenkomende batch wordt ertegen gecontroleerd voordat er enige bedrijfslogica draait. Een batch die faalt, wordt niet half verwerkt en niet op gevoel gerepareerd, ook niet als de oplossing voor de hand ligt. Voor de hand liggende oplossingen die stil worden toegepast, zijn hoe één verkeerde aanname uitgroeit tot een maand verkeerde boekingen. De batch gaat in quarantaine met een reden, en een benoemde persoon krijgt een melding.

Quarantaine voelt traag voor wie doorvoer wil. Een afgewezen batch kost een uur aandacht van iemand. Een verkeerd gelezen batch kost dagen onderzoek en, in finance, een correctiespoor waar de accountants naar gaan vragen.

Quarantaine legt de kosten van een wijziging ook bij de mensen die haar kunnen voorkomen. Als de afnemer elke wijziging stil opvangt, hoort niemand stroomopwaarts dat een upgrade een workflow verderop heeft geraakt, en de volgende upgrade kan hetzelfde doen. Als een batch stopt, komt de vraag terecht waar de wijziging is gemaakt. We rapporteren quarantaines per bron elke maand aan de eigenaar van de export. De eerste maanden is dat getal ongemakkelijk. Daarna daalt het, omdat wijzigingen met aankondiging gaan komen.

Quarantaine van hele batches heeft één echte prijs: één foute regel houdt honderden goede op. Dat accepteren we voor alles wat naar het grootboek boekt. Voor gebruik waarbij alleen gelezen wordt, zoals een dashboard of een triagewachtrij, mag een contract afwijzing per regel toestaan, zolang afgewezen regels worden geteld en die telling net als elke andere tegen de controletotalen wordt gecontroleerd.

Elke bron krijgt een eigen contract

Toen we voor Bredent Medical vier Europese markten koppelden, elk op Dynamics 365 of een legacysysteem, bleek er niet zoiets als één ERP-contract te bestaan. Elke markt had zijn systeem anders ingericht, gebruikte eigen codes en exporteerde op een eigen schema. Eén integratielaag stond voor alle vier, met een contract per bron en een mapping per markt naar één gedeeld model. De contracten hielden die laag betrouwbaar terwijl elke markt zijn eigen configuratie bleef aanpassen. Dat weegt het zwaarst als een bedrijf markten toevoegt: elke nieuwe markt komt binnen als een nieuwe bron, en hoort met haar contract binnen te komen.

Bankdata vraagt dezelfde discipline. MT940-afschriften en ISO 20022-berichten van het type camt.053 bevatten referenties, valutadatums en boekdatums die de kwaliteit van de matching bepalen lang voordat er een model aan te pas komt, en banken veranderen het gebruik van velden als ze tussen formaten migreren. Een contract per bank en rekeningtype, met sentinels, vangt dat voordat de reconciliatie het doet.

Wijzigingen lopen parallel, niet van de ene op de andere dag

Exports gaan veranderen, en soms is de wijziging terecht. Het contract heeft versies, en een geplande wijziging volgt het parallel change-patroon dat Danilo Sato in 2014 op de site van Martin Fowler beschreef: de bron publiceert de nieuwe versie naast de oude, de workflow leest beide en vergelijkt ze gedurende een periode waarin een maandafsluiting valt, en pas daarna wordt de oude versie uitgezet. Een wijziging die niet parallel kan lopen, gaat live met de quarantaine op haar strengste stand voor de eerste batches.

Contracten worden getest met kapotte bestanden

Bij elk contract hoort een set voorbeeldbestanden: goede, en bewust kapotte met een hernoemd veld, een gewijzigd datumformaat, ontbrekende regels of een verkeerd totaal. De grens moet de eerste accepteren en elk van de tweede afwijzen, en dat draait bij elke wijziging in de testsuite. Als de ERP-partner een upgrade inplant, kan het team van de klant een voorbeeldexport uit het testsysteem door de grens halen en binnen enkele minuten weten of er iets breekt.

We spreken ook één regel af met de IT-afdeling van de klant en de ERP-partner: een wijziging in een export die een workflow voedt, loopt via hetzelfde wijzigingsproces als een wijziging in de workflow. Die regel heeft meer incidenten voorkomen dan welke validatiecode die we hebben geschreven ook.

Het contract overleeft het ERP

Dit werk levert iets op waar niemand budget voor reserveert. De meeste bedrijven waarmee we werken, vervangen of upgraden hun ERP binnen een paar jaar. Als dat gebeurt, is het lastigste deel van het project uitzoeken waar elk proces verderop in de keten echt op leunt: welke velden, in welke betekenis, op welk schema. Een bedrijf met datacontracten heeft die lijst al, opgeschreven, getest en onder versiebeheer. Het contract dat werd geschreven om één AI-workflow te beschermen, wordt de specificatie voor de migratie, en de tests met kapotte bestanden worden de acceptatietests voor de exports van het nieuwe systeem.

Luide fouten zijn het doel

Het meeste van wat een AI-workflow in productie betrouwbaar maakt, gebeurt voordat het model iets ziet. Een contract houdt niet tegen dat exports veranderen. Het maakt de verandering luid, en luide fouten worden in een uur verholpen. Stille fouten worden door de accountant gevonden.

Bespreek uw operatie met onze engineers.

Beschrijf één proces en de systemen waarop het steunt. Een senior engineer reageert binnen twee werkdagen met een eerste beoordeling: wat we zouden bouwen, wat niet, en waarom.

Een senior engineer leest elke aanvraag en reageert binnen twee werkdagen.