Stop Choosing Between coroutineScope and supervisorScope — Fix the Failure Model First
Android teams waste hours debating coroutineScope versus supervisorScope when the real fix is architectural: stop throwing business errors as exceptions. A Result-driven data layer eliminates the debate entirely and prevents the common bug where CancellationException gets swallowed and converted into a spurious business failure.
Kotlin's coroutineScope cancels sibling tasks when one child fails, while supervisorScope isolates failures. But this distinction only matters when business errors propagate as exceptions. Once failures are wrapped in a Result type at the repository boundary, the coroutine sees only a normal return value — no exception, no cancellation, no difference between the two scopes.
The deeper problem is that an exception-driven architecture forces try-catch into every ViewModel and muddles control flow with data flow. CancellationException must always propagate upward as a control signal; catching it accidentally converts a lifecycle event into a business failure, wasting resources and breaking cancellation.
A clean split puts technical exceptions in the Data layer, converts them to Result.failure, and lets the coroutine scope manage only lifecycle, concurrency, and cancellation. The ViewModel then consumes Result like any other data, without a single try-catch.
The entire coroutineScope-versus-supervisorScope debate is a symptom of a deeper design mistake: treating business failures as exceptions rather than as ordinary data. Fix the data layer, and the scope choice becomes a non-issue for business logic.
Kotlin's decision to make CancellationException a subclass of Exception is a recurring footgun. A catch-all `catch(e: Exception)` silently swallows cancellation, and the fix — a dedicated re-throw clause — is easy to forget until a production bug surfaces.
Result-driven architectures invert the typical Android error-handling pattern: instead of exceptions flowing upward and being caught at the UI, technical exceptions are caught at the lowest layer and converted into data that flows upward through normal return channels.