O controle de fluxo é uma das primeiras lições que aprendemos ao programar. Existem muitas formas de realizar esse controle, sendo o if a mais comum. Sua estrutura é bem simples:

1if condicao { 
2    // Bloco executado se verdadeiro
3} else { 
4    // Bloco executado se falso
5}

Dessa forma, controlamos o programa baseando-nos em expressões booleanas de maneira direta. A regra é clara: desviar o fluxo se algo é verdadeiro, caso contrário, executar o bloco else. Porém, nem sempre o else é importante ou obrigatório.

Você lê mais código do que escreve

Esta é uma verdade fundamental na programação. Ao programar, entender o código existente é tão importante quanto criar novo código. Escrever código limpo não faz diferença para o computador, mas sim para quem lê.

Ter menos blocos else encadeados é uma forma de simplificar o fluxo sem alterar o comportamento, permitindo que outros programadores entendam facilmente a lógica. A sequência das instruções fica mais clara quando não precisamos “pular” mentalmente entre blocos condicionais.

1ok := false
2if ok { 
3    // Este bloco não é executado	
4} else {
5    // Executa aqui
6}

Lemos a linha 1 e em seguida a linha 5, o que adiciona complexidade no entendimento. A situação piora quando temos blocos if aninhados:

1ok := false
2ok2 := true
3if ok { 
4    // Este bloco não é executado	
5} else {
6    if ok2 {
7        // bloco aninhado!	
8    }   
9}

Agora temos múltiplos níveis de aninhamento, tornando o código muito difícil de entender! Através da supressão do else, podemos ter algo mais simples que expressa a mesma ideia funcionalmente.

É importante entender que podemos ignorar o else na maioria dos cenários, embora existam situações onde ele é mais útil.

Tudo se resume à quebra de fluxo

A questão é que muitos cenários onde o else é utilizado não representam um desvio obrigatório de fluxo. Um exemplo claro é o seguinte:

1offset := 0
2if custom > 0 {
3    offset = custom 	
4} else {
5    offset = 10
6}

Neste caso, não é uma questão de controle de fluxo, mas sim de inicializar uma variável com um valor padrão de acordo com uma configuração. É muito código para algo simples. Podemos simplificar assim:

1offset := 10
2if custom > 0 {
3    offset = custom 	
4}

O comportamento não muda e fica muito mais direto de entender. No caso dos blocos aninhados:

1ok := false
2ok2 := true
3if ok { 
4    // Este bloco não é executado	
5}
6if ok2 {
7   // Executa aqui	
8}

Agora ficou mais simples! Ao entender que o else não é necessário, melhoramos significativamente a legibilidade do código.

Early Return é seu amigo

Outro padrão comum é o controle do retorno de função através do else:

1func shouldRender(page Page) string {
2    if page.Draft {
3        return page.Content
4    } else {
5        return ""
6    }
7}

Que pode ser reescrito como:

1func shouldRender(page Page) string {
2    if page.Draft {
3        return page.Content
4    }
5    return ""
6}

O else pode ser ignorado porque apenas o if precisa ser executado. Mesmo que haja um bloco mais extenso de código dentro do else, a refatoração terá o mesmo efeito. O early return é uma ferramenta muito útil para simplificações, pois geralmente o bloco else pode ser totalmente ignorado.

Falhe rápido

Outro cenário comum é utilizar o padrão fail fast, ou seja, falhar cedo. Não vale a pena manter longos blocos se eles não serão executados em caso de falha.

 1func shouldRender(page Page) error {
 2	if err := Validate(page); err != nil {
 3        return err
 4    } else {
 5        if err := RenderPage(page); err != nil {
 6            return err
 7        } else {
 8			return nil
 9        }	
10    }
11}

O else está sendo usado para manipular o fluxo, tornando o código complexo. É como se o código estivesse tentando todos os caminhos, mas nem todos são válidos, pois não representam alterações de estado ou algoritmo. Seguindo a regra de remover os else, temos:

1func shouldRender(page Page) error {
2	if err := Validate(page); err != nil {
3        return err
4    }
5    return RenderPage(page)
6}

Agora a intenção fica mais clara e direta, sem indireções desnecessárias.

Então quando podemos usar o else?

É claro que existem casos onde o else é essencial:

1if config.fileWriter { 
2    // Caso tenha sido configurado
3    writeToFile(data)
4} else {
5    // Executa um writer padrão
6    writeToConsole(data)
7}

No exemplo acima, a escrita sempre é executada, utilizando diferentes estratégias. A escrita em arquivo é uma exceção e o padrão é utilizado para outros casos. O else é necessário porque faz parte do fluxo do programa como um todo.

Outros cenários onde o else faz sentido:

  • Validação de dados: Quando você precisa tratar casos válidos e inválidos de forma diferente
  • Configurações alternativas: Quando diferentes configurações levam a comportamentos distintos
  • Lógica de negócio complexa: Quando a lógica realmente requer dois caminhos mutuamente exclusivos

Benefícios de evitar o else

  1. Código mais legível: Menos níveis de aninhamento
  2. Menos complexidade ciclomática: Reduz a complexidade do código
  3. Mais fácil de testar: Menos caminhos de execução
  4. Melhor performance: Menos saltos condicionais
  5. Código mais funcional: Segue princípios de programação funcional

Concluindo

Programar é um ato não só de instruir o computador, mas de comunicação. Existem diferentes formas de executar operações, e sempre devemos preferir as mais diretas e com menos controle desnecessário.

O else não é um vilão, mas na maioria dos casos é desnecessário. Aprender a identificar quando ele pode ser removido é uma habilidade valiosa que melhora significativamente a qualidade do seu código.

Lembre-se: código limpo é código que comunica claramente sua intenção. Às vezes, menos é mais.