01 / INTEGRATION
Making systems agree
Contract design, idempotency, retry and backoff, dead-letter handling, and the unglamorous work of reconciling two sources that both believe they are authoritative.
- REST
- Webhooks
- Queues
- ETL
- OAuth
// hero.sequencecoherence 100% · glyphs 0 · t 0.00s
Almere, NL · CET
Integration Engineer
I engineer software the way a cinematographer lights a scene — everything invisible, nothing accidental.
Dominique Karreman
integration engineer · almere, nl · cet
Most software fails at the boundaries — where one system hands off to another, where an assumption that held on one side quietly stops being true on the other. That is the work I have spent my time on: making systems that were built separately, by different people, at different times, behave as though they were designed together.
I came to engineering through photography. Cinematography teaches you that a frame is a set of decisions — what is in focus, what is exposed, what is left out of shot — and that the best of them are the ones nobody notices. The structure should look obvious in hindsight and unremarkable in use.
I build across the stack: C# and Python where systems talk to each other, Swift when it has to be native, React and Laravel when it has to ship. Four runtimes, one engineer — which mostly means I have learned what each of them is bad at.
Where the eye was trained. Light before code.
Composition as a form of engineering.
Systems that only work if five people read the same play.
Structure you have to feel rather than reason about.
EXHIBITION FLOOR · 04 MACHINES
// selected work
An exhibition floor in a dark building: four machines on a bench, one lamp over each. The room stays unlit until you point at something.
Move over a machine to switch its light on
LEVEL +1 / MACHINE FLOOR
Ducts, conduit, and the parts of a building nobody photographs.
LEVEL 0 / SELECTED WORK
LEVEL −1 / ARCHIVE
Experiments, dead ends, and the versions that did not survive review. Everything upstairs was standing on this.
// capabilities
01 / INTEGRATION
Contract design, idempotency, retry and backoff, dead-letter handling, and the unglamorous work of reconciling two sources that both believe they are authoritative.
02 / BACKEND
Domain modelling, transactional boundaries, and knowing which consistency guarantee a feature actually needs rather than defaulting to the strictest one available.
03 / INTERFACE
State that is honest about being asynchronous, rendering budgets treated as a constraint rather than an afterthought, and interaction that survives a slow connection.
04 / NATIVE
When the platform layer stops being enough — on-device processing, camera and sensor pipelines, and the frame budget that comes with them.
// live — try it
Kill the transform node and the pipeline does not lose your message — it applies backpressure, queues, and retries with exponential backoff until the node returns. Malformed payloads never reach it at all; validation diverts them to the dead-letter queue where they can be inspected instead of silently dropped.
// philosophy
Teams spend their effort on what happens inside a service and their outages on what happens between them. I would rather over-invest in the contract, the failure mode, and the retry semantics than in the elegance of code nobody else will call.
Budgets set at the start are constraints that shape the work. Budgets discovered at the end are bugs with a deadline attached. The sequence at the top of this page is 2.7 MB because that number was chosen before it was built, not measured after.
A queue and a retry will outlive a clever abstraction. Most of what I have shipped that still runs is unremarkable on purpose — the interesting decision was usually choosing not to build the interesting thing.
// source
The scroll-scrubbed sequences were guarded by a boolean set before each seek and
cleared on the seeked event. When a
seek is issued before the video has data that event never fires — so the flag
stayed true and the scrubber was dead for the rest of the session. Trusting the
browser’s own state removes the entire class of bug.
/* Deliberately NOT guarded by a boolean "seeking" flag. A seek issued
before the video has data never fires `seeked`, and a flag set on the
way in then never clears -- one dropped event and the scrubber is dead
for the rest of the session. Trust the browser's own video.seeking and
re-check next frame, so a dropped seek simply gets reissued. */
function syncSeek() {
if (!duration) return;
const t = smooth * duration;
if (Math.abs(t - video.currentTime) <= 1 / 48) { stalled = 0; return; }
if (!video.seeking) {
if (video.currentTime === lastAt && ++stalled > 90) return;
lastAt = video.currentTime;
video.currentTime = t;
}
if (!seekRaf) seekRaf = requestAnimationFrame(() => { seekRaf = 0; syncSeek(); });
}
Every entrance on this page starts clipped to zero height.
IntersectionObserver measures its
ratio after clipping, so the ratio was permanently zero and a
threshold-based observer could never fire. The reveal was hiding itself from the
thing meant to reveal it.
/* threshold MUST stay 0. The resting state clips the element to zero
height, and IntersectionObserver measures ratio after clipping -- so
any non-zero threshold can never be met and the reveal never fires.
isIntersecting is still true, so set the trigger with rootMargin. */
const io = new IntersectionObserver((entries) => {
for (const e of entries) {
if (!e.isIntersecting) continue;
e.target.classList.add('is-in');
io.unobserve(e.target); // an entrance replayed is noise
}
}, { threshold: 0, rootMargin: '0px 0px -14% 0px' });
// github
Message pipeline with contract validation, dead-letter routing and backoff. Placeholder — pending build-time GitHub data.
apertureOn-device exposure and histogram engine for iOS. Placeholder — pending build-time GitHub data.
grainDithering and halftone engine. Produced the sequence at the top of this page. Placeholder — pending build-time GitHub data.
No framework, no font service, no analytics. One dependency — three.js, self-hosted and loaded only for the exhibition scene, on pointer-capable desktop. Two scroll-scrubbed H.264 sequences, one shared scrubber, and a canvas. The numbers above are read from the Performance API on this page load rather than typed in by hand — if they get worse, this section says so. Media keeps counting as you scroll, because the sequences are fetched only when you approach them; a figure captured at load would have flattered the page by several megabytes.