Johannes Neutze
Engineering Manager in the merchant organization at DoorDash / Wolt. Munich.
I lead a team that owns merchant-facing workflows. Right now that is a greenfield CRM, built by a 10-person cross-functional team I lead, owning engineering and product; I founded and hired its three-engineer backend core from zero. Before that, my team owned the order workflows that 150k+ merchants in 25+ countries run their business on. I came up through Android engineering, and I still pick the boring, reversible option most of the time — the rejected alternative is usually the interesting part of the story.
High-scale platform reliability
I ran Zalando’s mobile developer platform team: the CI/CD, release tooling, and developer-productivity systems every mobile team at the company built on, for apps with 20M+ monthly active users. The work that mattered was measurement before opinion — a developer survey to pick the targets, then Gradle Enterprise and XCMetrics to get real baselines. The first data showed iOS builds taking 18 minutes on CI against 4 on a laptop: the CI hardware was two generations behind, and builds ran three threads on six available CPUs.
Release engineering is where most of my judgment goes, and the merchant application at Wolt is where it ran: a two-week release train on the client against continuous deployment on the backend; a 1% global canary ahead of full rollout; feature flags for per-market enablement; a documented rollback to the last stable build, used inside 24 hours when a data-usage regression appeared. A weekly SLA-based crash review sits on top of it. I started it with one engineer, and it grew into the team’s standing quality review.
I also ran a 24x7 incident-responder pool for a whole mobile organization, to a 15-minute response target and a 99.9% crash-free-users SLO across 10+ mobile teams. Its five Android and five iOS engineers came from outside my reporting line, and the pool was senior-only by written policy and oversubscribed, so I picked the rotation rather than filling it. Through Cyber Week I commanded incident response for mobile under a release freeze already in force, enforcing it in the build tooling and running a second stream that admitted only risk-assessed changes, merged back without an outage.
Systems architecture
The teams I lead work in Kotlin and Scala on Kafka, gRPC and REST, integrating with Salesforce and a merchant onboarding platform. What I bring to these systems is the architecture call. My hands-on depth started in mobile, where the instinct for release risk and client-edge constraints comes from, and stays in use in what I run at home, further down this page. The call that recurs across four companies is reuse over rebuild — the incremental, reversible option instead of the impressive one, with the alternative named and costed:
- The Tazz migration. After Wolt acquired Tazz, a Romanian delivery company, I led the engineering for moving its 5k+ merchants and 12k+ venues — commissions, contracts, banking and KYB (know-your-business) records — onto the platform. I routed it through the existing merchant onboarding service instead of writing a faster bulk importer, trading throughput for every legal and compliance check still running. Data mapping, the compliance questions and the contract terms were closed before implementation started, and the one legal question that did not resolve went into the plan as explicitly open. On a migration whose dominant failure mode is bad data, the sequence is the design. It landed a week early with no production incidents raised.
- The Tazz import, rerunnable before the first run. I made that a requirement before anything ran, and sized ingestion to what the downstream services could absorb rather than to what the import could push, because pushing at source capacity is how a migration takes out the systems it feeds.
- Asynchronous startup on hardware I could not replace. When the merchant app went onto low-cost handhelds already in merchants’ hands, the fleet ran out of memory at startup. I directed the decomposition of the startup path into asynchronous stages instead of asking for new devices.
- The commission-sync connector. I chose the Kafka platform the company already ran over standing up new infrastructure for it, and routed the output into the finance registry that already carried SOX compliance. Nothing new had to be procured, secured or operated, and the audit trail stayed in the system auditors already test. The connector routes and does not transform: writes are idempotent, and it checks the per-record sequence before applying one, so a redelivered or late event never overwrites newer state with older.
- An engineering-owned boundary instead of vendor convenience. On the same platform I held the architecture line against a vendor-first ownership model pushed for speed, keeping core business logic and integrations in systems we own. It is slower to build, and it is the only thing that keeps the vendor choice reversible. Closing it, I set import-process ownership in writing and conceded a simplified design to keep the engineering non-negotiables: a single engineering-owned adapter for every write, every field that adapter needs, and the vendor accountable for whether the person approving a change is entitled to approve it. That concession is what let the feature ship rather than stall.
- How that boundary was won. I could not win “full vendor versus not” in a workshop with the business side, so I wrote the design document instead, did the depth work with the regulatory and finance functions, and brought in the Head of Product who owned the area, someone with standing on the business side, to argue it with me. I had the technical reasoning; they had the organizational legitimacy an engineering manager did not.
- A rollback that changed the strategy, not just the code. Midway through a public-facing service’s migration off a framework that had lost security support, the new stack started failing live orders once traffic passed a scale threshold, and I rolled it back before full adoption. Rather than push the same approach through again, I shifted the team to prove the new stack in a shadow environment against real production traffic — without it ever serving a request — before routing anything live through it. Slower, and it prevented the incidents a second blind attempt would have hit.
- A sidecar instead of a rewrite. Modernizing a legacy Java calendar app with hundreds of thousands of users, I moved features toward Kotlin alongside the old stack rather than freezing delivery for a rebuild.
- A backend-for-frontend instead of waiting. Through a two-brand merger I put a BFF layer between the rider app and upstream services, so mobile shipped against mock data, on its own timeline, rather than blocking on an upstream refactor — and aligned six codebases on shared patterns, so engineers could move between them without relearning the structure.
- Native instead of cross-platform, in 2016. Rebuilding the rider app, I distilled three predecessor apps into one native build rather than carrying on with the inherited Appcelerator Titanium stack. The cross-platform stack had already proven hard to maintain in an acquired company’s codebase, and not repeating that was the constraint — alongside low data consumption, because couriers were on prepaid plans.
- Layered architecture, built once. Presentation, domain use cases, data behind repositories, dependency injection scoped per feature — the same layering on both the native Android and iOS apps of a regulated digital-health product, so authentication, networking and persistence were built once rather than per screen.
Engineering management and team topology
I start teams from scratch, inherit them mid-flight, and rebuild them when they stall. Two teams from zero to three — Selfapy’s mobile team while I was still writing code, and Merchant CRM’s engineering team, bootstrapped by redesigning the talent profile: splitting one unfillable combined role into separate Salesforce-platform and backend positions. That produced 75+ sourced candidates in week one, and a first final round within 7 days, against a pipeline that had moved nobody in four months. I contributed to 10+ hires across my time at Wolt, three of them roles I owned outright on the CRM team.
I also took a newly acquired team on an interim basis while running the integration it came from, and built its operating model so that I was not the route through it: engineers connected directly to the platform teams they depended on, still executing their own plan six weeks after I handed the team over. At Zalando I took a platform team from two engineers to five, rebuilding from a low of one, and the retention answer there is who grew.
Every formal promotion case I have put forward has landed — a senior engineer to Staff, by closing the specific visibility and stakeholder-communication gap a prior cycle had flagged, and a mid-level DevOps engineer to senior in a job family too new to have a leveling rubric, which meant assembling the evidence a rubric would normally supply. At my manager’s request, and as part of the mandate I was hired into, I also mentored two successive leads of an adjacent team. The second was a former report of mine, so I coached the same engineer first as their manager and then as a peer running their own team. As leads, neither reported to me. When the lead changed, I declined to merge the two teams and held delivery for both, twelve engineers across two squads, six of them my own team, with the new lead running one of them day to day.
On performance I move early and in writing: a concern goes into the next 1:1 and, if it does not land, into a plan with a fixed window and HR in from the start. New joiners get a 360 at three months, so probation is decided on evidence rather than impression.
The mechanisms I care about are the ones that outlast me:
- Decision records as a habit. An RFC and ADR practice plus a documented shortcuts register, so trade-offs stop being oral history and a deliberate short-term debt has a name, an owner and a fix.
- A structural proposal, half of it staffed on purpose with contractors. On Merchant CRM, the combined engineering role could not be filled, so I proposed splitting it into a platform track and a backend track. The platform half was staffed with vendor contractors, funded by another organization: the company did not intend to own that stack long term, so it did not want to hire and develop engineers on it; contractors could start in weeks where a requisition could not; and that side was independent of the engineering core and needed more hands, so overstaffing it was the safe direction. Two vendor leads worked to the requirements and architecture boundary I set, with four consultants executing under them. The cost was the largest engineering group on the program sitting outside my reporting line.
- Delivery across four relationships. I led a migration workstream as a virtual stream across four relationships at once — one direct report, a peer at my own level, and two counterparts on the acquired company’s side I unblocked rather than directed — in a program of thirteen interdependent workstreams. Holding one delivery together across those four was the hard part. With the device stream I ran beside it, that made six people held to one delivery, two of them reporting to me.
- A decision structure for a cross-functional program. I set up steering and working layers with published ownership, and decisions recorded in shared trackers rather than left in private messages, so the program’s calls could be traced after the meeting that made them.
- Making the case for a platform function. I first-authored the case to my director for a merchant platform function — a costed team, a proposed scope, and the metrics I was willing to be judged against. A foundations team was later formed on the same rationale, with a backend-services scope rather than the mobile-platform one I proposed. I had a hand in shaping what it covered.
- Headcount cases, in the language of the people who allocate. In every management role since 2017 I have prepared the headcount case — which roles, at which levels, against which work — as the input my manager’s plan is built on. My manager takes it to leadership; my part is arguing for capacity in the allocators’ own terms.
- A gate, not a checklist. When I delivered a merchant consent framework, the durable artifact was not the three consent categories or the revocation flows. It was routing every new third-party cookie through procurement with a data processing agreement. The driver was regulation rather than a usability request — a tax-reporting directive plus marketing-consent law, where the real exposure is failing to deliver a mandatory notice to the correct legal contact. That gate constrains everyone who came after me.
- Covering the staff-engineer seat until it was filled. On that same team I covered the seat through coaching and borrowed cross-team capacity until a staff engineer joined. I reported upward that implementation quality and velocity both improved once they did.
- Capacity argued in the open. Product and I agreed on 30% of the year for technical fundamentals, and 15% for defects, by writing the deferred product work into the roadmap next to it. The same document allocated 0% to UX improvements, which is the part that made the split real — an allocation with no visible loser is a wish written over an existing plan.
- Ownership designed into the process. Rotational release management and feature owners writing their own release notes distribute responsibility structurally instead of routing it through me.
- One name against each piece of work. A subset of the team takes a problem and exactly one person is accountable for it, rather than me directing several engineers individually against the same piece of work. It is the part that scales: adding engineers adds parallel problems with named owners, whereas direct instruction degrades as soon as the team outgrows the manager’s attention.
What I run at home
A small llama.cpp inference stack on an M2 Max, entirely on hardware I own — no cloud model APIs anywhere in it, every endpoint bound to 127.0.0.1. The documents it reads are my own scanned records, so the locality is the requirement rather than a preference. It is personal-scale: five model servers, one machine, one user, no availability target. What it is good for is keeping the architecture muscle in use.
The boundary is the part I would defend in a review. One repo owns infrastructure: model files, ports, GPU layers, batch sizes, how much context the hardware can afford, all declared in a single servers.toml. A second owns the application: what to extract, which prompts, how to judge a result, what to write back. The application never re-declares any of it — it calls GET /props on the running server for the context window it actually has. The obvious alternative is a config copy in the consumer, which is faster to write and correct exactly until the day it silently isn’t. The cost of the choice is real and worth naming: those server keys and ports are now a published interface, so renaming one breaks the consumer at run time with nothing failing in the producer.
Two models and a judge — the pipeline decision I like most is the one that made it slower. For document metadata, two models extract every field independently and a third arbitrates — picks a winner, states a confidence — and only high-confidence results are written back. Everything else goes to a review queue, and the notes I add there get replayed through the arbiter, so correcting it reduces future corrections. One model with a confidence threshold would have been a third of the compute, and it would have meant trusting a number that models are known to be bad at producing. Disagreement between two independent runs is a better signal than either one’s self-assessment.
The honest misses: arbitration triples the inference cost per document — wall-clock and heat on hardware I own rather than a bill, since nothing in the path is metered — and the contract test on that published interface only runs where both checkouts sit on the same machine; anywhere else it skips.
Repositories
Nearly everything I build is employer-owned or private, including everything above. The four projects below are mine, and they are private for now, so nothing here links out yet. Each row is a bundle: everything that belongs to one job, whichever repositories hold it. The three software projects are built the same way. The written target changes first and the code follows it, and none of them deletes anything for good.
| Repository | What it is |
|---|---|
hestia |
Keeps the Downloads folder of a Mac and of a Google Drive in order: files sorted by kind, archives unpacked, documents turned into PDFs, email attachments brought in. Python on the Mac and Apps Script on Drive, held to the same rules by a parity check and by test cases both sides are run against. |
pythia |
The document pipeline behind the section above. A file dropped into an inbox comes out as a searchable PDF/A in Paperless, where two models and a judge propose its metadata. The text-recognition engines were chosen by testing vision models against conventional recognizers on my own documents. |
iris |
Sorts pictures and videos from an inbox by topic, size and date, so the good ones are ready for Google Photos and the rest waits in one pile per reason. It is being rebuilt from its spec, one iteration at a time. |
academia |
Coursework from Technische Universität München, in the problem domain I still work in: the bachelor’s and master’s theses, the paper on circumventing Android protection methods published in the AmiEs 2016 proceedings, and an interdisciplinary project on delivery-time forecasting. |