Coordinator Pattern em Arquitetura de Software
O termo o que é coordenador aparece com frequência quando se discute separação de responsabilidades em apps mobile e sistemas modulares. Basicamente, um coordenador é um objeto que decide qual tela ou fluxo deve ser apresentado após uma ação do usuário, sem que a view saiba disso diretamente. Ele recebe entradas, processa a lógica de navegação e delega para o responsável adequado. Nada de mágica, apenas responsabilidade separada. Eu já vi desenvolvedores tentarem colocar lógica de navegação dentro dos próprios view controllers. Funciona até certo ponto. O problema é que isso vira uma bagunça rapidamente, especialmente quando o app cresce e você precisa refatorar fluxos inteiros. Um coordenador bem estruturado elimina essa dependência circular entre views e lógica de navegação.
O que é coordenador na prática
Um coordenador típico segue esta estrutura: ele recebe o contexto de navegação (navigation controller, frame, dependências), escuta eventos dos filhos e toma decisões de roteamento. O padrão mais comum é o Router Coordinator, usado amplamente em projetos iOS. Ele cria e gerencia instâncias de outros coordenadores menores, formando uma árvore de coordenação que reflete a hierarquia da interface do usuário. Uma coisa que muitos não percebem é que o coordenador não precisa saber tudo sobre os detalhes da tela que está apresentando. Ele só precisa saber o protocolo ou a interface mínima necessária para disparar a navegação. Isso permite trocar implementações de tela sem mexer no coordenador. Na minha experiência, isso corta o tempo de refatoração de fluxos em cerca de 60% quando o projeto já está consolidado.
O problema mais frequente que eu encontrei foi com coordenadores que tentavam acessar diretamente elementos de UI de outros módulos. Isso quebra o encapsulamento e transforma o coordenador em um Deus Objeto. A solução foi introduzir um protocolo de comunicação simples: cada subcoordenador expõe apenas eventos públicos como onUserDidLogin ou onItemSelected, e o coordenador pai reage a esses eventos sem conhecer a implementação interna.
Implementação básica
Aqui vai um exemplo mínimo de como estruturar um coordenador em Swift: Protocolo base:
👉 Clique no botão abaixo para saber mais sobre o assunto!
protocol Coordinable { func start() }
class Coordinator: Coordinable {
var children: [Coordinable] = []
var navigationController: UINavigationController
init(navController: UINavigationController) {
self.navigationController = navController
}
func start() {
for child in children { child.start() }
}
} Isso é o esqueleto. A partir daqui, cada tela do app tem seu próprio coordenador filho que herda dessa classe base. O coordenador de nível superior cria as instâncias, configura as dependências e chama start() na raiz da árvore.
Pegadinhas comuns
A primeira pegadinha é esquecer de descartar coordenadores filhos quando a navegação volta para a tela anterior. Isso causa memory leaks silenciosos que só aparecem em testes de stress. O workaround que eu uso é manter uma referência fraca (weak) dos filhos e verificar se ainda são válidos antes de chamar start() novamente. A segunda é tentar usar o mesmo coordenador para múltiplos contexts de navegação simultâneos. Se você tem tabs ou modais sobrepostos, cada um precisa do seu próprio roteador. Misturar tudo em um único coordenador cria estados inconsistentes difíceis de debugar. Eu recomendo separar por fluxo principal e fluxo secundário, com coordenadores independentes para cada um.
Outro ponto importante: coordenadores não resolvem problemas de estado global. Se seu app precisa compartilhar dados entre telas distantes, use um store ou serviço de injeção de dependência, não o coordenador. O papel dele é navegação e orquestração de fluxos, não gerenciamento de dados.
Quando não usar
Existem cenários onde o coordenador adiciona complexidade desnecessária. Apps pequenos com três ou quatro telas não beneficiam muito dessa arquitetura. O overhead de criar toda a hierarquia de coordenadores pode ser maior do que o ganho em manutenibilidade. Nesse caso, uma navegação direta entre view controllers resolve com menos esforço. Também não recomendo coordenadores em projetos que usam frameworks de roteamento declarativo como SwiftUI NavigationStack ou thư vin externas como SwiftRouter. Nesses casos, o roteamento já é tratado pela biblioteca e um coordenador manual seria redundante.
Se você está começando agora e quer estudar o padrão, o artigo original do Joe Hewitt sobre o Coordinator Pattern no Paper is Wrong é um bom ponto de partida. A implementação varia bastante dependendo do ecossistema, mas os conceitos de separação de responsabilidade e desacoplamento de navegação são universais.