Skip to content

PATTERN Cited by 1 source

Parallel rewrite with differential testing

A safe language rewrite of a security-critical library where the new implementation is developed in parallel with the original — both compile, both run, both receive the same inputs — and compatibility is enforced via differential testing (differential fuzzing + extensive integration + unit tests). When the new implementation demonstrates input-output parity under fuzzing plus memory/performance advantages, the old implementation is retired.

Distinct from incremental porting (replace one function at a time), ground-up reimplementation with spec-driven tests (write the tests from the spec), and transpilation (mechanical source-to-source translation).

When to use

Preconditions:

  1. The original implementation is your oracle of correctness — it is "what the consumers depend on," not the spec. Any spec deviations in the original are load-bearing for downstream behaviour.
  2. The library processes untrusted input automatically — the case for memory safety is strong enough to justify the parallel-engineering cost.
  3. The input space can be fuzzed productively (structured formats like MP4, protocol messages, config files) — random or mutation-based inputs reach meaningful states.
  4. The library is cross-platform — rewriting once in a memory-safe language eliminates per-platform divergence that could otherwise become a parser-differential attack surface.
  5. The target language's ecosystem + build-system support is mature enough on the target platforms. For mobile Rust in 2026, the answer is yes; for niche platforms or niche languages it may not be.

The pattern

  1. Freeze the original's contract. The original implementation's observable behaviour (outputs for all valid inputs, error codes for invalid ones) is the oracle.
  2. Rewrite in parallel. New implementation is a greenfield codebase in the new language, following the new language's idioms rather than a line-by-line port.
  3. Differential harness. A fuzzer / test runner feeds the same input to both implementations, compares outputs and errors. Any divergence is treated as a bug in one (usually the new one) and fixed.
  4. Test matrix. Extensive integration and unit tests supplement differential fuzzing with hand-crafted corner cases.
  5. Staged rollout. Run both in production, compare outputs as a shadow, promote the new implementation when the divergence rate hits zero under load.
  6. Retire. Delete the old implementation only once the new one is fully validated on every supported platform.

What makes it different from...

  • patterns/ai-driven-framework-rewrite (Cloudflare vinext): target-API is external (Next.js), oracle is the target framework's test suite ported as executable spec, output-matching is at the application level (page render / behaviour). Here the oracle is the internal existing implementation and the output matching is at function / byte level via differential fuzz.
  • patterns/rust-replacement-of-dynamic-language-hot-path (Cloudflare FL1→FL2): replaces a dynamically-typed implementation (Lua) with a statically-typed one (Rust) on the hot path for correctness + performance. Here both implementations are statically typed (C++ → Rust); the axis is memory safety not dynamic-vs-static.
  • patterns/language-rewrite-for-concurrency (Dropbox Feast→Go, DSQL JVM→Rust): rewrites to get a concurrency model that fits the workload; here the driver is memory-safety for untrusted-input parsing.

Canonical wiki instance

WhatsApp's media-consistency library wamedia:

  • Starting point: 160,000 lines of C++ (excluding tests), already cross-platform (Android / iOS / Mac / Web / Wearables).
  • Endpoint: 90,000 lines of Rust (including tests) — code size inverted, not inflated.
  • Compatibility proof: "We used differential fuzzing and extensive integration and unit tests to ensure compatibility between the two implementations."
  • Outcomes: performance + runtime-memory advantages over the C++ baseline; largest known client-side Rust deployment; deployed to WhatsApp + Messenger + Instagram.
  • Costs: initial binary-size increase from the Rust standard library; long-term investment in build-system support for the diverse platforms WhatsApp supports.

Why not the alternatives

Meta names the choice explicitly: "Rather than an incremental rewrite, we developed the Rust version of wamedia in parallel with the original C++ version." Incremental would have meant mixing C++ and Rust in the same binary with FFI at every boundary — operationally painful, and losing the consolidation advantage that is the whole point of a cross-platform library.

Seen in

Last updated · 319 distilled / 1,201 read