Código limpo (clean code)

O código é limpo se puder ser facilmente compreendido

Data de publicação: 24/02/2024 23:52

Última atualização: 10/03/2024 00:23

Criar um software é como qualquer outro tipo de escrita. Programadores veem os sistemas como histórias a serem contadas em vez de programas a serem escritos.

Nosso sistema de valores se foca mais na aparência externa do que no conteúdo que entregamos.


Tópicos



Variáveis:

  • Evite usar nomes inúteis para variáveis.
  • Declare o máximo possível o significado da variável quando for dar um nome a ela.
  • Cuidado em usar nomes muito parecidos, você irá se confundir. Por exemplo, como o desenvolvedor saberá qual função chamar sendo que elas estão declaradas da seguinte forma: getActiveAccount, getActiveAccounts e getActiveAccountInfo.
  • Não se refira a um grupo de contas como accountList, a menos que realmente seja uma List. Use nomes como accountGroup, bunchOfAccounts, ou apenas, accounts.
  • Não use como parâmetro variáveis como a1 ou a2, prefira usar palavras como source ou destination.


Funções:

  • Evite repetição de código.
  • Funções devem ser curtas, bem nomeadas e bem organizadas.
  • As funções devem fazer uma coisa. Devem fazê-la bem. Devem fazer apenas ela.
  • Você sabe que está criando um código limpo quando cada função que você lê é como você esperava.
  • Por exemplo writeField(name) seria um nome bastante claro, denominado como palavra-chave da função.
  • Devem ser pequenas e ter no máximo 20 linhas. Caso ela esteja muito grande, é preciso quebrá-la em outras funções.
  • As funções que recebem argumentos variados podem ser nômades, díades ou mesmo tríades. Seria um erro passar mais parâmetros do que isso. Tenha um máximo de 3 parâmetros.
  • Se uma função chama outra, elas devem ficar verticalmente próximas e a que chamar deve ficar acima da que for chamada, se possível. Deve-se declarar as variáveis imediatamente acima do seu primeiro uso.
  • Se uma função vai transformar seu parâmetro de entrada, a alteração deve aparecer como o valor retornado.
  • As chamadas de if, else e while devem ser pequenas, bem como, não devem ter estruturas aninhadas.
  • Passar um booleano para uma função certamente é uma prática horrível.


Comentários:

  • Comentários imprecisos são muito piores que nenhum.
  • "Oh, é melhor inserir um comentário!". Não! É melhor limpá-lo. Simplesmente, é uma questão de criar uma função cujo nome diga a mesma coisa que você deseja colocar no comentário.
  • Usar somente comentários informativos. Use com moderação.
  • Evite: Informações inapropriadas, comentários obsoletos, comentários redundantes, comentários mal escritos, códigos como comentário.


Estrutura:

  • Evite criar estruturas híbridas que são metade objetos e metade estruturas de dados.
  • Objetos expõem as ações e ocultam os dados.
  • As estruturas de dados expõem os dados e não possuem ações significativas.


Erros:

  • Tratamento de erro é uma coisa só. Portanto, uma função que trata de erros não deve fazer mais nada.
  • Forneça exceções com contexto, crie mensagens de erro informativas e as passe juntamente com as exceções.
  • Não retorne null e não passe null.


Classes:

  • Seguem praticamente, senão o mesmo, conceito das funções.
  • Devemos poder escrever com cerca de 25 palavras uma breve descrição da classe, sem usar as palavras "SE", "E", "OU", ou "MAS".
  • Analogia: Você quer suas ferramentas organizadas em caixas de ferramentas com muitas gavetas pequenas, cada um com objetos bem classificados e rotulados? Ou poucas gavetas nas quais você coloca tudo?
  • Princípio de Aberto-Fechado: As classes devem ser abertas para expansão, mas fechadas para alteração.


Emergência:

  • Efetue todos os testes: criar testes leva a projetos melhores. Você deve ser capaz de rodar todos os testes de unidade com apenas um comando.
  • Quantos testes são suficientes? Uma coleção de testes deve testar tudo que pode vir a falhar.
  • Bugs tendem a se reunir. Quando encontrar um bug numa função, é sábio fazer um teste exaustivo nela. Provavelmente você verá que o bug não estava só.
  • Refatoração: podemos aumentar a coesão, diminuir o acoplamento, separar preocupações, modularizar as preocupações do sistema, reduzir nossas classes e funções, escolher nomes melhores, etc.
  • Sem repetição de código: a repetição representa trabalho, risco e complexidade desnecessária extra.
  • Expressividade: escrever códigos que nós entendemos é fácil, mas outras pessoas que pegarem esse mesmo código não terão esse mesmo grau de conhecimento.


Geral:

  • Evite múltiplas linguagens dentro de um código fonte. HTML, CSS e JS em um arquivo por exemplo. Separe-as.
  • Evite condicionais negativas. Sempre que possível, use condicionais afirmativas. Por exemplo: if (buffer.shouldCompact()) é melhor do que if (!buffer.shouldNotCompact())
  • Encapsule as condições de limite. Por exemplo: if (level + 1 < tags.length) → declare e depois chame-a: int nextLevel = level + 1 if (nextLevel < tags.length).


Conceitos



Filosofia dos 5S:

  • Seiri, ou organização (pense em "ordenar"). Saber onde estão as coisas - usar abordagens como nomes adequados - é crucial.
  • Seiton, ou arrumação (pense em "sistematizar"). Há um antigo ditado americano que diz: "Um lugar para tudo, e tudo em seu lugar". Um pedaço de código deve estar onde você espera encontrá-lo - caso não esteja, refatore e coloque lá.
  • Seiso, ou limpeza (pense em "polir"). Manter o local de trabalho livre de fios pendurados, gorduras, migalhas e lixo. Observação: Livre-se de comentários inúteis.
  • Seiketsu, ou padronização. Concordar em manter o local de trabalho limpo e padronizado.
  • Shutsuke, ou disciplina (autodisciplina). Isso significa ter a disciplina para seguir as práticas e refletir frequentemente isso no trabalho e estar disposto a mudar.


Regra do escoteiro:

  • "Deixe a área do acampamento mais limpa do que como você a encontrou".


Quatro regras do Projeto Simples de Kent Beck:

  • Efetuar todos os testes;
  • Sem duplicação de código;
  • Expressar o propósito do programador;
  • Minimizar o número de classes e métodos.


DRY:

  • Don't Repeat Yourself → Não se repita.


TDD

F.I.R.S.T

  • Rapidez (Fast) → os testes devem ser rápidos. Devem executar com rapidez. Quando os testes rodam devagar, você não desejará executá-los com frequência. E, consequentemente, não encontrará problemas cedo o bastante para concertá-los facilmente. E você não se sentirá livre para limpar o código, que acabará se degradando.
  • Independência (Independent) → os testes não devem depender uns dos outros. Um teste não deve configurar as condições para o próximo. Você deve ser capaz de executar cada teste independente e na ordem que desejar. Quando eles dependem uns dos outros, se o primeiro falhar causará um efeito dominó de falhas, dificultando o diagnóstico e ocultando os defeitos abaixo dele.
  • Repetitividade (Repatable) → deve-se poder repetir os testes em qualquer ambiente. Você deve ser capaz de efetuar testes no ambiente de produção, no de garantia de qualidade e no seu notebook enquanto volta para casa de trem sem uma rede disponível. Caso seus testes não possam ser repetidos em qualquer ambiente, então você sempre terá uma desculpa para o motivo das falhas. E também perceberá que não consegue rodar os testes fora o ambiente adequado.
  • Auto validação (Self-Validating) → os testes devem ter uma saída booleana. Obtenham ou não êxito, você não deve ler um arquivo de registro para saber o resultado. Você não deve ter de comparar manualmente dois arquivos de texto para ver se os testes foram bem sucedidos. Se os testes não possuírem auto validação, então uma falha pode ternar-se subjetiva, e executar os testes pode exigir uma linga validação manual.
  • Pontualidade (Timely) → os testes precisam ser escritos em tempo hábil. Devem-se criar os testes de unidade imediatamente antes do código de produção no qual serão aplicados. Se criá-los depois, o teste do código de produção poderá ficar mais difícil. Ou talvez você ache que um pouco do código de produção seja complexo demais para testar. Ou talvez você não crie o código de produção de maneira que possa ser testado.