Performance Runbook
Mobile Performance Runbook
This runbook defines how to profile, validate, and improve runtime performance in apps/mobile.
Scope
- App startup and tab switching latency
- High-frequency rerender paths (home, interview, headers)
- Image decode/cache behavior
- Study session startup reliability (standard and senior modes)
Current Optimizations (Implemented)
expo-imageis used for repeated profile/avatar images withcachePolicy="memory-disk"andcontentFit="cover".- Tab navigator is configured with:
lazy: truefreezeOnBlur: true
- Hot paths moved from whole-store subscriptions to targeted Zustand selectors (
useShallowwhere needed). - Senior mode selection is hardened to avoid non-evaluatable state-dependent prompts when profile context is missing.
Profiling Workflow
- Build and run a dev client (not Expo Go for realistic native behavior):
cd apps/mobilenpm run iosornpm run android
- Record baseline traces:
- Cold start to first interactive screen
- Home tab open, then switch across all tabs twice
- Start one standard practice session and one senior session
- Check for:
- JS thread stalls during tab switches
- Excessive rerenders in home/interview components
- Repeated image fetch/decode instead of cache hits
- Save trace artifacts and device metadata in PR notes.
Acceptance Targets
- Tab switch interaction remains smooth with no visible frame drops on mid-tier Android.
- Home screen re-renders only when selected store slices change.
- Senior practice/exam startup never returns empty sessions when eligible senior questions exist.
- No regression in algorithm test suites and interview API mode tests.
Native Module Roadmap (Performance-Focused)
Adopt modules only after profiling shows a measurable bottleneck.
Tier 1 (Recommended Next)
react-native-mmkv
- Why: significantly faster key-value storage than AsyncStorage for hot reads/writes.
- Use for: frequently updated lightweight state (session metadata, cached counters).
- Caution: requires migration strategy and encryption decision.
@shopify/flash-list
- Why: better list virtualization performance for long/complex lists.
- Use for: large history/result feeds or dense question lists.
- Caution: only worth adding where list rendering is an actual bottleneck.
Tier 2 (Conditional)
expo-sqlite(or another SQLite wrapper)
- Why: better structure/perf for large historical datasets than key-value storage.
- Use for: high-volume analytics/history storage.
- Caution: schema migrations and query abstraction overhead.
@shopify/react-native-performance
- Why: production-grade startup and interaction instrumentation.
- Use for: objective P50/P95 monitoring in release builds.
- Caution: adds telemetry plumbing and dashboard work.
Tier 3 (Specialized)
@shopify/react-native-skia
- Why: highly optimized custom graphics pipeline.
- Use for: heavy custom animated canvases only.
- Caution: avoid unless current UI requirements exceed standard RN/Reanimated capabilities.
Decision Gate Before Adding Any Module
Require all three:
- Measured bottleneck in profiler traces
- Estimated gain and owner for rollout
- Regression test plan (functional + performance)
Without these, keep current stack and optimize code paths first.