Methods & Patterns
Key software development methods and design patterns, covering everything from continuous integration and testing to architecture.- Design Tokens
changedDesign tokens have reached adopt status across all teams. Our token pipeline is fully automated: design changes in Figma trigger token builds that publish to npm, CocoaPods, and Maven. The W3C Design Token Format ensures portability, and our theming system — previewed in Storybook — supports brand-specific and market-specific customizations.
What Are Design Tokens
Design tokens are the atomic values of a design system — colors, spacing, typography, border radii, shadows, and motion parameters — expressed as platform-agnostic data. Instead of hardcoding #0E0E12 in CSS or UIColor(red: 0.05, ...) in Swift, every team references color.background.primary, and the token pipeline resolves it to the correct value for each platform.
This indirection is what makes theming, white-labeling, and dark mode possible without touching application code.
Our Token Architecture
Figma (source of truth)
└─ Figma Variables API
└─ Token Transformer (CI)
├─ CSS Custom Properties → npm (@porsche-digital/tokens-web)
├─ SCSS Variables → npm (@porsche-digital/tokens-scss)
├─ Swift Asset Catalog → CocoaPods
├─ Kotlin Compose Theme → Maven
└─ JSON (raw) → S3 (runtime theming)
The pipeline runs on every merge to the design system's main branch. Token packages are versioned with the design system — a color change is a minor bump, a renamed token is a major bump.
Token Categories
Category
Examples
Count
Color
color.background.primary, color.text.secondary, color.accent.success
84
Spacing
spacing.static.small, spacing.fluid.medium
16
Typography
font.size.text.small, font.weight.bold, font.family.primary
22
Border
border.radius.medium, border.width.thin
8
Shadow
shadow.elevation.low, shadow.elevation.high
4
Motion
motion.duration.fast, motion.easing.standard
6
Theming
Our token structure supports layered theming:
Global tokens — raw values (blue-500: #178BFF)
Alias tokens — semantic mappings (color.accent.primary → blue-500)
Component tokens — scoped overrides (button.background → color.accent.primary)
Dark mode is a theme layer that remaps alias tokens. Market-specific themes (e.g., China market) override a subset of globals. This three-tier approach means a single component can render correctly across all theme combinations without conditional logic.
Adoption Journey
Q1 2024: 911 team piloted tokens in the configurator frontend — replaced 200+ hardcoded color values
Q3 2024: Figma Variables API integration automated the design-to-code pipeline
Q1 2025: All four teams adopted the shared token packages; manual color/spacing values in code reviews became a blocking finding
Q3 2025: W3C Design Token Community Group format adopted for interchange; runtime theming via JSON tokens deployed to CDN
Lessons Learned
Name tokens semantically, not visually — color.text.primary survives a rebrand; color.dark-gray does not
Lint for hardcoded values — our Stylelint plugin flags raw hex colors and pixel spacing as errors
Version tokens with the design system — decoupling caused painful mismatches before we unified versioning
Document every token — our token reference site is auto-generated and includes visual previews, usage guidelines, and migration notesread more… - Trunk-Based Development
changedTrunk-based development is now adopted by all four teams. The Cayenne team completed their transition from GitFlow this quarter. Organization-wide deployment frequency is up 300% year-over-year, and our change failure rate has dropped below 5%. Feature flags have become a core part of our development culture.
How It Works For Us
Every developer commits to main (or a short-lived branch that merges within 24 hours). There are no develop, release/*, or hotfix/* branches. The workflow:
Developer creates a feature branch from main
Work happens in small increments — PRs are typically under 200 lines
CI runs on every push: lint, typecheck, test, build (via GitHub Actions)
After code review approval, the branch merges to main
main is always deployable — broken builds are treated as P0 incidents
Feature Flags
Feature flags are the enabler that makes trunk-based development safe for large features:
LaunchDarkly manages our flags across all environments
New features ship behind flags from day one — no long-lived branches
Flags are cleaned up within 2 sprints of full rollout (enforced by a scheduled reminder)
We maintain ~40 active flags at any given time; our maximum was 65, which we agreed was too many
DORA Metrics
Metric
Before (GitFlow)
After (Trunk-Based)
Deployment frequency
Weekly
Multiple daily
Lead time for changes
2-3 weeks
1-2 days
Change failure rate
12%
4.5%
Mean time to recovery
4 hours
25 minutes
These improvements came not from trunk-based development alone, but from the practices it forced: smaller changes, better CI, feature flags, and continuous deployment.read more…
- Architecture Decision Records
changedADRs have moved to trial. The Taycan team has joined the 911 team in maintaining decision logs. We have created a shared ADR repository that aggregates decisions across teams, enabling cross-team visibility into architectural direction. The MADR template has been customized with Porsche-specific sections for compliance and security impact.
What Are ADRs
An Architecture Decision Record captures the context, decision, and consequences of a significant technical choice. Unlike meeting notes or Slack threads, ADRs are version-controlled, searchable, and persistent — they answer "why did we choose X?" months or years after the decision was made.
Our ADR Process
Propose — developer creates a PR with a new ADR in docs/adr/ using our MADR template
Discuss — team reviews the ADR asynchronously (minimum 2 reviewers, one from outside the proposing team)
Decide — ADR status is set to "accepted" or "rejected" with the decision rationale
Supersede — when a decision is revisited, the original ADR is marked "superseded by ADR-XXX" and a new ADR captures the updated context
Template Structure
Our customized MADR template adds two Porsche-specific sections:
# ADR-042: Migrate from Datadog to Dash0
## Status: Accepted (2025-03-15)
## Context
[What is the issue? What forces are at play?]
## Decision
[What is the change that we're proposing?]
## Consequences
[What becomes easier or harder?]
## Compliance Impact ← Porsche-specific
[Does this affect data residency, audit logging, or regulatory requirements?]
## Security Considerations ← Porsche-specific
[Attack surface changes, credential management, network exposure?]
Impact So Far
Since adoption:
38 ADRs written across the 911 and Taycan teams
3 decisions revisited — the ADR history made it easy to understand the original context and evaluate what changed
Onboarding accelerant — new team members read the last 10 ADRs to understand the architectural landscape faster than any wiki page could convey
The Cayenne and Macan teams are expected to adopt ADRs in the next quarter as part of a broader documentation standardization effort.read more… - Event-Driven Architecture
changedEvent-driven architecture continues in trial with the Cayenne team joining. Our event catalog now documents 40+ domain events with schema validation enforced at publish time. The pattern has enabled several new cross-service features that would have been impractical with synchronous REST calls, such as real-time inventory updates across dealer networks.
Event Infrastructure
Our event backbone runs on Amazon MSK (managed Kafka) with the following setup:
Schema Registry — Confluent Schema Registry enforces Avro schemas at produce time; incompatible schema changes are rejected before any event is published
Event Catalog — an AsyncAPI-based catalog auto-generated from our schema definitions, documenting all events with producer/consumer ownership
Dead Letter Queue — failed events route to a DLQ with automatic retry policies (3 retries with exponential backoff, then alert)
Key Domain Events
Event
Producer
Consumers
Volume
vehicle.configured
Configurator
Pricing, Analytics, CRM
~50K/day
order.status.changed
Order Service
Dealer Portal, Notifications, Analytics
~5K/day
inventory.updated
Inventory Service
Dealer Portal, Search Index
~200K/day
user.action.tracked
Frontend SDK
Analytics Pipeline, Personalization
~2M/day
Lessons Learned
Schema evolution is critical — we enforce backward-compatible changes only. Adding optional fields is fine; removing or renaming fields requires a new event version.
Idempotency by default — every consumer must handle duplicate events gracefully. We use event IDs for deduplication.
Observability matters more — debugging async flows is harder than REST. We trace events end-to-end using OpenTelemetry correlation IDs, visible in Dash0.
Start with choreography — we avoided a central orchestrator. Services react to events independently. This keeps coupling low but requires clear event ownership documentation.read more… - WebAssembly
new
HiddenWebAssembly enables near-native performance for compute-heavy tasks in the browser. The Cayenne and 911 teams are trialing it for specific modules where JavaScript performance is a bottleneck.
The Cayenne team has compiled their 3D vehicle configurator's rendering pipeline to WebAssembly using Rust and wasm-bindgen. The result: frame times dropped from ~16ms to ~4ms for complex material calculations, enabling smooth 60fps rendering on mid-range mobile devices that previously struggled at 30fps.
The 911 team is experimenting with WebAssembly for client-side telemetry data processing — aggregating and filtering large datasets locally before sending summaries to the server, reducing bandwidth usage by ~80% for power users with extensive driving history.
Both teams use wasm-pack for the Rust-to-WebAssembly compilation pipeline, with TypeScript type definitions auto-generated from the Rust source. Bundle size overhead is manageable: the Cayenne rendering module adds ~120KB gzipped.
Key constraints we have identified: debugging WebAssembly is still significantly harder than JavaScript, and the compilation step adds build complexity. We restrict WebAssembly usage to isolated, performance-critical modules with clear interfaces — not general application logic.read more…
- Pair Programming
changedPair programming is being re-evaluated. With AI-assisted coding tools like GitHub Copilot becoming prevalent, the dynamics of pairing have shifted. Only the 911 team still practices regular pair programming. We are reassessing how pairing integrates with Copilot-augmented workflows and whether the traditional model still provides the same value.
The Shift
Before Copilot, pair programming served two primary functions:
Real-time code review — catching bugs and design issues as they're written
Knowledge transfer — spreading codebase familiarity across team members
Copilot has partially absorbed function #1 — it catches typos, suggests correct API usage, and fills boilerplate. But it cannot replace function #2, which remains the most valuable aspect of pairing for us.
Current Practice (911 Team)
The 911 team pairs 2-3 times per week, typically for:
Complex debugging sessions — when a bug spans multiple services or involves subtle race conditions
Architecture discussions — designing new features at a whiteboard, then immediately implementing the skeleton together
Onboarding — new team members pair with seniors for their first 2 weeks, working on real tasks rather than synthetic exercises
They use Tuple for remote pairing, which provides low-latency screen sharing with native drawing tools.
Open Questions
Does "Copilot + solo developer" produce comparable output to "pair without Copilot"?
Should pairing sessions focus exclusively on design and review, leaving implementation to solo+AI workflows?
Is the social/mentoring benefit of pairing worth the 2x developer cost in an AI-augmented environment?
The 911 team is running a structured comparison through Q3 2025: alternating sprints with and without mandatory pairing, measuring defect rates, velocity, and developer satisfaction.read more…