Writing
Field notes from shipping iOS.
45 essays on SwiftUI, concurrency, testing, performance — and how to use AI in a codebase you still respect in the morning.
2026
SwiftData in 2026: what's production-ready and what still hurtsA practical assessment of SwiftData on iOS 26: what works well, what is still rough, migration pitfalls, and when Core Data remains the safer call.10 min readModular iOS apps with Swift Package Manager: real boundaries, real build timesHow to break an iOS app into Swift Package modules that actually improve build times and team velocity, without over-engineering the dependency graph.11 min readNavigationStack in production: deep links, programmatic navigation, and state that survivesHow to use NavigationStack for real apps: wiring deep links, managing programmatic navigation paths, and keeping state restoration reliable across interruptions.11 min readSwiftUI design handoff: turning Figma into maintainable UIHow designers and iOS engineers can turn Figma work into tokens, components, states, and interaction rules that survive implementation.11 min readBeta testing iOS apps: TestFlight feedback loops that find real issuesA practical TestFlight process for finding product, performance, onboarding, and release-risk issues before they reach production.9 min readiOS observability beyond crash reportingCrash reports tell you where the app died. Good observability tells you why releases degrade, which flows fail, and where users lose trust.9 min readState restoration on iOS: making interrupted flows reliableHow to preserve navigation, drafts, pending work, and user trust when iOS interrupts your app at the least convenient moment.9 min readDesigning agentic iOS features with clear user controlA practical model for agentic app features: explicit user intent, bounded tools, visible progress, confirmation points, and recoverable actions.6 min readFoundation Models in production: practical boundaries for on-device AIHow to decide which Foundation Models features belong on device, when to use Private Cloud Compute or a server model, and how to design reliable failure paths.12 min readKeeping a personal codebase clean when AI makes code cheapAI makes it easy to generate more code than a personal project can absorb. The fix is boring: smaller diffs, hard deletion, strict boundaries, and refusing to let experiments become architecture.10 min readA practical setup for AI-assisted Apple-platform developmentThe day-to-day wiring that makes coding agents useful on iOS, macOS, and the rest of the Apple stack: repo rules, MCP layer, local tools, sessions, and the boring checks that keep the build green.13 min readUsing MCP and coding agents without losing controlMCP can make coding agents much more useful, but only if teams treat tools as controlled capabilities instead of handing the model every sharp object in the repo.8 min readPrompting coding agents for iOS work: tighter briefs, smaller diffs, better resultsHow to use coding agents for iOS development without drowning in technical debt. Focus on contextual briefs, bite-sized tasks, and a strict review loop.5 min readReviewing AI-generated iOS code without lowering the barAI-generated iOS code should be reviewed with the same standards as human code: product behavior, lifecycle edges, concurrency ownership, tests, architecture, and production diagnosis. Faster typing is not a quality model.13 min readCode review for Swift teams: what to standardize and what to stop arguing aboutSwift code review works better when teams standardize the decisions that affect correctness, architecture, testability, and ownership — and stop relitigating harmless style preferences in every pull request.11 min readXcode build times: what actually helpsXcode build times improve when teams reduce work, make dependency invalidation boring, split targets with discipline, measure clean versus incremental builds, and stop treating DerivedData folklore as a strategy.11 min readiOS CI that stays fast as the app growsFast iOS CI is not a GitHub Actions trick. It is a product of small schemes, deterministic tests, ruthless caching, useful sharding, and a refusal to let slow checks become everybody’s problem.10 min readWhy iOS apps start feeling flaky after launchFlaky apps are rarely cursed. They usually rot after launch because teams stop measuring reality, ignore lifecycle edges, treat networking as happy-path plumbing, and let small product decisions quietly break trust.10 min readFinding memory leaks in iOS apps without wasting a day in InstrumentsMemory leaks are not solved by staring at Instruments until the graph confesses. Start with ownership, reproduce the leak, prove deallocation, then use Instruments for the cases that actually deserve it.11 min readLogging on iOS: useful structure, sane defaults, and better debuggingMost iOS logging is either print spam that nobody reads or silence that hides the bug. A reasonable logging setup is small, structured, and actually useful when something breaks at 2 AM.8 min readConcurrency boundaries in networking and persistenceMost concurrency bugs in iOS apps are not race conditions in the textbook sense. They are boundary violations: the wrong actor touching the wrong layer at the wrong time.10 min readOffline-first on iOS: sync, conflicts, and earning user trustOffline-first is not a checkbox. It is a contract with the user about what happens when the network disappears, how conflicts get resolved, and whether their data is actually safe.9 min readSwiftUI forms that stay manageable as the product growsA maintainable SwiftUI form is not one giant view with thirty bindings and a prayer. Split by section ownership, keep drafts local, validate with intent, and stop letting product growth turn basic data entry into sludge.9 min readModeling app state so SwiftUI updates stay predictablePredictable SwiftUI starts with boring state boundaries: keep ownership clear, derive local view state instead of sharing giant models, and stop letting one write ripple through half the app.10 min readImage loading on iOS: caching, decoding, and the mistakes that make scrolling worseA practical image-loading setup for iOS: cache the right thing, decode off the main thread, control request churn, and stop blaming scrolling jank on the collection view.11 min readBuilding a SwiftUI design system without overengineering itA useful SwiftUI design system is not a giant abstraction layer. It is a small set of tokens, components, and rules that make product work faster without hiding the platform or freezing the app in theory.9 min readDeep links on iOS: a setup that stays maintainableA maintainable deep-linking setup comes from one rule: treat links as app routes with typed parsing, ownership boundaries, and tests, not as random URL handling scattered across the codebase.11 min readSnapshot testing in 2026: when it helps, when it lies, how to keep it saneSnapshot tests are useful when they protect stable UI or serialization contracts, but they become expensive noise the moment they start standing in for design review, product judgment, or weak lower-level tests.10 min readiOS testing strategy: test boundaries, promotion rules, and trustworthy signalA useful iOS testing stack is less about tool choice and more about test boundaries, promotion rules, and keeping slow checks rare enough that people still trust the signal.11 min readFeature flags: safe rollouts without shipping fearA practical feature flag setup for iOS: separate release, experiment, and kill-switch flags, keep evaluation deterministic, and avoid the cleanup debt that turns rollout safety into product entropy.10 min readBackground tasks in 2026: what works, what gets throttled, and how to be reliableA practical guide to background work on iOS in 2026: where BGTaskScheduler helps, where the system throttles you, and how to design refresh and processing flows that stay reliable on real devices.11 min readSendable pitfalls: what actually breaks, and how to redesign safelySwift 6 surfaces Sendable problems exactly where values cross isolation boundaries. Here is what usually breaks, how to classify each error, and how to redesign ownership without hiding the problem behind @unchecked Sendable.10 min readActors in practice: safe shared state without "actor everywhere" nonsenseA practical guide to Swift actors: where they help, where they hurt, and how to isolate shared state without turning your app into async soup.10 min readSwift 6 strict concurrency migration: the staged plan that won’t brick your appA practical migration plan for Swift 6 strict concurrency: baseline warnings, isolate boundaries, fix Sendable issues, and tighten checks without stalling delivery.10 min readSwiftUI lists that don’t lag: identity, diffing, and avoiding layout thrashMost SwiftUI list “performance problems” are self-inflicted: unstable identity, accidental view churn, and heavy layout work in rows. Here’s how to make lists fast, measurable, and boring.7 min readAGENTS.md for iOS: guardrails that stop AI from breaking your appTreat AI as a powerful, unreliable teammate. An AGENTS.md file gives it constraints, workflows, and verification steps that keep your iOS codebase stable and your PRs reviewable.5 min readSlash commands that save hours: /build /test /perf /release-notes for iOSTurn repetitive iOS workflows into reliable one-liners. Define a small set of slash commands that run the right builds, tests, and checks, and generate release notes without ceremony.5 min readCodex workflow for iOS: guardrails, repeatable loops, and how to keep the build greenA practical Codex-assisted workflow for iOS teams: define guardrails, run tight build and test loops, measure impact, and ship changes without breaking CI.7 min readNetworking in modern iOS: typed endpoints, retries/backoff, and observability without bloatA practical URLSession setup that scales: typed endpoints and decoding, retry rules that do not create duplicate side effects, and lightweight logging/metrics so you can measure reliability and latency.6 min readA fast, non-flaky iOS test setup: unit speed and stable UI testsA pragmatic iOS testing setup: keep unit tests fast, make UI tests stable, and add one verification loop that catches regressions without turning CI into a lottery.5 min readApp launch performance in 2026: first-frame thinking, cold-start budgets, and practical fixesA practical way to measure iOS cold start and ship improvements: define a first-frame budget, diagnose the common failure modes, and verify changes with repeatable runs.6 min readStoreKit subscriptions in the real world: entitlements, edge cases, and recovery strategiesA practical StoreKit 2 approach for subscription gating that survives renewals, grace periods, restores, and the weird stuff you only see after launch.8 min readSwiftUI animations that don’t glitch: transactions, explicit vs implicit, and performance-safe patternsA practical SwiftUI animation guide: how transactions actually work, why animations disappear, and how to ship smooth UI without expensive re-renders.4 min readSwiftUI Observation performance: stop unwanted re-renders and measure what mattersPractical patterns for @Observable, avoiding accidental invalidations, and proving performance wins with measurement (not vibes).5 min readSwift Concurrency in Practice: Async/Await and ActorsPractical Swift concurrency patterns for async/await, actors, MainActor, Sendable, cancellation, and building responsive iOS apps without data races.5 min read