Uma coisa é fato, se você já trabalhou em equipes formadas por programadores inexperientes ou dando suporte a códigos desenvolvidos por outros programadores, a experiência certamente foi traumatizante. Eu sou um dos que se tiver que trabalhar com código de outras pessoas ou até mesmo meus códigos de 4 ou 5 anos atrás, já sente aquele leve frio na barriga.
Independentemente de qual linguagem, Framework ou para qual plataforma você desenvolva, escrever códigos fáceis de ler e manter é uma tarefa árdua. Então, se liga nessas dicas para escrever um código do qual você se orgulhe de mostrar aos outros 🙂
Importante: Boa parte das dicas postadas aqui foram retiradas do livro “Código Limpo – Habilidades Práticas do Agile Software”, então, para se aprofundar no assunto, sugiro a leitura do mesmo.
Somos Autores
Assim como os autores de livros de romance, nós também somos autores e todos autores têm leitores, então é sua obrigação utilizar uma linguagem clara e direta para que sua obra seja de fácil entendimento. Se seu leitor (Que pode ser você mesmo, daqui uns meses ou anos) precisar ficar rolando a página, acessando outros arquivos, etc. Para poder entender o que você estava tentando fazer naquele bloco de código, isso é um bom sinal de que você não escreveu da melhor maneira possível.
Idioma
A primeira dica de como escrever um bom código é definir um idioma padrão. Não existe nada que lhe obrigue a escrever códigos em inglês, mas se você dominar o idioma, prefira escrever em inglês. Português requer acentuações e isso pode gerar alguns problemas de entendimento, já que você não pode (ou pelo menos não deve, mesmo que a linguagem permita) escrever com acentuação. Além disso, a sintaxe das linguagens já são em inglês, então é meio estranho ler código em português e inglês ao mesmo tempo. Exemplo:
1 2 3 |
void definirNome(String Nome) { // ... } |
A situação piora ainda mais quando você mesmo resolve misturar os dois idiomas.
1 |
Contrato contract = user.getContrato(); |
Super ruim de ler isso, não é verdade?
Importante: Optei por usar Português nos exemplos desse Post, para ficar mais acessível a quem não tem domínio de inglês, mas que com certeza estão dando atenção a isso, não é amiguinhos?
Nomes significativos
Imagine que você esteja iniciando uma nova graduação e em sua sala de aula há 45 alunos, todos com nomes muito legais como: “a”, “a2”, “x”, “clt”, “b2c3”, etc. Esses nomes foram escolhidos pelos pais deles, porque estavam com preguiça de ter que escrever nomes grandes toda hora. Imagine a confusão?
1 2 3 4 5 6 |
int a = 10; int b = 1; if(a < b) { // ... } |
Você viu o código acima? O que ele significa? O que o programador pensou ao fazer ele?
Você pode até pensar: “Pô, mas ninguém faz isso”. Acredite, faz sim e é muito mais comum do que você pensa, então, evite fazer isso, é muito mais fácil de entender quando você dá nomes significativos as suas variáveis, funções, classes, etc.
1 2 3 4 5 6 |
int limiteDeTentativas = 10; int tentativasRealizadas = 1; if(tentativasRealizadas < limiteDeTentativas) { // ... } |
Olha como o código ficou bem melhor de entender agora.
Aqui cabe uma observação importante. Se você usa variáveis i
em blocos for
, como por exemplo: for(int i=0; i<10; i++)
, isso não chega a ser um problema. Como essa prática é comumente utilizada em diversas linguagens, meio que virou uma conversão, então praticamente todo mundo sabe o que isso significa.
Uma outra dica é: Evite usar prefixo nos nomes de suas variáveis, funções, etc…
1 2 3 |
String nomeFuncionario = funcionario.meuFW_obterNome(); int idadeFuncionario = funcionario.meuFW_obterIdade(); Double salarioFuncionario = funcionario.meuFW_obterSalario(); |
Além de ficar horrível, isso prejudica um dos recursos mais interessantes das IDEs, o autocomplete. Imagine você ter diversos métodos e digitar “me”. Uma lista enorme de métodos e propriedades são exibidas sem necessidade. Fora isso, chega um momento que seu cérebro se acostuma com esses prefixos e ele nem mais os lê, porque ele já sabe que aquela informação inútil está ali. E se ele não mais as lê, pra que elas existem?
Objetos com parâmetros
Quando uma função parece precisar de mais de dois ou três parâmetros, é provável que alguns deles podem ser colocados em uma classe própria.
1 2 3 4 5 6 7 8 9 |
void enviarEmailDeNotificacao( int idCliente, String nomeCliente, String emailCliente, String avatarCliente, String mensagem ) { // ... } |
Percebe como há muita informação que poderia ser enviada em um único Objeto? Não seria melhor fazer algo assim?
1 2 3 |
void enviarEmailDeNotificacao(Cliente cliente, String mensagem) { // ... } |
Prefira exceções a retorno de código de erro
Uma função deve fazer ou retornar algo, não ambos e quando fazermos funções retornarem código de erros esse conceito é violado, pois os comandos são usados como expressões de comparação em estruturas if
. Um exemplo:
1 2 3 4 5 6 7 8 9 |
if(deletarPagina(pagina) == E_OK) { if(registro.deletarReferencia(pagina.nome) == E_OK) { log.gravar("Página Excluída"); } else { log.gravar("Ocorreu um erro ao tentar excluir o registro da página: " + pagina.nome); } } else { log.gravar("Ocorreu um erro ao tentar excluir a página: " + pagina.nome); } |
Em um exemplo como esse, o seu sistema precisaria de vários ifs
desnecessários para ficar comparando a todo tempo se uma função fez algo.
Não seria muito mais simples fazer algo assim:
1 2 3 4 5 6 |
try { deletarPagina(pagina); registro.DeletarReferencia(pagina.nome); } catch(Exception e) { log.gravar(e.getMessage()); } |
Inclusive, se você extrair os blocos try/catch, o resultado é ainda melhor. Exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public void deletar(Pagina pagina) { try { deletarPaginaETodasReferencias(pagina); } catch(Exception e) { gravarLog(e); } } private void deletarPaginaETodasReferencias(Pagina pagina) throws Exception { deletarPagina(pagina); registro.deletarReferencia(pagina.nome); } private void gravarLog(Exception e) { log.gravar(e.getMessage()); } |
Mas Paulo, a segunda opção é bem maior, eu vou precisar digitar muito mais e terei 3 funções
Sim, eu sei, porém cada uma tem sua responsabilidade. Isso a principio pode parecer mais trabalhoso, mas ao decorrer do desenvolvimento do seu sistema você verá o quanto isso vai lhe ajudar. 🙂
Endentação/Indentação)
Endentar um código adequadamente é tão importante que algumas linguagem (como o Python por exemplo) obrigam você a usar. Mas a questão aqui vai além disso. Blocos dentro de instruções if
, else
, while
, etc. Devem ter apenas uma linha, que geralmente será uma chamada para uma função pequena. Isso melhora consideravelmente a qualidade de seu código e você ainda pensará melhor no conceito de responsabilidade única.
Lembre-se: Uma função deve fazer apenas uma coisa e fazer-la bem.
Ex.:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void cadastrarFuncionario(Funcionario funcionario) { if(funcionario.obterEmail() != null && !funcionario.obterEmail().trim().isEmpty()) { if(funcionarioDao.inserir(funcionario) { if(disparadorDeEmail.enviarBoasVindas(funcionario.obterEmail())) { // ... } else { log.gravar("Ocorreu um erro ao tentar enviar as boas vindas para: " + funcionario.getId()); } } else { log.gravar("Ocorreu um erro ao tentar cadastrar o funcionario: " + funcionario.getId()); } } } |
A função acima tem um nível de profundidade muito grande nos ifs
, podemos refatorar esse código para melhorar sua manutenibilidade e sua legibilidade. Uma sugestão seria:
1 2 3 4 5 6 7 8 |
void cadastrarFuncionario(Funcionario funcionario) { try { funcionarioDao.inserir(funcionario); disparadorDeEmail.enviarBoasVindas(funcionario.obterEmail()); } catch(Exception e) { log.gravar(e.getMessage()); } } |
Qual código é mais fácil de ler?
Evite ao máximo o uso do ELSE
Se você abrir alguns de seus códigos e analisar mais detalhadamente suas funções, certamente você verá uma série de elses
que não tem a menor razão para existir. Exemplo:
1 2 3 4 5 6 7 |
boolean eMaiorDeIdade(Aluno aluno) { if(aluno.obterIdade >= 18) { return true; } else { return false; } } |
Você poderia simplificar esse código para:
1 2 3 4 5 6 7 |
boolean eMaiorDeIdade(Aluno aluno) { if(aluno.obterIdade >= 18) { return true; } return false; } |
viu como o else não é necessário? Mas ainda dá para melhorar ainda mais:
1 2 3 |
boolean eMaiorDeIdade(Aluno aluno) { return aluno.obterIdade() >= 18; } |
Comentários
Aqui pode estar a parte mais polêmica desse Post. Sabe quando seu professor dizia que é sempre bom comentar todo o seu código? Pois é, ele estava errado. Comentários, na grande maioria das vezes serve para uma única coisa. Compensar o nosso fracasso em nos expressar em nossos código.
É muito comum lermos códigos onde 50% ou mais do código é comentário. Você muitas vezes tem 5 ou 6 linhas de comentários para explicar 2 linhas de código. Mas, se o código for autoexplicativo, pra que comentário?
O que você preferiria ver em um código? Isso:
1 2 3 4 5 6 7 |
/** * Caso o funcionário tenha mais de 60 anos, tenha um salário inferior a R$ 3000,00 * e caso ele tenha filhos, o mesmo está elegível a receber um bonus */ if(funcionario.idade > 60 and funcionario.salario < 3000 and funcionario.temFilhos()) { // } |
ou simplesmente um desses métodos?
1 2 3 4 5 |
if(funcionario.estaElegivelParaOBonus()) { } if(funcionario.eBonificavel()) { } if(funcionario.podeReceberBonus()) { } |
É claro que não estou dizendo para você nunca comentar seus código. Em diversas situações você precisará deixar um comentário explicativo. Um exemplo disso é em blocos de expressões regulares, que geralmente tem uma leitura bem complicada ou em blocos que podem afetar arquivos importantes caso sejam mal utilizados. Mas a ideia aqui é você tornar o seu código o mais legível possível, assim você irá cada vez menos precisar de comentários.
Uma coisa é bastante irritante é abrir um código como esse:
1 2 3 4 5 6 7 8 |
// Armazena o nome do usuário String nome; // Armazena a idade do usuário int idade; // Armazena o e-mail do usuário String email; |
Qual a necessidade disso, jovem? será que um atributo nome
, dentro de uma classe Usuario
, não é explicativo o suficiente?
Bem, esse foi o básico sobre Clean Code. É óbvio que tem muito mais coisa a ser explorada e provavelmente eu faço uma parte 2, e 3 e 4… desse post.
Espero ter sido claro em minhas explicações e espero que esse Post lhe ajude de alguma forma a melhorar seu código, mesmo que você trabalhe sozinho. Até a próxima!!!
Muito interessante, legal o artigo!
De tudo que foi dito aí reparei que tenho como hábito exagerar no comentário, incluindo as vezes até o demandante de uma solicitação. Penso na rapidez de manutenção e que o próximo a trabalhar no código pode ser novato.
Valeu, Rangel 😉
Mais legal do que o artigo é o teu site, Bugginho. Inspirador demais esse layout clean. <3 Abraço!
Valeu, amiguinho. Mas o Layout não foi desenvolvido por mim, eu apenas tive o bom gosto de escolher ele :), caso queira utiliza-lo, eu comprei ele por cerca de U$ 70,00 no Theme Forest. O nome dele é: Gridlove
Faz tempo que não utilizo o else. Puuts realmente ele é desnecessário, só fazer a lógica ao contrário em alguns casos.
Também faço nome de variáveis bem auto-explicativas, assim qualquer programador vá conseguir entender, Nome dos métodos faço a mesma coisa, sempre.
Quanto ao uso de Regex, quando é algo meio complicado, eu faço bloco de comentários e a string onde a regex irá resolver o problema. Também faço comentários em consts de ValueObjects, quando o objetivo é encasular vários status para uma regra de negócio. Mesmo os consts sendo auto-explicativas, acho necessário escrever algo resumido só para ter algo documentado.
Ótimo artigo, clean code é vida!
É isso ai, amiguinho. Um código bem escrito é melhor que 1.000 linhas de comentários inúteis 😉
Excelente post este livro faz parte de uma lista de livros ao qual tenho que ler.
Concordo com quase tudo q vc disse, exceto pelo uso do else. Nunca vi o else como inimigo e varias vezes eu acabei encontrando falhas de design quando me pergunto “e se essa condição for falsa? Tenho q fazer alguma coisa?”. Agora, retornar variáveis inicializadas com valor default me parece mais o uso de funções com ponto de retorno único. Sempre gostei dessa técnica, ela faz sentido principalmente em linguagens como C que não tem limpeza de memória automática.
Discordo fortemente da ideia de não usar comentários, e de códigos “””””””””auto explicativos””””””””” (sim, com essa quantidade de aspas).
O que é fácil e auto explicativo para você, programador, não o será para o próximo programador, nem para você mesmo, daqui a vários anos.
E ainda que definir e explicitar o que faz uma variável pelo nome às vezes baste, não podemos nem de longe dizer o mesmo de funções, como elas operam e fazem o que têm de fazer.
Na minha opinião, um código bem feito, tem sim mais comentários que código escrito.
As variáveis são curtas e bem explicadas, e o “grosso” dos comentários se limita às declarações iniciais, sendo reduzido conforme o código vai sendo escrito.
É triste você pegar código que o autor achou limpo à época e que hoje nem ele mesmo entende.