Clean Code Matters!
Cuspir código que a maquina lê é a parte mais fácil de programar, a parte difícil é criar código fácil de manter.
Na semana passada encontrei uns trabalhos antigos de quando comecei a programar. Na época eu estava começando na linguagem C e ainda pensava que era bom em resolver problemas.
Eu realmente sabia resolver problemas e na tentativa e erro solucionava esses problemas em tempo recorde até, mas nunca era uma boa solução. Eu cuspia muito código. As soluções que eu criava eram dificeis de acompanhar, mas o motivo não era a complexidade do código e sim a qualidade do código. Era o famoso código espaguete.
Para compensar a baixa qualidade do código eu comentava linha por linha ou com blocos de comentário explicando o que estava acontecendo. "Agora ficou bem melhor", eu pensava.
Na realidade eu estava produzindo ainda mais lixo que deveria manter depois. Qualquer alteração iria ter que refletir também nos meus comentários. Isso era péssimo. Veja só o código que havia me deparado:
int excluir(struct Lst root, struct Lst *no){
if(no == NULL){
return 0;
}
struct Lst *auxiliar = no;//Declara um No auxiliar que ira receber o No a ser excluido
no = NULL; //Exclui o no
if(auxiliar->next != NULL){//Se o proximo No depois do No que foi excluido nao for Nulo, entao...
auxiliar->next->prev = auxiliar->prev;//...Auxiliar SEGUINTE recebe o informacao do No ANTERIOR ao No excluido.
}
if(auxiliar->next != NULL){//Se o proximo No depois do No que foi excluido nao for Nulo, entao...
auxiliar->prev->next = auxiliar->next;//No ANTERIOR recebe a informaсao do No DEPOIS do No excluido.
}
else{
auxiliar->prev->next = NULL;//Nesse caso. O No anterior ao que for excluido sera o ultimo. Por isso recebe NULL.
}
salvar(&root);
}
Está péssimo, mas apesar de tantos erros, com comentários redundantes e if
s aninhados, eu fiquei feliz em vê-los no meu antigo código. Perceber esses erros significa que eu evolui como programador. Ver um código antigo seu e se sentir orgulhoso dele pode ser um péssimo sinal. Sinal de que você não melhorou desde a ultima vez que encarrou seu ultimo código.
Eu evolui meus padrões de implementação, meu jeito de declarar funções, meu jeito de comunicar com o código. Conforme eu evoluia essas habilidades eu ainda desconhecia o nome apropriado para essas habilidades de comunicação, até que eu li o livro Clean Code do Uncle Bob e foi nesse momento que comecei a perceber o que eu estava evoluindo.
O que é Clean Code?
Clean Code é sobre escrever um código mais fácil de ler, mais fácil de entender e mais fácil de manter. Tem tudo a ver com técnicas de comunicação e expressão para tentar reduzir ao minimo possivel a ambiguidade, deturpações e outros ruídos no código que dificultam na comunicação.
O foco é pensar que ele vai ser visto ou mantido por outras pessoas e que ele precisa ser o mais comunicativo possivel para que essas pessoas que vão manter seu código entendam o comportamento dele, afinal, nada impede uma dessas pessoas de serem um psicopata que sabe seu endereço!!
Se preocupando com a qualidade do código vai ficar mais simples e fácil de entender: o Workflow da sua aplicação, a forma como os objetos interagem entre si e a responsabilidade de cada elemento da sua aplicação.
E isso importa tanto?
Isso importa muito! Programadores passam muito mais tempo lendo código do que escrevendo e devemos aprender logo cedo que nenhum código é escrito para ser abandonado. Outros psicopatas vão ler e talvez terão que manter seu código, e manter código é de longe a parte mais díficil de um sistema.
E uma das melhores consequencias do Clean Code é aumentar a confiança de quem está lendo. Quando entendemos bem sobre um assunto nós nos sentimos mais confiantes em falar sobre ele, e isso também se reflete quando estamos programando. Se entendermos o código e o problema que ele resolve nós ficamos mais confiantes para estender e modificar suas funcionalidades.
Dicas para melhorar
Fica dificil resumir toda experiencia passada pelo livro em apenas um artigo, mas existem algumas dicas que ajudaram muito a melhorar a qualidade do meu código.
1. Remova código e comentários inuteis
É comum vermos código com comentários. Normalmente isso é natural. O problema começa quando você faz comentários desnecessários comentando blocos de código ou instruções óbvias. Seu código vai mudar e ter que se preocupar se o comentário de uma linha ou bloco de código está atualizado só vai adicionar mais trabalho. Olhe esse esse exemplo abaixo.
contador++; //incrementa contador
É extremamente redundante e desnecessário. Nós sabemos o que o operador ++
faz, então não faz sentido comentar a linha descrevendo a operação.
contador++;
Ler o código deve ser tão natural quanto ler um texto e para tornar o código mais natural precisamos dar nomes mais descritivos para nossas variáveis e funções. Comentários não são tão ruins, mas um código auto descritivo é muito melhor.
2. Utilize nomes descritivos
Nomes descritivos ajudam muito na legibilidade do nosso código. Eles tornam a leitura mais natural e muitas vezes ajudam a dispensar comentários. Seu código se torna auto explicativo quando você adiciona mais descrição nos nomes. Olhe o código abaixo.
function authUsuario() {
//...
}
Nessa função a interpretação do significado de authUsuario
pode ter outras interpretações. Será que é authorization? authenticate? authorize? author? As intenções da função não estão explicitas em seu nome. Os nomes precisam comunicar suas intenções. Eles precisam dizer seu motivo de existir e qual papel eles devem cumprir. Dessa forma, vamos refatorar o código anterior como abaixo.
function autenticaLoginDoUsuario() {
//...
}
Ao criar nomes mais descritivos nós deixamos explicito o comportamento e responsabilidade da variavel ou função, e devemos respeitar suas responsabilidades.
3. Utilize nomes pronunciaveis
Tente utilizar nomes pronunciaveis sempre que possivel. Pense na dificuldade que é para pronunciar uma sigla e ainda mais entender seu significado.
const ddmmyyyyStr = moment().format('DD-MM-YYYY');
O nome dessa variavel é dificil de ser pronunciada e provavelmente não vamos ler caractere por caractere para saber exatamente o que ela significa.
const dataAtualCompleta = moment().format('DD-MM-YYYY');
Se seu código utilizar nomes pronunciaveis a pessoa vai conseguir ler e entender quase instantaneamente o significado e propósito da variavel. Humanos são tão bons com palavras que conhecem, então aproveite essa qualidade nossa e utilize palavras pronunciaveis.
4. Encapsulamento de condicionais
Condicionais podem parecer simples a primeira vista. "É apenas True ou False", nós pensamos, mas na realidade as condicionais adicionam mais complexidade ao nosso código.
if (idade > 18 && !pagamentoPendente) { ... }
A realidade é que não fica muito claro o que o if
está verificando. Deveriamos ser capazes de saber o que ele faz antes de olhar dentro do seu bloco de código.
Para melhorar esse código nós podemos extrair essa condicional para uma função. Nós vamos encapsular a condicional em uma função, desse jeito:
function isUsuarioValido(idade, pagamentoPendente) {
return idade > 18 && !pagamentoPendente;
}
E depois só precisamos chamar essa função dentro do nosso if
:
if (isUsuarioValido(idade, pagamentoPendente)) { ... }
Dessa forma podemos ler de forma natural o que o if
está verificando: SE É UM USUÁRIO VÁLIDO FAÇA ISSO. Isso deixa explicito a intenção do if
antes mesmo de olhar sua implementação. Não precisamos adicionar comentários pois o código está se documentando.
5. Evite efeitos colaterais
Os efeitos colatareis são mentiras. Nossa função promete que vai fazer UMA COISA e secretamente ela faz outra. Ela não deixa explícito que vai ter efeitos colaterais.
const pacote = new Pacote( ... );
function calculaFrete(endereco) {
pacote.frete = CorreiosApi().frete(pacote.endereco, endereco);
return pacote.frete;
}
Repare que o nome da função diz que irá calcular o frete, mas na implementação também estamos atribuindo o valor do frete dentro do pacote que é declarado fora da função calculaFrete
. Isso é um efeito colateral. Não estamos deixando explícito o comportamento da nossa função e mesmo que o nome da função fosse calculaFreteEAtribuiAoPacote
, ainda não seria bom pois estaria tendo mais de uma responsabilidade.
Para evitar isso precisamos respeitar o escopo da nossa função. Devemos limitar nossa leitura e atribuição para dentro do escopo da função que se limita aos seus parametro e ao que é declarado dentro do corpo da função, então podemos refatorar dessa forma:
const pacote = new Pacote( ... );
function calculaFrete(origem, destino) {
return CorreiosApi().frete(origem, destino);
}
Dessa forma a função calculaFrete
se torna independente da variavel externa, além de deixar mais explicito suas dependencias por ter apenas uma unica responsabilidade. Sempre que possivel tente utilizar funções que não causam efeitos colaterais (Funções puras), mas não torne isso um dogma pois algumas vezes será necessário modificar estados externos.
Conclusão
Esse artigo na verdade é uma Lightning Talk de 10 minutos que criei com o objetivo de mostrar problemas comuns que eu enfrentei quando comecei a programar, sobre a importância de utilizar técnicas de Clean Code e algumas dicas básicas puderam melhorar a qualidade do meu código.
Os slides da palestra estão disponíveis no meu SlideShare e também podem ser visualizados abaixo e a linguagem utilizada nos slides é Swift
Ainda sobre Clean Code, eu escrevi outro artigo Dicas de Clean Code: Funções pequenas e concisas onde descrevo as vantagens de ter funções com apenas uma responsabilidade, que também é uma ótima prática para manter a legibilidade do nosso código.
E vocês, também tiveram uma experiencia semelhante? Qual o sentimento de vocês quando olham para um código antigo seu?
You might also be interested in these articles...
Desenvolvedor na TriadWorks - Email