Clean Code
“Desenvolvedores profissionais escrevem código como profissionais, e código escrito por profissionais é código limpo!”
O que é Clean Code (Código Limpo)?
Robert C. Martin (2014), em seu livro “Clean Code” apresenta várias conceituações sobre o que é código limpo. Autores diferentes utilizam palavras diferentes para conceituar, como:
- Bjarne Stroustrup (criador C++): “... O código deve ser elegante...”
- Grady Booch: “... O código limpo é simples e direto...”
- Dave Thomas: “... Além do seu criador, outro desenvolvedor pode ler e melhorar um código limpo...”
- Michael Feathers: “... Um código limpo sempre parece que foi escrito por alguém que se importava...”
- Ron Jeffries: “... Efetue todos os testes, sem duplicação de código, expressa todas as ideias do projeto que estão no sistema, minimiza o número de entidades, como classes, métodos, funções e outras do tipo...”
- Ward Cunningham (co-criador XP): “... Você sabe que está criando um código limpo, quando cada rotina que você leia se mostra como o que você esperava...”
A partir disso, Robert C. Martin (2014), faz uma compilação e busca apresentar um conjunto de características que possam expressar o que é um código limpo, sendo:
- Elegante, fácil de se compreender, e agradável de se ler;
- Simples e direto;
- Segue princípios de programação;
- Sem duplicidade;
- Bem testado;
- Parâmetros, Métodos, Funções, Classes e Variáveis possuem nomes significativos (que revela seu propósito);
- Código é autoexplicativo (sem necessidade de comentários para compreender o código);
- Código bem formatado (é possível ler o código sem precisar utilizar a barra de rolagem);
- Métodos e Classes devem ter uma única responsabilidade (princípio da responsabilidade única).
Regras Gerais de Clean Code
Keep It Stupid Simple (KISS)
Em português, "mantenha tudo o mais simples possível". É um princípio que nos diz que devemos manter a nossa lógica sempre o mais simples possível. Evitando complexidade desnecessária, para que o código seja fácil de ler e fácil de evoluir ou de se dar manutenção. Ainda que as vezes isso possa significar um código maior em número de linhas.
Abaixo segue um exemplo de um código reescrito para seguir tal princípio. O objetivo era ter uma função que retornaria o nome do dia da semana correspondente ao seu número.
No primeiro caso foi utilizado um switch-case para retornar o dia para cada um dos números possíveis (Figura 1).
Figura 1. KISS - switch-case.
Esse código pode ser simplificado utilizado um vetor com os dias, de forma que basta retornar o dia na posição do vetor que corresponder ao número recebido (ver Figura 2). Dessa forma, a legibilidade é melhor e fica mais simples evitar possíveis erros e realizar alterações necessárias. Ficaria mais simples introduzir alternativas de nomes de dias em idiomas diferentes, por exemplo.
Figura 2. KISS.
Regra do Escoteiro
"Deixe sempre o acampamento mais limpo do que você encontrou!". O lema dos escoteiros também serve para o código. Toda vez que um desenvolvedor mexer em um código, deverá deixá-lo mais bem organizado do que como o encontrou. Se todos os desenvolvedores de um time seguirem esse princípio, aos poucos cada trecho de código poderá evoluir.
Para seguir esse princípio os passos são simples. Sempre que um código for ser evoluído, o desenvolvedor deverá primeiro analisa-lo e refletir se não seria possível melhorar algum trecho. Caso seja possível, a melhoria deve ser feita antes das novas alterações.
Causa Raiz
Sempre procure a causa raiz do problema. Por vezes quando surge um novo bug os desenvolvedores implementam correções temporárias, que são rápidas e fáceis de fazer, mas que não corrigem o problema por completo.
Isso faz com que o problema volte a ocorrer e acabe causando um retrabalho ainda maior no futuro. Dessa forma, o ideal é sempre solucionar a causa raiz, mesmo que no momento do erro isso signifique gastar mais tempo.
Utilize nomes descritivos
Nomear bem as variáveis, funções ou classes facilita a leitura e o entendimento do código. Nomes confusos fazem com que os desenvolvedores percam mais tempo tentando entender para que serve cada trecho de código. Dessa forma, vale escrever nomes descritivos, ainda que signifique ter um nome mais longo.
Abaixo temos um exemplo disso. Se uma variável é nomeada "X", não há como entender seu propósito. "Total" já é um nome melhor, mas ainda não descritivo o suficiente. Finalmente, "totalDeRegistros" já é um nome que nos permite ter uma ideia do propósito da variável sem precisar ler o restante do código que estivesse ao seu redor.
Sendo assim, o exercício a ser feito para seguir esse princípio é o de ler todos nomes definidos e refletir se para cada um deles é possível entender o propósito sem a necessidade de entender o restante do contexto (ver Figura 3).
Figura 3. Nomes Descritivos.
Siga as convenções
Se no início do projeto foram definidas convenções siga-as. Coisas como por exemplo usar camelCase para nomes de variáveis, ou escrever constantes em maiúsculo, ou mesmo convenções de idioma. Seguir as convenções pré-estabelecidas ajuda a manter o código fácil de entender para todos os membros de uma equipe, inclusive os mais novos, além de criar um padrão reconhecível.
Para seguir tal princípio, basta tomar o cuidado de seguir as convenções ao escrever novos trechos de código. E para os trechos já implementados, verificar se todos seguem os mesmos padrões.
No exemplo abaixo (Figura 4), podemos ver que cada uma das três funções descritas utiliza convenções diferentes.
Figura 4. Utilização de Diferentes Convenções.
O mais correto, portanto, seria escolher uma das convenções e segui-la consistentemente (Figura 5).
Figura 5. Escolhend uma Convenção.
Don’t Repeat Yourself (DRY)
Em português, "não se repita". Evite repetições de código. Se existe um trecho que é necessário em muitos lugares, este deverá ser transformado em uma função, módulo, ou reescrito de alguma outra forma que permita reusabilidade.
Dessa forma, para seguir esse princípio os desenvolvedores devem procurar no projeto, manualmente ou através de ferramentas automatizadas, por trechos de código que sejam frequentemente repetidos. Essa repetição deve então ser removida, através de alguma das formas citadas.
Escreva funções pequenas e com apenas um objetivo
Funções menores e com poucas responsabilidades são mais fáceis de serem entendidas e reutilizadas. Também fica mais fácil encontrar quaisquer problemas e mudar comportamentos.
Sendo assim, se uma dada função possuí várias responsabilidades, é ideal separar essas responsabilidades entre múltiplas funções. Abaixo é possível ver um exemplo (Figura 6), em que uma função sozinha cuidava de todo um fluxo completo, e poderia ser dívida em múltiplas funções diferentes.
Figura 6. Funções Pequenas e com Apenas um Objetivo.
Uma última dica válida, é que no caso de projetos grandes já em andamento, as vezes pode ser difícil analisar tudo manualmente para ver se os princípios estão sendo seguidos. Para facilitar esse trabalho, podem ser utilizadas as chamadas ferramentas de análise de código estático, que vão conseguir identificar a maior parte dos problemas mencionados automaticamente.
No livro, Martin cita diversos outros princípios. Alguns deles se referindo a aspectos mais complexos da programação, como por exemplo paralelismo. E também a aspectos que não são diretamente do código, como por exemplo estrutura de pastas e arquivos (MARTIN, 2014).
O significado do bom código pode ser subjetivo, mas os princípios do Clean Code são amplamente aceitos pela comunidade desde que foram estabelecidos, e se seguidos à risca certamente tendem a propiciar um aumento significativo na qualidade do produto em questão, dito que esta pode ser diretamente influenciada pela qualidade interna do software (FOWLER, 2019).
Referências Bibliográficas
- MARTIN, Robert. Clean Code: A Handbook of Agile Software Craftsmanship. Nova Jersey: Prentice Hall PTR, 2014.
- FOWLER. Is High Quality Software Worth the Cost? Martin Fowler, 2019. Disponível em: https://martinfowler.com/articles/is-quality-worth-cost.html. Acesso em 28 de jul. De 2021.