O problema que async/await não resolve sozinho
Assincronicidade não elimina complexidade; ela muda onde a complexidade vive. Sem uma estrutura explícita, tarefas podem sobreviver ao contexto que as criou, falhas ficam desconectadas e o cancelamento deixa de ser uma garantia para virar uma convenção.
O contrato de um CoroutineScope
Em Kotlin, um scope define tempo de vida e responsabilidade. A concorrência estruturada garante que um bloco só termina quando seus filhos terminam. Isso faz da hierarquia de jobs uma representação do próprio fluxo do programa — e não um detalhe escondido em callbacks.
Falhar junto ou supervisionar
coroutineScope propaga a falha de um filho e cancela os demais; supervisorScope isola essas falhas quando cada tarefa pode produzir valor independentemente. A escolha é semântica: ela deve expressar a regra do domínio, não apenas evitar uma exceção.
Uma heurística prática
Se o chamador precisa do resultado para continuar, mantenha a tarefa dentro do seu scope. Se uma operação precisa sobreviver à requisição, dê a ela um proprietário explícito — uma fila, um worker ou um serviço com ciclo de vida próprio. GlobalScope quase nunca é esse proprietário.
Se esta ideia te ajudou, compartilhe com alguém que também constrói sistemas.