Escrever código é escrever para alguém
Criar um software é, no fundo, parecido com qualquer outro tipo de escrita. A diferença é que, como devs, a gente costuma se preocupar mais com "será que isso vai funcionar" do que com "será que isso vai ser fácil de entender depois". E é exatamente esse o problema que o livro ataca: código limpo não é só código que funciona, é código que qualquer pessoa — inclusive você, seis meses no futuro — consegue ler sem sofrer.
Nomes que fazem sentido
Tudo começa pelos nomes. Variável com nome tipo x, temp ou dado2 obriga quem está lendo a parar e adivinhar o que aquilo representa. O ideal é que o nome já entregue o significado sozinho. E cuidado com nomes parecidos demais: se você tem getActiveAccount, getActiveAccounts e getActiveAccountInfo no mesmo arquivo, ninguém vai saber de cabeça qual delas chamar. Outro detalhe simples: só chame algo de accountList se aquilo realmente for uma lista — senão, use algo mais genérico, como accounts ou bunchOfAccounts. E parâmetros como a1, a2 são uma armadilha; prefira nomes que expliquem o papel deles, tipo source e destination.
Funções pequenas e que fazem uma coisa só
Uma função boa faz uma coisa, faz ela bem, e só ela. Quando você lê o nome de uma função e o que ela faz é exatamente o que você esperava, isso é um sinal de que o código está limpo. Na prática, isso significa funções curtas — o livro sugere até 20 linhas como teto — e com poucos parâmetros, no máximo três. Se uma função chama outra, é legal que elas fiquem próximas no arquivo, com a que chama vindo antes da que é chamada, igual quando você lê um texto de cima pra baixo. Também vale evitar passar um booleano como parâmetro: isso geralmente é sinal de que a função está fazendo duas coisas disfarçadas de uma.
Comentários: menos é mais
Aqui tem uma ideia que costuma surpreender quem está começando: comentário ruim é pior do que nenhum comentário. Se você sente vontade de comentar uma linha pra explicar o que ela faz, talvez o problema seja que o código não está claro o suficiente — e a solução é reescrever, não comentar. Comentários valem a pena quando trazem informação que o código sozinho não consegue passar, mas devem ser usados com moderação. Comentário desatualizado, redundante ou mal escrito é pior do que deixar o código falar por si.
Separe dados de comportamento
Existe uma diferença importante entre objetos e estruturas de dados: objetos escondem os dados e expõem ações (métodos); estruturas de dados expõem os dados e não têm comportamento de verdade. O problema é quando você cria algo no meio do caminho — metade objeto, metade estrutura — porque isso deixa o código confuso sobre o que ele realmente é.
Erros não devem se misturar com o resto
Tratar erro também é uma responsabilidade só, então uma função que lida com erros não deveria fazer mais nada além disso. Vale a pena criar mensagens de erro que realmente ajudem quem for debugar — com contexto, não só "deu erro". E uma regra prática: evite retornar null e evite passar null como argumento, porque isso costuma gerar verificações desnecessárias espalhadas pelo código todo.
Classes enxutas
A lógica das classes segue praticamente a mesma das funções: devem ser pequenas e focadas. Um teste legal é tentar descrever o que a classe faz em umas 25 palavras, sem usar "e", "ou", "mas" — se você precisa dessas palavras, é sinal de que a classe está fazendo coisa demais. Tem também o Princípio Aberto-Fechado: uma classe deve poder ser estendida (você adiciona coisas novas) sem precisar ser alterada por dentro toda vez.
Testes e refatoração
Ter testes automatizados não é luxo, é o que permite refatorar com confiança. O ideal é rodar toda a bateria de testes com um único comando, e os testes devem cobrir tudo que pode quebrar — não só o caminho feliz. Uma observação interessante do livro: bugs tendem a se agrupar. Se você achou um bug numa função, vale a pena testar essa função a fundo, porque é bem provável que tenha mais escondido ali.
Refatorar é o processo de melhorar a estrutura interna do código sem mudar o que ele faz por fora: reduzir repetição, separar responsabilidades, trocar nomes ruins por nomes melhores. E repetição de código não é só feiura — ela representa trabalho extra e risco, porque toda vez que você corrigir algo, vai precisar lembrar de corrigir em todos os lugares onde aquilo foi copiado.
Algumas regras que resumem tudo
O livro traz algumas filosofias que ajudam a fixar a ideia central. A Regra do Escoteiro diz: "deixe o código mais limpo do que você encontrou" — não precisa resolver tudo de uma vez, só não piorar. As quatro regras do design simples, de Kent Beck, resumem bem o objetivo: os testes devem passar, não pode ter duplicação, o código precisa deixar claro o que o programador quis dizer, e o número de classes e métodos deve ser o mínimo necessário. E claro, o clássico DRY — Don't Repeat Yourself, não se repita.
Por fim, vale lembrar do FIRST, o conjunto de qualidades que bons testes deveriam ter: rápidos (pra você rodar com frequência sem perder tempo), independentes entre si, repetíveis em qualquer ambiente, capazes de se autovalidar (sem você precisar conferir resultado na mão) e escritos no momento certo — de preferência, logo antes do código que eles testam, não depois.
No fim das contas, código limpo não é sobre seguir regras à risca, é sobre respeitar quem vai ler aquilo depois — e esse alguém, na maioria das vezes, é você mesmo.