PATTERN Cited by 1 source
Pilot-component language migration¶
Pattern¶
When considering switching a significant codebase to a new systems language (a "one-way door" decision), do not start with the hardest or most critical component. Instead:
- Pick the smallest / most isolated / most self-contained component whose perf or safety properties are representative of the goal.
- Require it to already have an existing implementation in the current language, to act as the baseline.
- Require any library / client dependencies to already exist in the candidate language.
- Have engineers new to the candidate language do the rewrite — this measures the realistic productivity curve, not best-case expert perf.
- Treat the result as the go / no-go signal for broader rewrite.
Compared to patterns/achievable-target-first-migration, this focuses on cross-language migrations specifically — the risk is productivity and one-way-door commitment, not breadth.
Case study: Aurora DSQL's Adjudicator pilot¶
The systems/aurora-dsql team faced the Crossbar's tail-at-scale problem and had to consider Rust. Rather than start with the Crossbar itself, they chose the Adjudicator — the component that sits in front of the journal and arbitrates conflicts:
| Selection criterion | Adjudicator match |
|---|---|
| Small / self-contained | Yes — much simpler than the Crossbar. |
| Existing baseline | Yes — Kotlin implementation, years of tuning. |
| Dependencies already in candidate lang | Yes — Rust client for the journal already existed. |
| Realistic productivity signal | Yes — assigned to two JVM engineers new to Rust. |
Result:
- Kotlin baseline: 2,000 → 3,000 TPS after years of incremental optimization.
- First-cut Rust port by Java developers, no perf tuning: 30,000 TPS. ~10×.
This single data point flipped the internal question from "should we use Rust?" to "where else could Rust help us?" — and licensed the data-plane rewrite and (later) the control-plane rewrite.
Why this is safer than a full rewrite¶
- Blast radius is small. If the pilot fails, you lose weeks, not years; the bad-case outcome is "we learned something," not "we're mid-rewrite and can't go back."
- Productivity data is real. The only way to know how fast engineers are in language X after ramp is to measure. A pilot produces that number under realistic conditions (new devs, not gurus).
- Perf data is real. No one trusts microbenchmarks for architectural decisions. A real component under real load is signal; a Shootout number is noise.
- Builds internal confidence. Colleagues watching the pilot succeed are far more open to "let's do the rest" than to "let's do a one-year rewrite on a promise."
When not to use this pattern¶
- If no component is small enough to serve as a pilot, you have a decomposition problem, not a language problem — fix that first.
- If the candidate language's ecosystem is immature for your domain, a pilot will mislead. The DSQL post makes this point for their earlier control-plane-in-Kotlin decision: when they re-evaluated, internal Rust library support had caught up (AWS Authentication Runtime's Rust client was outperforming Java); earlier, it had not.
Seen in¶
- sources/2025-05-27-allthingsdistributed-aurora-dsql-rust-journey — Adjudicator chosen as the pilot for JVM → Rust; 10× TPS result licensed the broader data-plane rewrite and later the control-plane rewrite.