O padrão Singleton é frequentemente citado como uma má prática, quase um "pecado capital" da programação. Basta abrir qualquer fórum ou rede social técnica e você verá alertas como:
"Nunca use Singleton"
"Singleton é perigoso"
"Evite ao máximo"
Mas será que o problema está no Singleton em si, ou na forma como ele é utilizado — e, principalmente, em onde ele é utilizado?
Spoiler: o problema não é o padrão — é o programador fora de contexto.
Singleton: como destruir seu sistema com um padrão mal usado
Vamos falar sobre o queridinho de muitos iniciantes: o Singleton. Pra alguns, ele é o padrão dos padrões. É só ver um objeto global que já vem a vontade de encapsular tudo num Singleton. Mas aqui é o TheCodeNaked, e a gente vai te mostrar o que acontece quando você se apaixona pelo padrão errado.
Antes de tudo: o que é um Singleton?
Um Singleton é um padrão de projeto que garante que uma classe tenha uma única instância acessível globalmente. Só isso. Parece simples, né? E é. Mas o que parece inofensivo pode virar uma bomba-relógio no seu sistema.
Onde ele realmente é últil?
- Quando você tem um gerenciador de configurações que precisa ser compartilhado em toda a aplicação.
- Quando tem uma instância central de log.
- Quando você precisa de coordenadores de contexto, como um container de dependências muito específico.
Ou seja: quando existe uma razão real, técnica e justificada para ter um único ponto de acesso com estado controlado.
Agora, onde ele destrói seu sistema?
- Quando você usa Singleton só pra facilitar o acesso a alguma coisa.
- Quando você esconde dependências com ele, em vez de injetar explicitamente.
- Quando sua classe vira um Deus objeto, com várias responsabilidades escondidas num Singleton "prático".
E o pior: quando você precisa testar esse sistema.
Singleton e testes: um caso de horror
- O Singleton carrega estado global. Isso significa que um teste pode influenciar o outro, mesmo sem querer.
- Ele torna difícil simular comportamentos, porque é acoplado, difícil de substituir e muitas vezes estático.
- Se você precisar de dois Singletons com comportamentos diferentes em contextos diferentes, boa sorte. Isso vai doer.
Sinais de que você está viciado em Singleton
- "Ah, não quero passar esse objeto por parâmetro, é muito trabalho. Bota num Singleton."
- "Preciso acessar isso de qualquer lugar. Singleton."
- "Não tenho certeza do ciclo de vida dessa classe. Singleton."
Percebe o padrão? O Singleton vira uma muleta. Ele resolve o problema da preguiça, não da arquitetura.
Existem alternativas melhores?
Sim. Se você está usando Singleton só pra compartilhar algo:
- Use injeção de dependência.
- Use contextos bem definidos, onde o ciclo de vida das instâncias está claro.
- Use variáveis locais ou de escopo controlado.
Se você realmente precisa de um Singleton:
- Certifique-se de que ele é thread-safe.
- Certifique-se de que ele não carrega estado que muda com o tempo.
- E principalmente: documente o porquê dele existir.
Conclusão nua e crua
O Singleton não é vilão. Mas também não é herói. Ele é uma ferramenta. E como qualquer ferramenta, pode ser usada pra construir... ou pra destruir.
O problema é que ele é fácil demais. Conveniente demais. E quando algo é conveniente, a gente tende a esquecer de pensar.
Aqui no TheCodeNaked, o conselho é simples:
Se você usou um Singleton porque era mais rápido, você provavelmente se arrependerá depois.
Use com sabedoria. Ou melhor ainda: não use, até ter certeza absoluta de que precisa.
No próximo artigo: "Injeção de Dependência não é sobre containers".