Se você tem o costume de ler artigos, ou estuda sobre padrões de projeto, talvez já tenha visto alguém da comunidade de software comentando sobre o **Singleton**, e seus "males".
*─ "Sendo um padrão de projeto, ele não deveria melhorar a qualidade do código? Por quê seria diferente com o Singleton?"*
Para responder essa pergunta, primeiro precisamos entender que **esta premissa não é verdadeira**. Padrões de projeto, como bem-definidos em meu artigo ***[Descomplicando o Strategy](https://www.softplan.com.br/blog/descomplicando-o-strategy/)***, nada mais são do que um catálogo de soluções a problemas comuns.
Cada padrão de projeto carrega **prós** e **contras**; **benefícios** e **custos** de implementação. No caso específico do Singleton, os mais críticos consideram estes "custos" grandes demais.
Mesmo que nunca tenha ouvido falar deste padrão de projeto, neste artigo, pretendo contextualizar sobre **o que** é o Singleton, **quais os "problemas"** que ele traz para o código, e **quais as alternativas** do seu uso.
## 1. O que é um Singleton?
Para entendermos o "problema" que o Singleton traz, primeiro precisamos definir o que é um "Singleton", visto que a definição do que este padrão representa, muitas vezes, é o que mais confunde aqueles que são a seu favor, ou contra.
Podemos começar com a seguinte afirmação: *uma instância única de determinado objeto durante a vida útil de uma requisição, **não** é um Singleton*. Um Singleton, por definição, é justamente esta instância **acessível globalmente no projeto**.
Análogo às descrições dadas pela GoF (*Gang of Four*), no livro "Design Patterns", podemos elencar **3 características básicas** para definir o que precisamos para criar um Singleton:
1. Ele deve possuir uma única instância durante a vida útil da aplicação;
2. Não deve ser possível instanciá-lo através do seu construtor, que deve ter visibilidade preferencialmente privada;
3. Sua instância deve estar disponível de forma global, no seu projeto;
Estas definições são muito importantes, pois a falha no entendimento do que um Singleton representa pode acabar levando pessoas a não entenderem a acusação de ele ser considerado um ***anti-pattern***.
### 1.1. Anti-Pattern? É de comer?
Anti-Patterns, ao contrário do que soa a primeira vista, não é necessariamente o oposto de um padrão de projeto. Os chamados "anti-padrões", em resumo, são respostas comuns a problemas frequentes, que são normalmente ineficazes e têm um grande risco de serem contraproducentes.
Atenção no detalhe: são "**respostas comuns**", para "**problemas frequentes**". Ou seja, ser um anti-pattern não anula o fato de o Singleton continuar sendo um padrão de projeto.
Os anti-padrões têm mais a ver com o **uso errado de uma solução correta**, do que a solução em si ser algo ruim, ─ apesar de que isso também pode ocorrer.
## 2. O Singleton na prática
O Singleton, como já explicado, provê ao desenvolvedor uma instância única de um objeto, e de escopo global. Abaixo, segue um exemplo de como seria sua implementação utilizando a linguagem de programação Java.
```java=
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null ) {
instance = new Singleton();
}
return instance;
}
}
```
> *Observação: Apesar de na classe de exemplo estar explicitado o nome "Singleton", é importante reforçar que você não precisa mencionar o nome do padrão de projeto no nome da classe, e isso apenas foi feito para exemplificar a sua estrutura.*
O Singleton pode ser uma solução viável, caso você esteja em uma situação em que se apresente esses **dois problemas**:
1. Você **precisa** de uma, e apenas uma, instância de um "*objeto X*".
2. Você **precisa** acessar essa instância de qualquer lugar da sua aplicação.
Caso um dos dois itens acima não fizerem parte das suas necessidades, provavelmente há outra saída para o seu problema.
1. Se você **não precisar de uma única instância**, o construtor de seu objeto não precisa ser privado, basta instanciar seu objeto onde quer que você precise utilizá-lo.
2. Se você **não precisa acessar sua instância de qualquer lugar**, significa que você possui um escopo limitado. Neste caso, uma alternativa seria identificar "*a partir de onde*" é necessário acessar seu objeto.
- *Uma forma de fazer isso, seria criar um campo estático privado que guarde sua instância, e passar este objeto por *injeção de dependência* onde quer que ele seja utilizado. O tema "**injeção de dependência**", e sua ligação com o Singleton, será abordado mais adiante ainda neste artigo.*
### 2.1. Benefícios do Singleton
**É extremamente fácil de acessar**: servindo como uma variável "de escopo global", fica evidente que seu acesso é excepcionalmente simples. Não há a necessidade de transitar a instância do seu objeto por todo o seu sistema.
**Garante que só haja uma única instância**: independente de qual o objeto, ou do motivo, o Singleton vai garantir que exista apenas uma única instância dentro do seu projeto, evitando falhas lógicas que podem envolver esta regra.
Algo interessante de se comentar, que tem direta ligação com os benefícios citados acima, é a sua versatilidade para atuar como uma chave **Mutex** (_**Mut**ual **Ex**clusion_). Em ambientes **[multi-thread](https://towardsdatascience.com/multithreading-and-multiprocessing-in-10-minutes-20d9b3c6a867)**, onde duas ou mais operações podem entrar em concorrência, a instância da "chave" se mantém sendo uma só e isso facilita no controle de execuções.
Evidentemente, o Singleton em sí não está isento de concorrências, e precisa de um [tratamento adequado](https://medium.com/@cancerian0684/singleton-design-pattern-and-how-to-make-it-thread-safe-b207c0e7e368) dependendo da linguagem em que está sendo utilizada, para que possa ser considerado uma solução thread-safe.
Se você nunca ouviu falar sobre **Mutex** (também chamados de "semáforos", ou "locks"), mas se interessou pelo assunto, recomendo uma leitura [deste artigo](https://medium.com/swlh/what-is-mutex-6127af8ced4f), para se aprofundar mais.
### 2.2. Custos do Singleton
Fazendo uma breve pesquisa, podemos encontrar **vários artigos** de **diferentes autores** comentando sobre vários **custos de implementação** que envolvem a implementação de um Singleton. Dentre os mais discutidos, e que mais considero interessantes abordar, são:
1. Quebra dos **princípios SOLID**;
2. Fator "**falta de rastreabilidade**";
3. **Dificulta** na implementação de **testes**;
4. Sacrifica **transparência**, por **conveniência**.
Para tornar mais fácil a digestão do que cada problema representa, acho importante haver uma separação em pequenos tópicos. Assim, fica mais fácil o entendimento e há uma boa distinção entre eles.
#### 2.2.1. Ele quebra os princípios SOLID
O primeiro dos nossos problemas, e mais comum de se ouvir quando se trata do Singleton, é que ele quebra os princípios do [*SOLID*](https://www.softplan.com.br/blog/solid-evolua-orientacao-a-objetos/). Para ser mais exato, o **Princípio da Responsabilidade Única** (*SRP - Single Responsability Principle*).
O seguinte trecho é responsável pelo problema:
```java=
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
```
Isto ocorre pois, além de o Singleton ter o controle do ciclo de vida do objeto (sua instância interna), ele também garante o acesso deste mesmo objeto. Com esses dois fatores somados, acabamos com **duas responsabilidades**.
─ *"O que deveria ser feito para que não houvesse a quebra do **SRP**?"* ─ Em resumo, a responsabilidade de popular o `instance` deveria ser delegada para outra classe; exatamente uma das propostas de outro padrão de projeto, conhecido como **Monostate**.
Se gostaria de saber mais sobre o SRP, e entender o porquê ele é importante, recomendo a leitura do nosso artigo "[*Conheça um dos princípios SOLID mais importantes: Single Responsibility Principle*](https://www.softplan.com.br/blog/single-responsibility-principle/)", escrito por meu colega, **Pacifique Mukuna**.
#### 2.2.2. Falta com rastreabilidade
Suponha que você está em uma situação em que precisa **criar** e **controlar** as **instâncias de um usuário** de um determinado sistema, e que apenas **um usuário** pode estar conectado por vez. Uma possibilidade seria a de criar uma classe "gestora" dessa instância de usuário conectado.
Existem algumas alternativas possíveis para seguir com o desenvolvimento, criar um Singleton servindo como a "*classe gestora*" é uma delas. Assim, não seria necessário se preocupar com as partes do sistema que precisarão consumir este usuário conectado: basta recuperar a instância da classe gestora, que é acessível de qualquer lugar do projeto.

Agora, podemos fazer uma reflexão: "*Neste sistema, qual o objeto que pode alterar o usuário que está conectado?*" Parece fácil: "*O Gestor*" ─ provavelmente seria a primeira resposta.
Refletindo um pouco mais na solução, podemos observar um detalhe muito importante sobre este desenho: **a classe gestora é acessível de qualquer lugar do sistema**. Portanto, **a solução implica que o usuário pode ser alterado de qualquer local** também.
Indo um pouco mais além neste exercício, podemos esquecer a classe "*usuário*", e substituí-la pelo "**Objeto Genérico X**", que constantemente é modificado pelos objetos que o chamam.

Observe que conforme o nosso objeto **Gestor** é utilizado, mais comum passa a ser o fator "**falta de rastreabilidade**".
A questão aqui é mais filosófica do que prática. O fato é que por mais que seja justificado o seu uso, podemos concluir que há duas questões absolutas e intrínsecas neste padrão de projeto:
1. Você **não pode garantir** que as propriedades do seu objeto não vão mudar, **quando não deveriam mudar**. Neste quesito, o **acesso global** é o fator que torna muito difícil prever o uso indevido do Singleton;
2. Como consequência do anterior, se houver uma **modificação indevida** nas propriedades do seu objeto, é **extremamente complexo** de identificar o ponto em que está havendo a alteração, principalmente em grandes aplicações onde operações que modificam as propriedades do objeto são comuns.
#### 2.2.3. Torna difícil a implementação de testes
Atenção: Não estou dizendo que "**o Singleton é difícil de testar**", mas sim que ele "**torna difícil a implementação de testes**". Isto, geralmente, no código que o consome.
Para não me estender nesta explicação, considere que para ter o entendimento do porquê o Singleton dificulta a implementação de testes, é necessário ter uma base do que são [testes automatizados](https://www.softplan.com.br/blog/beneficios-dos-testes-funcionais-automatizados/), em especial **testes unitários** e como eles são implementados.
Mas, de forma resumida, um teste unitário consiste nas seguintes ideias:
- **Testar uma classe de forma isolada**: se todas as partes de um determinado sistema estiverem funcionando isoladamente, não deveria haver problema quando reunidas. [Porém este é um assunto discutível, e depende da intenção do desenvolvedor](https://martinfowler.com/bliki/UnitTest.html).
- **Testar de forma independente**: além de testar a classe de forma isolada, cada teste deve ser absolutamente independente um do outro. Independente da ordem de execução, todos os testes precisam passar.
- **Testar de forma rápida**: por consequência dos pontos anteriores, os testes unitários têm a peculiaridade de serem de pequeno escopo, e portanto são de rápida execução.
São a base daquilo que na engenharia de software é conhecido como "[pirâmide de testes](https://martinfowler.com/articles/practical-test-pyramid.html)" ─ e em ordem de prioridade, são aqueles que deveriam existir em mais abundância, nos projetos.
<img src="https://i.imgur.com/DtfOPb4.png" alt="Exemplo da pirâmide de testes" style="display: block; margin: 0 auto" height="400"/>
----
Agora, para entendermos o problema que o Singleton pode apresentar durante a **execução de um teste unitário**, podemos recuperar a ideia descrita mais acima, sobre existir uma "classe gestora" do usuário conectado: vamos chamá-la de `RegistroUsuario`. Além disso, levemos em consideração que determinado sistema possui um serviço com a seguinte verificação:
```java=
public class Servico {
public boolean usuarioPodeCadastrarNovosClientes() {
// Obtém a instância do Singleton
RegistroUsuario registroUsuario = RegistroUsuario.getInstance();
// Guarda o usuário conectado no sistema em uma variável
Usuario usuarioLogado = registroUsuario.getUsuarioLogado();
// Faz um retorno indicando se o usuário conectado tem a permissão
return usuarioLogado != null && usuarioEhAdmin(usuario));
}
private boolean usuarioEhAdmin(Usuario usuario) {
return "ADMIN".equals(usuario.getPermissao());
}
}
```
O serviço acima é relativamente simples, e apenas verifica se o usuário conectado no sistema atualmente possui permissão para cadastrar novos clientes. O método deve retornar **VERDADEIRO** se houver um usuário conectado, e este usuário possuir a permissão "**ADMIN**".
Se você já tem o costume de criar testes, facilmente conseguirá identificar três possíveis cenários:
- ...**ou** o usuário **é** `ADMIN`;
- ...**ou** o usuário **não é** `ADMIN`;
- ...**ou não tem usuário conectado**.
Podemos criar uma classe de teste unitário para automatizar estas verificações, como no exemplo abaixo:
```java=
public class ServicoTest {
private Usuario usuarioAdmin = new Usuario("ADMIN");
private Usuario usuarioComum = new Usuario("COMUM");
private Servico servico;
@Before
public void setUp() {
this.servico = new Servico();
}
@Test // Quando não há usuário conetado.
public void teste01() {
RegistroUsuario.getInstance().setUsuarioLogado(null);
Assert.assertFalse(servico.usuarioPodeCadastrarNovosClientes());
}
@Test // Quando há usuário conetado, mas não possui permissão.
public void teste02() {
RegistroUsuario.getInstance().setUsuarioLogado(usuarioComum);
Assert.assertFalse(servico.usuarioPodeCadastrarNovosClientes());
}
@Test // Quando há usuário conetado, e possui permissão.
public void teste03() {
RegistroUsuario.getInstance().setUsuarioLogado(usuarioAdmin);
Assert.assertTrue(servico.usuarioPodeCadastrarNovosClientes());
}
}
```
Acontece que os testes unitários, na maioria dos casos, **rodam em paralelo por serem independentes** ─ e é exatamente neste ponto que o Singleton passa a ser um problema.
A execução em paralelo faz com que os testes executem modificações no Singleton em concorrência, e quando `teste01`, por exemplo, for realizar o *assert* da informação, invocando o método do serviço, é bem provável que outro teste, como o `teste02`, já tenha modificado o valor do Singleton novamente, o que causaria um **falso-negativo** no *assert* do `teste01`.
Talvez o gráfico abaixo facilite em elucidar o exemplo descrito acima:

Retomando o segundo item elencado sobre a definição de um testes unitário: **os testes devem ser independentes**. Portanto, em alguns casos, é extremamente difícil de testar unitariamente um código que consome um Singleton, principalmente se o Singleton tiver uma ligação direta com o retorno do método que você está testando.
#### 2.2.4. Sacrifica transparência, por conveniência
No artigo "[Singletons são mentirosos patológicos](https://testing.googleblog.com/2008/08/by-miko-hevery-so-you-join-new-project.html)", de **Misko Hevery**, é dado um bom contexto através de testes de qual é o problema aqui: Singletons, dentre muitos outros problemas, podem tornar excepcionalmente dificeis análises e descoberta de cadeias de dependências.
O exemplo utilizado por Hevery **pode ser considerado um tanto extremo**, e talvez realmente seja por ser um caso bem particular de um evento que ocorreu com ele enquanto desenvolvia para a Google, mas o seu principal ponto continua sendo válido: Singletons nada mais são do que um **estado global**. Estados globais fazem com que seus objetos possam secretamente se **apossar de coisas que não são declaradas em suas interfaces** e, como resultado, Singletons transformam suas interfaces em **mentirosos patológicos**.
Assim, podemos interpretar a frase "*sacrifica transparência, por conveniência*" como sendo algo comum de variáveis de escopo global, por não haver explícito as dependências na interface do código que consome o Singleton.

Análogo à imagem acima, podemos dizer que o método `fazAlgumaCoisa()`, do **Objeto A**, não sabe que o `fazOutraCoisa()`, do **Objeto B**, utiliza o Singleton ─ e novamente, isto torna excepcionalmente complexo análises de cadeias de dependências.
Hevery, em especial, fez [uma palestra para a **Google Tech Talks**](https://www.youtube.com/watch?v=-FRm3VPhseI), em 2008, que eu super recomendo uma visita se você entender inglês, e se interessou pelo assunto. Na palestra ele aprofunda, dentre vários outros tópicos do vídeo, justamente o fato de ele considerar Singletons uma má prática.
## 3. Singleton *versus* Monostate
O **Monostate Pattern**, ou simplesmente "**Monostate**", foi um padrão de projeto proposto por **Robert C. Martin**, em seu artigo **Singleton and Monostate**, em 2002, como uma proposta "*Clean Code*" de um Singleton.
Este padrão de projeto propõe guardar uma instância única de um objeto, e prover acesso global à esta instância ─ assim como o Singleton, porém com algumas pequenas diferenças:
- Seu construtor deve ser **público**;
- Seus métodos **não podem ser estáticos**;
- Deve possuir uma **propriedade estática privada**, para guardar a **instância do objeto** desejado.
```java=
public class Monostate {
private static Object instanciaDoObjeto;
// ...demais propriedades
public Monostate() {}
public void setInstanciaDoObjeto(Object objeto) {
Monostate.instanciaDoObjeto = objeto;
}
public Object getInstanciaDoObjeto() {
return Monostate.instanciaDoObjeto;
}
// ...demais métodos
}
```
Observando a estrutura de sua implementação, podemos notar que o **Monostate**, além de precisar ser instanciado onde quer que seja utilizado, ele não controla o ciclo de vida da instância de seu objeto, e portanto, este controle também deve ser implementado pelo código que o consome. Isto trás para quem o utiliza três vantagens principais:
1. Não quebra o **Single Responsability Principle** do **SOLID**, e por consequência, temos à disposição [seus benefícios](https://www.section.io/engineering-education/introduction-to-solid-principle/);
2. Por precisar ser instanciado para consumir a **instância única** do objeto, que é privado em relação ao Monostate, pode ser considerado uma solução **mais transparente** que o Singleton;
4. Mesmo que haja concorrência de chamada do `getter` do Monostate, não existe nenhum controle interno que crie uma instância para você. Isto implica que é **mais difícil** de ocorrer o problema de serem criadas instâncias de forma não-intencional do seu objeto ─ e se ocorrer, provavelmente é relacionado à invocação do `setter`, no **código que o consome**.
Em questão de comparação, não existe muito no que se debruçar aqui. Costuma-se dizer que o Monostate e o Singleton **são dois lados de uma mesma moeda**, com o detalhe do tipo de categoria que cada um cai: o Monostate é um padrão de projeto do tipo **comportamental**, e o Singleton **criacional**. Ainda assim, vale o conhecimento para julgar qual o melhor padrão de projeto, e para qual situação.
Ficou curioso? Quer saber mais sobre o **Monostate**? Leia o artigo completo do **Uncle Bob** sobre este assunto em: [**SINGLETON and MONOSTATE**](https://drive.google.com/file/d/12CwbCGnYVMfTtPn5hEHuBAS9GqJR69Kb/view?usp=sharing).
## 4. Singleton *versus* Injeção de Dependência
Enquanto uma das maiores premissas do Singleton é a sua conveniência, **transparência** é a chave da **injeção de dependência**.
A lógica por trás deste tópico, é bem simples de se entender: se uma classe ou método **requer um determinado objeto** para efetuar as suas operações, este objeto **deve** ser injetado como uma dependência.
Reescrevendo o método `usuarioPodeCadastrarNovosClientes()`, do serviço descrito mais acima, podemos ao invés de recuperar o usuário de um Singleton, tornar explícito a dependência que o método **precisa** de um `Usuario`. Isto também é conhecido como "*passar objeto por referência*".
```java=
public class Servico {
public boolean usuarioPodeCadastrarNovosClientes(Usuario usuario) {
return usuarioLogado != null && usuarioEhAdmin(usuario));
}
private boolean usuarioEhAdmin(Usuario usuario) {
return "ADMIN".equals(usuario.getPermissao());
}
}
```
O serviço **não precisa se preocupar de onde vem o usuário**. Esta é uma preocupação que o cliente ─ aquele que consome este serviço, deve ter.
Com esta pequena alteração, o serviço passou a ser:
- **Transparente**: está claro quais as suas dependências, e como ele as manipula;
- **Fácil de testar**: sem o uso do Singleton, o nosso problema de execuções de testes em paralelo deixou de existir;
Por último, **injeção de dependência** também serve para causar reflexões em quem está escrevendo o código, e que podem dar alguns *insights* bem bacanas.
Um exemplo seria refletir se o nosso método `usuarioPodeCadastrarNovosClientes` realmente precisa do objeto `Usuario`, ou talvez apenas a `String` de permissão baste? Aliás, será que realmente é necessário um método no nosso serviço para fazer essa verificação? E se o próprio objeto `Usuario` possuir um método interno para validar esta regra? Questões como essas são 100% pertinentes, e podem naturalmente ocorrer a partir do momento em que estiver explícito as dependências daquele trecho de código.
## 5. Opinião do autor
Como comentado no início deste artigo, todo padrão de projeto possui **custos** e **benefícios de implementação** (trade-offs). É importante conhecer o "*lado bom*" e o "*lado ruim*", antes de julgarmos ou defendermos uma ideia.
Eu escrevi este artigo, em grande parte, pois cada lugar que eu pesquisava encontrava uma informação nova, e com pouquíssimas explicações que justificassem o que estava sendo dito. Este artigo, portanto, serve como material de estudo para consolidar todas essas informações em um local centralizado.
A maioria dos autores se posiciona de um lado, mas às vezes não tem jeito: existem situações em que você **precisa** de uma única instância de um objeto, e essa instância **precisa** ser de escopo global. Mas mais importante do que **precisar usar alguma coisa**, é entender direito **como essa "coisa" funciona**.
### 5.1. Agradecimentos especiais
Fazer este texto foi especial para mim, e muita gente me ajudou para chegar neste resultado. Por isso, queria deixar um agradecimento para algumas pessoas, pois é graças a elas que posso dizer que estou extremamente satisfeito com o ponto que o artigo chegou.
Gostaria de agradecer, primeiramente, à **minha esposa**, por perder tanto tempo lendo e relendo as 50 versões deste texto. Mesmo sem ser da área, ela foi uma peça muito importante e foi um dos meus maiores motivadores para continuar escrevendo. Queria agradecer também aos meus colegas, [**Fernando Costa Leite**](https://www.linkedin.com/in/fernando-costa-leite/), e [**Felipe Pereira Maragno**](https://www.linkedin.com/in/felipemaragno/) por terem me dado alguns valiosos feedbacks durante o desenvolvimento do artigo, e ao **[Fabio Domingues](https://www.linkedin.com/in/dominguesfabio/)**, e **[Francisco Hillesheim](https://www.linkedin.com/in/francisco-hillesheim-19299825/)** por apoiarem na escrita das vantagens que o Singleton traz para o desenvolvedor, bem como agregarem na ideia de *solução thread-safe*. Por último, mas não menos importante, também queria agradecer ao [**Cleidir Cristiano Back**](https://www.linkedin.com/in/cleidir-cristiano-back/), [**Vinicius Roggia Gomes**](https://www.linkedin.com/in/vinigomes/), e [**Renato Mendes Viegas**](https://www.linkedin.com/in/renato-viegas/) por revisarem o resultado: vocês foram peças fundamentais para o refinamento do artigo.