Skip to content
Selected work

Case study

Performance and resilience on a 50M+ user consumer platform

Four years embedded in a client's iOS team on a large-scale consumer app with millions of daily active users, where crash rate, startup time and release confidence are the job.

Role
Senior iOS engineer, leading 8+ engineers
Platform
iOS + Apple TV
Stack
Swift · UIKit · VIPER / Clean Architecture · Instruments · WebSocket · Protobuf · Fastlane
Period
Dec 2021 – present

Context

A consumer app at this scale sees every device and OS combination in the market. Crash and startup regressions appeared only on specific devices or OS versions and were invisible in the office.

Multiple teams shipped into one codebase on a fixed release cadence, so a regression from one feature could block everyone's release.

My role

  • Hands-on senior engineer on the iOS and Apple TV apps, coordinating a team of 8+ engineers.
  • Owned the crash-triage routine, the modular architecture and the release pipeline; took on-call.

Constraints

  • Client under NDA; the app, its users and its numbers cannot be named here.
  • Releases could not slip for a single team's regression, and fixes had to be verifiable on devices the team did not own.
  • Backend contracts often landed after the mobile schedule needed them.

Key decisions

  1. Decision 1

    A crash-triage routine instead of ad-hoc firefighting

    Every crash is categorised by type, ranked by user impact multiplied by frequency, and the top of the list is reviewed in every release retro. It costs a recurring meeting and discipline; it replaced arguments about priority with a shared list.

  2. Decision 2

    Targeted breadcrumbs and Instruments sessions over blanket logging

    Breadcrumbs were added only around the flows that crashed on specific device and OS combinations, with Instruments used to reproduce startup regressions. Less data than logging everything, but the data that existed was the data needed.

  3. Decision 3

    Feature flags and phased rollouts as the default for risky changes

    Any change touching playback, startup or networking ships behind a flag and rolls out in phases. It adds flag hygiene and cleanup work, and it means a regression affects a fraction of users and can be reverted without a release.

What I built

  • Modular VIPER / Clean Architecture structure that other teams in the codebase adopted, which cut the time for a new engineer to ship a first change.
  • WebSocket-based live updates for real-time surfaces in the app.
  • Protobuf contracts with local Node mocks so mobile work could proceed before backend endpoints existed.
  • Automated UI and unit tests with CI quality gates, and Fastlane release pipelines owned end to end.
Feature moduleVIPER sliceFeature flagremote configCI gatesUI + unit testsPhased rolloutFastlaneCrash reportsbreadcrumbsTriage listimpact × frequencyRelease retroevery releaseLocal Node mocksProtobuf contracts
How a risky change travels: flagged, measured and rolled out in phases, with crash data feeding the triage list that the retro reviews.

Validation

  • Instruments profiling on the affected device and OS combinations to reproduce startup and memory regressions before and after a fix.
  • CI quality gates: automated UI and unit tests must pass before a build is cut.
  • Phased rollout metrics compared against the previous release before widening.

Release and operation

  • Fastlane pipelines for the iOS and Apple TV targets, with release owners rotating across the team.
  • On-call rotation for production issues, with the triage list as the single place a new crash lands.

What changed, and what I'd do next

  • Substantial reduction in crash rate through profiling, breadcrumbs and the triage routine.observed
  • Faster release confidence: regressions caught behind flags and in phased rollouts rather than after full release.observed
  • Modular architecture adopted by other teams working in the same codebase.observed

Measured: a number from logs, analytics or a release pipeline. Observed: seen in production without a formal measurement. Design goal: what the system is built to guarantee.

What I'd do next

  • Automate the impact-times-frequency ranking from crash data so the triage list needs no manual assembly.
  • Extend the local mock approach into contract tests that fail CI when backend and mobile drift.