Guia Clean Code: Da Teoria à Prática (Parte 1)

Guilherme Manzano
8 min readSep 22, 2021

--

Recentemente, li o livro Clean Code de Robert C. Martin (conhecido como Uncle Bob), que fala sobre como desenvolver códigos seguindo boas práticas de programação, que visam a facilitar a leitura e refatoração do código. Quando estamos escrevendo um código, pensamos apenas em resolver o problema de negócio da forma mais direta que nosso cérebro encontra naquele momento. Porém, quando vamos ler o código produzido com mais calma, percebemos que alguns métodos e classes acabaram ficando confusas, com muitas linhas de código e muitas finalidades distintas. Se mexermos nesse código apenas depois de algumas semanas a situação é até pior, pois esquecemos detalhes que pensamos durante a construção.

Vamos imaginar agora que outro desenvolvedor vai pegar precisar alterar esse código. Não conhecendo a fundo a funcionalidade e a lógica desenvolvida, além de tentar entender um código pouco legível, ficará ainda mais difícil fazer alterações no código sem gerar bugs ou quebrar a aplicação.

Capa do livro. Fonte: https://www.amazon.com.br/Clean-Code-Handbook-Software-Craftsmanship-ebook/dp/B001GSTOAM

Por esses motivos, é muito importante aplicarmos boas práticas e refatorações constantes nos nossos códigos, facilitando a sua manutenção e entendimento por parte de outros programadores ou, até mesmo, de nós mesmo. Vou compartilhar agora alguns pontos principais de aprendizado que adquiri na leitura deste livro, mas recomendo que todos leiam este livro, para aprofundarem seu conhecimento técnico. Como complemento, vou postar um artigo desenvolvendo Clean Code em um pequeno programa em Java, nas próximas semanas.

Qualquer um consegue escrever código que um computador entende. Bons programadores escrevem código que humanos entendem — Martin Fowler

Nomes Significativos

Utilize nomes que revelem seu propósito, o nome de uma variável, função ou classe deve responder a todas as grandes questões. Por exemplo, para definir uma variável que indica um tempo percorrido em dias. Observe a seguinte variável:

int d;

O nome da variável d não explica nada para o leitor do código. O que essa variável faz? Quando utilizá-la? Um nome tão vago dificulta a compreensão do código. Por outro lado, um nome explicativo facilita a compreensão da utilidade da variável e do código propriamente dito, como o exemplo a seguir:

int daysSinceCreation;

O nome de Classes e Objetos precisam ser constituídos de substantivos, como AddessCustomer, CustomerPayment, CustomerData, entre outros. Já os nomes de métodos devem conter verbos (devem exprimir ação) mais substantivos, como findUser, saveFile etc. Além disso, é necessário nomear os métodos de acesso, autenticação e alteração com prefixos como get, set ou is.

Para constantes, utilize apenas letras maiúsculas para defini-las. Não utilize Magic Number, se precisar utilizar algum número no código, extraia-o para uma constante e coloque um nome auto explicativo (qual a finalidade deste número naquela classe/método).

Funções

As funções devem ser pequenas, uma função com centenas ou milhares de linhas torna difícil a leitura, além de toma muito tempo do programador para analisa-lo. De preferência, as funções não devem ter mais que 20 linhas.

Uma função deve fazer uma única coisa apenas (princípio da responsabilidade única). Caso uma função tenha mais de uma responsabilidade, é preciso “quebrá-la” em mais funções, onde cada uma delas exercerá apenas uma função.

Com relação aos parâmetros das funções, o ideal é que elas não tenham nenhum parâmetro. Se isso não for possível, então utilize um ou dois parâmetros para a função. Em casos excepcionais, utilize três parâmetros. Não utilize mais parâmetros que isso em sua função. Os parâmetros são complicados e necessitam de muitos conceitos, além de dificultarem o entendimento do código para outros programadores. Além disso, quanto mais parâmetros, mais trabalho para se escrever os casos de testes da função.

Caso precise utilizar realmente o nome de métodos ou variáveis que não sejam intuitivas, crie uma documentação explicando o que ela está fazendo de fato (por exemplo, utilizando o Javadoc com @param, @return, entre outros , para programas Java).

Tratamento de Erro

Utilize exceções ao invés de retornar códigos de erros, pois vai evitar que o chamador verifique os erros imediatamente após a chamada, gerando problemas caso ele se esqueça de tratá-los.

Utilize exceções não verificadas, pois verificar exceções fere o Princípio de Aberto-Fechado. Por exemplo, se você lançar uma exceção a ser verificada a partir de um método no seu código e o catch estiver alguns níveis acimas, será necessário declará-lo na assinatura de cada um dos métodos entre você e o catch, ou seja, significa que uma modificação em um nível mais baixo do software pode forçar a alteração de assinaturas em muitos níveis mais altos.

Não passe ou retorne null, pois isso exige que façamos tratamento de NullPointerException em muitas partes do código, e esquecer de tratar um dos casos com null irá lançar uma exceção indesejada no seu programa.

Quando for lançar exceções, evite código de erro, lance mensagens claras para quem vai ver aquele código. Extraia o código contigo no try/catch para funções separadas, para melhorar a sua legibilidade.

Classes

Seguindo a convenção padrão Java, uma classe deve começar com as variáveis públicas, seguidas das estáticas, depois as constantes, variáveis estáticas privadas e, por fim, as variáveis privadas. Quanto aos métodos, primeiro devem ser declarados os públicos, depois as privadas.

As classes devem ser pequenas e devem ter uma única responsabilidade. Para saber se sua classe está fazendo muita coisa, nomeie-a descrevendo o que ela faz. Se for necessário usar palavras como “se”, “e’, “ou” ou “mas” no nome da classe, significa que ela possui muitas responsabilidades e deve ser dividida em classes separadas.

Evite passar parâmetros na mesma classe entre os métodos, utilize o this quando for preciso utilizar o valor de uma variável em vários métodos.

Não se repita (DRY — Don’t Repeat Yourself)

Este princípio fala para reduzirmos ao máximo a duplicação de código em nosso projeto. Quando temos código duplicado, além de aumentarmos a complexidade (com mais linhas de código, é preciso mais testes e maiores chances de gerar bugs), se precisarmos alterar um dos blocos de código que se repetem temos que ficar procurando e altera-los. Como vocês podem imaginar, é a receita perfeita para esquecermos de alterar um dos blocos repetidos e causarmos alguns bugs e problemas desnecessário.

Através da Orientação a Objeto, podemos isolar facilmente esses códigos repetidos em métodos e classes específicas, chamando-a toda vez que se precisarmos utilizá-la, evitando a duplicidade.

Deixe o código mais limpo do que você encontrou

É comum termos que modificar um código desenvolvido por outro programa, seja para corrigir um bug, ou para adicionar uma nova funcionalidade. Quando tiver que alterar um código, mesmo que não seja seu, aplique tudo o que sabe de boas práticas e código limpo, facilitando a refatoração e entendimento para os próximos desenvolvedores.

Como a refatoração pode afetar diretamente a lógica da aplicação, é vital que a aplicação tenha testes com uma boa cobertura, que vão garantir que a aplicação não vai quebrar durante as alterações.

Caso a aplicação ainda não possua testes, crie-os! Mesmo que não dê tempo de criar os testes necessários e depois fazer a refatoração, fazer só os testes já irá preparar o terreno para que os próximos programadores façam a melhoria no código.

Comentários
NUNCA utilize códigos comentados. Eles poluem o código e geram confusão em outros desenvolvedores que precisam alterar aquele código. Afinal, aquele código comentado era uma versão antiga? O desenvolvedor estava fazendo alguns testes e esqueceu de apagar os códigos comentados? Eles representam sugestões de refatorações futuras? Representam códigos que serão implementados no futuro? Representam algum tipo de lembrete que ajudam o desenvolvedor a entender o código que escreveu naquela classe?

Como podemos ver, eles acabam atrapalhando bastante a compreensão do código. Além disso, hoje em dia podemos (e devemos) utilizar as ferramentas de versionamento de código (Github, Gitlab, Bitbucket, entre outros), onde podemos facilmente consultar o histórico de alterações .

Evite também utilizar comentários de linhas, pois as funções e variáveis precisam ter nomes autoexplicativos. Além disso, os testes também são uma forma de documentar e que podem deixar um código bem mais explicito do que comentários.

Evite a utilização de condicionais negativos

Condicionais negativos aumentam a complexidade do código, pois o desenvolvedor que está analisando o programa pode não perceber o símbolo de negação na frente (!) e achar que é uma condicional afirmativa. Além disso, ele aumenta a dificuldade de compreensão do código.

Dicas para programas Java

Apesar do livro Clean Code ter sido escrito utilizando a linguagem Java para a construção dos exemplos, resolvi separar todos as dicas que falam de programas Java propriamente dito neste tópico.

Caso você precise utilizar muitas constantes em seu programa, extrai-as para ENUMS para armazená-las. Isso deixará o código das classes mais enxutas, além de permitir reutilizar algumas dessas constantes em outras classes.

As interfaces definem o que uma classe deve fazer, mas não como. Ou seja, elas declaram os conjuntos de métodos, o comportamento que um conjunto de classes deve ter. Quanto utilizamos interfaces, a classe deverá então implementa-las, utilizando todos os métodos presentes na interface. Basicamente, uma interface estabelece um contrato a ser seguido por um conjunto de classes, a implementação dos métodos será feita pelas classes que a implementarem. É recomendado utilizar interfaces na maior parte dos casos, pois elas evitam que ocorram alguns problemas de ambiguidade de métodos e de desempenho. Além disso, elas podem ser utilizadas para especificar o comportamento de um tipo, implementar múltiplas heranças (pois uma classe pode herdar apenas uma outra classe, mas pode implementar várias interfaces) e compartilhar métodos entre várias classes.

No caso de métodos mais complexos, se for necessário acrescentar comentários, utilize o Javadoc para isso, pois eles possuem algumas marcações que facilitam a leitura e busca de informações, além de serem mais fafil de ser encontrados e reunidos.

Durante o desenvolvimento, utilize ferramentas para analisar a quantidade de code smells no seu código, pois elas vão apontar os erros e más práticas no seu código, sempre que você fizer uma nova alteração. Um plugin muito utilizado para isso é o SonarLint, que está disponível tanto para o Eclipse, quanto para o IntelliJ.

Outras dicas

· Evite sempre que possível, o uso de if ou while, pois eles aumentam a complexidade do código. É preferível trocá-los por um método com um nome bem explicativo;

· Não utilizar “wild cards” (coringas) nos imports das bibliotecas, importe cada método de forma separada. Isso evita uma sobrecarga desnecessária na memória, com métodos importados que não estão sendo utilizados;

· Code smell são “mau cheiro” no código, significa que tem algo no seu código que pode não estar seguindo as boas práticas de mercado e código limpo;

· Um dos piores code smells é a distância das linhas do seu código da margem, pois eles simbolizam que aquele código possui muitos if, else, for, que deixam o código mais complexo;

--

--

Guilherme Manzano

Desenvolvedor Java, disseminando um pouco do conhecimento que aprendi, para a comunidade de língua portuguesa. https://www.linkedin.com/in/guilhermemanzano