Skip to content

PATTERN Cited by 1 source

PR-deployed renderer testing in debug app

Problem

A demo harness for SDUI (like Appcraft Browser) gives you a fast inner loop for renderer development — but it deliberately omits:

  • App-shell context (top-level navigation, tab bars, persistent UI).
  • Real authentication.
  • Real analytics / tracking SDKs.
  • Real feature flags.
  • Real peer-screen interactions (opening other screens, modal stacks, deep-link resolution).

So a renderer that looks fine in the harness might break in the real app. You need an integration-loop testing path that's still fast enough to use per-PR but runs the renderer in production-app context.

Pattern

Use the app's debug build as a "pin a server-side PR and exercise it" harness:

  1. Developer opens a PR with renderer changes.
  2. CI deploys the renderer branch to a staging environment — the production app is configured to be able to reach staging renderers by their PR number (usually via a header or query param that routes to the PR-specific deploy).
  3. Developer launches the debug build of the real Zalando app on a simulator / device.
  4. Developer enters the PR number in the debug app's settings screen.
  5. The debug app sets whatever header / routing config is needed so its server calls hit the PR's renderer.
  6. Developer navigates through the real app and exercises the PR's renderer in full production context.

The cost is:

  • ~1 PR-deploy cycle latency (staging deploy = minutes).
  • ~1 debug-app install (once per device).
  • ~1 config tap (enter PR number).

Appcraft's implementation

Appcraft uses this pattern after the Appcraft Browser inner loop (Source: sources/2024-05-15-zalando-transitioning-to-appcraft-evolution-of-zalandos-server-driven-ui-framework):

"After the development stage, web developers open a PR which allows them to deploy the rendering changes in a staging environment, changes are then validated in a debug version of the Zalando app by incorporating the deployed PR number into the app debug settings. This allows testing in production screens and the actual app environment."

Testing-surface pairing

The post names both inner + outer loop explicitly:

Loop Tool Fidelity Latency
Inner Appcraft Browser Isolated runtime Seconds
Outer PR-deployed debug-app Full app context Minutes
Production Real deploy behind feature flag Full fleet Hours+

All three are complementary; each catches a different class of bug.

Why PR number as the routing key

  • Unambiguous — each PR has exactly one staging deploy.
  • Traceable — the PR number in the app's behaviour maps directly to code review; no out-of-band note needed.
  • Parallel-safe — multiple developers each pin their own PR without conflict.
  • Disposable — merging or closing the PR tears down the staging deploy; the app falls back to production on next launch.

Implementation concerns

Staging infrastructure

You need per-PR staging deployments. This is often built as:

  • CI builds a Docker image per PR.
  • Deploys it to a Kubernetes namespace keyed by PR number.
  • Exposes a URL like pr-12345.appcraft-staging.zalando.com.
  • A load balancer or DNS trick routes the PR number to the right namespace.

Debug-build routing hook

The debug build needs:

  • A settings UI to enter a PR number.
  • Logic to rewrite outgoing API base URLs (or add a header) so relevant calls go to the PR's staging deploy.
  • Ideally, a visible indicator that "I am pinned to PR #12345" so the developer doesn't accidentally demo the dev build to someone assuming it's production.

Security / data

PR-staging environments should use non-production data where possible. Reaching out to production backends from a PR deploy is a common foot-gun.

Adjacent patterns

  • Per-PR-ephemeral-environment pattern (also seen in Zalando's Airflow context as patterns/per-pr-airflow-environment-via-dag-versioning) — same idea at a different substrate.
  • Canary / feature-flag routing — production-only equivalent: same routing-by-ID idea but the ID is a user cohort or feature flag rather than a PR.
  • Appcraft Browser itself is the inner-loop counterpart.

Anti-patterns

  • Only testing in Appcraft Browser — misses app-shell / integration bugs.
  • Only testing via full App-Store releases — eliminates same-day delivery capability.
  • Requiring a production deploy to test — reintroduces the release-bottleneck this architecture is designed to avoid.
  • No visible indicator of PR-pinning — stakeholder demos look like the PR's behaviour is already in production.

Seen in

Last updated · 550 distilled / 1,221 read