Code Clean
Autor: Leandro Siciliano | Publicado: 2013-09-17T05:32:00-07:00


Levei bastante tempo para chegar as linguagens orientadas à objeto e chegar talvez não seja o grande problema, o problema na realidade é entender tudo aquilo que gira o mundo do desenvolvimento hoje em dia. Costumo falar que java não é difícil, mas o mundo java eu considero uma missão bem complicada. Não basta você aprender java, você hoje tem que estudar constantemente para conhecer bem os frameworks e saber no que eles podem ser úteis para você.



Eu vim de uma linguagem que nem orientada a objeto é. A IDE não ajuda as boas práticas e etc, enfim, quando fui para o mundo java foi como se eu tivesse saído de um fusca para uma Ferrari conversível.



Quando comecei a trabalhar com java fui direto para uma equipe que trabalhava com scrum e XP e várias técnicas que nunca tinha visto na minha vida, tais como TDD, BDD ...



Foi realmente um choque ! Eu vinha estudando tudo, lendo muito, tentando as coisas em casa, mas a prática é realmente a prática, não tenha dúvidas.



Com pouco menos de um ano no mundo java procurei o arquiteto da equipe e perguntei:

"Meu código tá legal ?"



Pedi uma dica e o mesmo falou:

"Leia o clean code !"



Clean Code é um livro escrito por Robert C.Martin, mais conhecido como Uncle Bob (Tio Bob).&nbsp;O livro é de fácil leitura, muito bem escrito e explicativo, aborda temas bastante interessantes. O livro trata de tópicos como: código limpo, nomeações de classes, variáveis, métodos e parâmetros, formatações do código, arquitetura, testes e TDD, refatorações e muito mais.



Ele ainda escreveu um outro livro que acho muito interessante que é o Clean Coder. Confesso que ainda não consegui ler todo, mas o pouco que li achei muito bacana. O livro fala do codificador limpo, ou seja, a maneira como um desenvolvedor se porta, como ele deve agir em determinadas situações e etc. Vou aqui misturar um pouco os assuntos com mais ênfase no Code Clean e sem uma ordem tão bem definida.



Importância dos testes

Tenho um amigo que foi um grande cara que me ajudou a ir para o mundo java inclusive me ajudando nessa oportunidade e me lembro há uns três anos atrás quando sentamos e fizemos um método e depois de pronto ele falou: "Vamos escrever um teste para ele para ver se ele está funcionando ?". Pensei comigo naquela época: "Que diabos esse cara tá falando ?" realmente eu não consegui saber o que ele estava dizendo. Na linguagem que eu trabalhava não tinha nada disso, quem testava era eu e depois o responsável técnico (uma espécie de mistura de testador com gerente de projetos e sei lá mais o que). Dois anos depois eu fico pensando como alguém programa sem testes automatizados, como você pode garantir que seu software vai continuar funcionando se você incluir uma nova regra de negócio ou alterar um método, por exemplo. Construir um software não é somente escrever um monte de código e ve-lo funcionar, mas é você saber que aquele código deverá ser manutenível e que outras pessoas vão altera-lo. O mais interessante hoje é que sou um viciado em TDD&nbsp;que é exatamente o processo de você escrever o teste antes do desenvolvimento. Acreditem, seu código vai ficar melhor.



Tenho uma passagem na vida que morro de vergonha, mas fui o culpado. Uma vez em uma grande empresa fiquei com um sistema onde a agilidade sumiu e eu fiquei direto com o cliente. Esse cara me pediu para alterar cem vezes a mesma coisa que era um relatório gigante, quando eu vi já tinha feito funções que tinha quase mil linhas e nem eu mais consegui entender. A IDE era um lixo, não ajudava, mas mesmo assim não era desculpa, eu mandei mal. Um amigo depois de um tempo teve que manter, o caso foi tão grave que ficamos sem nos falar um tempo e eu pedi desculpas e tudo ficou bem.



Teste é fundamental ! Você tem que ser responsável por aquilo que escreve e saber que seu sistema tem que continuar funcionando. Por mais que pareça bobo dentro do seu código, você tem que saber que seu sistema tem que continuar funcionando.



De tudo que eu falei vem uma das primeiras dicas do nosso querido Uncle Bob:

"Toda linha que você escrever deve estar testada e ponto final !"



Hoje eu falo que quem não acredita nesse princípio deveria repensar nos seus princípios. Acredito também que muitos dos que pensam que teste não é algo tão fundamental é porque provavelmente não conhece a prática de teste ou assim como eu antigamente, trabalha com alguma tecnologia ultrapassada.



Código manutenível

Eu tive vergonha por muitos anos das coisas que escrevia e até hoje eu corro atrás de melhorar a cada dia mais um pouco as coisas que faço. Estou longe da perfeição mas hoje tenho mais orgulho das coisas que escrevo. Eu um sistema que peguei nos últimos tempos, peguei um código do tipo:



i = carroService.getId();



Que raios é "i" ??? O pior é que o desenvolvedor que fez fez o favor de recortar e colar por todo o código. Eu aprendi que não devemos economizar nas palavras no seu código.



Um outro bom exemplo, em um botão na ação de um botão no site era utilizado uma chamada a uma ação e essa tinha o nome de "go()". Go ? Vai pra onde ??? Por que não "salvarCarro()" ? E mais uma vez, aquela função está replicada por várias partes do sistema no esquema recorta e cola e altera informações dentro da função.&nbsp;



Você tem que saber que um dia um programador vai pegar esse tipo de código e vai te xingar de todos os nomes e terá um trabalho enorme para alterar uma funcionalidade. Um dos caras que admiro demais,&nbsp;Martin Fowler,&nbsp;costuma falar que: "Qualquer um pode escrever um código que o computador entenda, mas o verdadeiro desenvolvedor escreve código que outro desenvolvedor entenda.". Códigos escritos por profissionais podem ser alterados sem custos exorbitantes.



Hoje eu considero que ler um código é como ler um livro, se você entender aquele código como uma história provavelmente o mesmo está bem escrito.



A empresa Eu s/a

Sua carreira é algo que você deveria ver como uma enorme importância. Quantos livros você leu nos últimos cinco anos ? Quantos cursos você fez ? Quais são suas próximas metas ? Quantas conferências você participou ?



Sua carreira é responsabilidade sua e não do seu empregador. Eu conheço várias pessoas que ficam esperando que seus empregadores ofereçam cursos e etc. Profissionais de TI tem que entender que parte de tudo que ganham tem que ser reinvestido na própria carreira. Trabalhamos em uma área muito dinâmica e que evolui diariamente. Todo dia tem alguma coisa nova. Se seu empregador te ajudar com isso, ótimo, se ele não fizer você tem que pagar essa conta, mesmo porque na maioria das vezes seu empregador não vai pagar todos os cursos que você gostaria de fazer.



Sou o homem cursos, eu costumo fazer três, quatro cursos por ano e acredite, eu não acho que nenhum seja jogado fora. Existem uns melhores, outros piores, com o tempo eu só passei a ser mais seletivo nos cursos que faço e nos livros e revistas que leio pela total falta de tempo. Eu adoraria que o dia tivesse 48 horas para poder fazer o dobro de cursos, mas infelizmente só tem 24.



Para conseguir sair do meio que estava e passar para uma área nova (java) eu fiz seis cursos seguidos gastei o equivalente a um carro popular, mas não me arrependo nem um pouco. Valeu cada centavo !



Um outro fator é o tempo que você dedica a sua carreira. Conheço muitas pessoas que reclamam dos seus trabalhos e não saem da praia. Então eu penso: "De que adianta reclamar e não fazer nada para mudar ?". Não adianta reclamar se você não se mexer. A maneira que penso é que, assim como o dinheiro, você tem que investir tempo na sua carreira. As pessoas costumam se acomodar. Escolheu a profissão errada ? Sai dela e corre atrás do que você quer mas seja justo e honesto com você mesmo e digo isso porque você só conseguirá sucesso nas suas escolhas se você tiver paixão naquilo que está fazendo.



Escrevendo um bom código segundo Uncle Bob

Vamos aqui dividir as coisas em alguns tópicos. Para iniciar gostaria de mencionar outra frase do Uncle Bob:



"Um bom programador não passa a responsabilidade de um código para outro."



Nomes significativos

Mencionei mais acima que peguei a pouco tempo um método com o nome de “go()”.&nbsp; Métodos, nomes de variáveis e etc tem que ter o nome que digam alguma coisa. Um método com nome de “go()” não diz nada, você vai precisar olhar onde o mesmo está sendo chamado para saber o que ele faz.



Um outro exemplo nesse caso é a velha prática do CTRL+C, CTRL+V. A ferramenta antiga que eu mexia tinha um help excelente com vários exemplos feitos, tipo, se quero declarar uma variável de data, eu poderia facilmente recortar o exemplo dado pelo help e colar no código que tudo funcionava. Mas veja, lá estava um exemplo dado pelo fabricante. Eu mesmo cansei de recortar e colar as coisas que estavam lá e depois não me preocupar com o nome que estava no exemplo, tipo:



Date d;



Mas agora me digam, o que é “d” ?



Vamos imaginar que mais para frente no código você se depare com a seguinte linha:

If(d.after(d1)){

 ...

}



E agora ? o que é d1 ? o que é d2 ?



Pior que tem desenvolvedor que ainda vai e ao invés de refatorar o nome da variável simplesmente coloca um comentário:



Date d; //Dia da semana



Não seria mais prático:



Date diaDaSemana;

Date diaDePagamento;





If(diaDaSemana.after(diaDePagamento)){

&nbsp; ...

}



Mais fácil a leitura né ?&nbsp;



Uncle Bob diz que os nomes devem ser significativos e devem dizer basicamente:



Por que existem ?
O que faz ?
Como é usado ?




Ele deve revelar sua intenção. Se um nome requer um comentário o mesmo não revela realmente a sua intenção.



Os nomes devem ser pronunciáveis e claros, algo que quando você olhe você entenda.



Imagine:



private getNSUsuario(){

 ….

}



Não seria melhor:



private getNomeESobrenomeDoUsuario(){

 ….

}



Ou seja, o nome se tornou pronunciável. Não economize nas palavras, escreva o quanto for possível para que seu código seja entendido facilmente.



Evite a notação húngara

O tipo não precisa estar no nome, por exemplo:

List listaDeLancamentos;



Isso pode atrapalhar, as vezes é utilizado um array onde se coloca que é um list e vice e versa. Utilize somente “lancamentos”, não interessa se é uma lista ou um array, interessa que você tem os lançamentos que precisa.



Classes e métodos

Segundo Uncle Bob, nome de classes devem ser substantivos e não conter verbos e nomes de métodos devem conter verbos. Os verbos são as ações. As ações que executam coisas por isso a presença de verbos nos métodos.



A regra para métodos. segundo Uncle Bob é:

“A primeira regra dos métodos é que eles devem ser pequenos. A segunda regra é que eles devem ser menores ainda.”



Métodos e classes menores são mais fáceis de ler e entender, além de manter é claro.



Métodos &lt;= 20 linhas

Linha &lt;= 100 caracteres

Classe = 200 a 500 linhas



Claro que toda regra tem sua exceção. Essas são dicas do livro, porém se você tem uma classe que vai precisar de mais linhas, um método que também precise de mais linhas, isso não é um problema, o lance é mais ter isso em mente como uma “bússola”.



“Métodos e funções devem fazer somente uma coisa, fazê-la certa e somente fazê-la”.



Vejo essa frase como o principio da coesão no seu código.



Muitas vezes não é fácil saber se aquele método está fazendo somente uma coisa. Uncle Bob dá uma boa dica. Ele diz que você deve tentar extrair parte do seu código para um método, se você conseguir, isso é porque aquele seu método realmente não está tendo uma só função.



Vamos imaginar se eu tivesse um método onde eu quisesse mostrar os detalhes de um usuário:



private void mostrarDadosUsuario(Usuario usuario){

&nbsp; &nbsp;

 mostrarCabecalhoUsuario();

 System.out.print(“Nome: “, usuario.getNome());

 System.out.print(“Sobrenome: “, usuario.getSobrenome());



}



As linhas do System.out.print são os detalhes do usuário, então será que não ficaria melhor:



private void mostrarDadosUsuario(Usuario usuario){

&nbsp; &nbsp;

 mostrarCabecalhoUsuario();

 mostrarDetalhesUsuario();



}



private void mostrarDetalhesUsuario{

 System.out.print(“Nome: “, usuario.getNome());

 System.out.print(“Sobrenome: “, usuario.getSobrenome());

}



Se um dia você quiser só listar os dados de um usuário, pronto ! Vc tem os métodos separados. Imagine se você quisesse imprimir os dados da maneira que estava antes, você nunca conseguiria.



Isso também é um bom exemplo do tipo de refatoração chamada “Extract Method”, vamos falar mais a frente sobre a importância da refatoração.



Uma outra coisa está na quantidade de parâmetros de um método. Um dia desses peguei uma aplicação legada que tinha uma função javascript com 34 parâmetros. Eu considero isso uma manutenção quase impossível. Imagine uma chamada:



montaMenu(1,2,1,1,1,1””,1,2,2,2,2,””,””,””,2,1,2,3 …)



Como entender ? o pior que o método era no nível “Date d”, logo, é preferível refazer. Uncle Bob fala que você deve ter uma justificativa muito boa para ter uma quantidade tão grande de parâmetros em um método.



Um outro agravante de um método com vários parâmetros é a dificuldade de se testar uma vez que você terá que testar todas as combinações possíveis.



Outra coisa que tem que se tomar cuidado é com método que diz que vai fazer uma coisa e faz outra.



Vamos imaginar:



public boolean verificarSenha(String senha){

 if(senha.equals(“zzz”)){

  Session.initialize();

  return true;

 }

 return false;

}



O objetivo do método é verificar a senha, porém, se a senha estiver correta o mesmo inicializa uma sessão, ou seja, o método já não tem a coesão esperada, o mesmo está com duas responsabilidades.



E se eu quisesse inicializar uma sessão ? eu seria obrigado a ter a senha correta ?



Para uma melhor coesão, seria melhor:



if(verificaSenha(“zzz”){

 Session.initialize();

}



public boolean verificarSenha(String senha){

 if(senha.equals(“zzz”)){

  return true;

 }

 return false;

}



Métodos devem fazer algo ou retornar algo, mas não as duas coisas ao mesmo tempo (princípio do command query separation)



Comentários nos códigos

Comentários podem ser mentirosos e trazer desinformação. Porque podemos afirmar isso ? Alguém conhece alguém que atualiza comentário ? Passei por vários códigos na vida com uma montueira de&nbsp; comentários que não serviam para nada e ainda confundiam. Se um método ou uma classe estiver bem escrito o comentário passa a ser dispensável.



Uma outra coisa importante, comentário não irá esconder um código ruim. Lembra do exemplo dado acima ?



Date d;



Esse código já está ruim, de nada adianta eu mudar para:



Date d; //dia da semana



Esse comentário não irá se propagar para todo o código e sempre que você se deparar com uma linha como:



d.after(d2);



Você vai continuar não entendendo o propósito do código. Podemos tentar colocar uma regra nisso. Concorda que quando se comenta um código pode ser que o mesmo precise ser refatorado ? Lembra dos exemplos anteriores onde “d” passou a ser “diaDaSemana” ? Com essa mudança seu código passa a ser um código que pode ser entendido por todos e se fizermos essa refatoração o código passa a não precisar mais de comentário.



Vamos imaginar um outro exemplo.



//Verifica se o usuário tem direito ao benefício

if(usuario.getIdade() &gt; 10 &amp;&amp; usuario.getIdade() &lt; 20){

 ….

}



Não seria melhor:

if(isUsuarioTemDireitoAoBeneficio(usuario)){

 ….

}



private boolean isUsuarioTemDireitoAoBeneficio(Usuario usuario){

 if(usuario.getIdade() &gt; 10 &amp;&amp; usuario.getIdade() &lt; 20){

  return true;

 }

 return false;

}



Reparem que tiramos o comentário, melhoramos o código e tornamos o mesmo mais legível. Só lendo o código agora você consegue saber o que realmente ele faz.



Outro tipo de comentário totalmente inútil é:



private boolean isUsuarioTemDireitoAoBeneficio(Usuario usuario){

 if(usuario.getIdade() &gt; 10 &amp;&amp; usuario.getIdade() &lt; 20){

  return true; //Retorna verdadeiro

 }

 return false; //Retorna falso

}



O return do método é lógico, não há necessidade de indicar o que o mesmo está retornando. Esses tipos de comentário também são desnecessários.



Em relação à comentários o Uncle Bob fala:



“Qualquer comentário que faça você olhar para outras partes do seu código para entende-lo, não valem os bits que consomem.”



Em regra geral o ideal é não comentar uma vez que as pessoas tem medo para excluir comentários dos códigos e muitas vezes seu código pode ficar melhor sem esses comentários.



Mas ai você pergunta: “Não vou comentar nunca ???”



Existem horas que comentário é importante. Digamos que você tenha um trecho em seu código que vai demandar um tempo de processamento alto, ou a disponibilidade de um recurso e etc. Nesses casos comentário acaba sendo útil. Algumas vezes também não se consegue colocar um nome em um método que explique o porque o desenvolvedor tomou aquela decisão, nesses casos utilizar um comentário não é de todo ruim.



Formatação

“Formatação é importante pois se trata de comunicação.”



Temos que pensar que o código é a maneira que vamos nos comunicar (nós desenvolvedores). Uma pessoa não gostaria de receber uma carta cifrada onde tivesse que interpretar o que nela está escrito, podemos pensar assim na hora de escrever um código.



Imagine ler o seguinte texto:

“Fui à praia com minha namorada e comprei água e sentei na areia e depois de muitas horas joguei frescobol e sai de lá as 18h para ir pra casa e cheguei em casa e tomei banho e fui comer alguma coisa e minha mãe veio falar comigo que não era para eu dormir tarde porque eu tinha aula no dia seguinte.”



Se você tentar ler isso em voz alta você provavelmente sentirá falta de ar. Por que acentuamos as fases ? Exatamente para formatarmos essa leitura. Não fica mais fácil ler dessa forma:



“Fui à praia com minha namorada, comprei água e sentei na areia. Depois de muitas horas joguei frescobol e sai de lá as 18h para ir pra casa. Cheguei em casa e tomei banho e fui comer alguma coisa. Minha mãe veio falar comigo que não era para eu dormir tarde porque eu tinha aula no dia seguinte.”



Diferente né ? no caso do código que produzimos é a mesma coisa. Lembre-se sempre que outro desenvolvedor vai ler o que você está escrevendo e vai ter que interpretar.

Uma outra coisa importante é que se você pega um código bem estruturado, você vai querer mante-lo bem estruturado. É muito ruim para qualquer desenvolvedor pegar um código sem formatação, sem indentação e ter que ler aquilo como se fosse um texto sem virgula, ponto …



Outras observações são as que métodos com conceitos relacionados devem ficar verticalmente próximos e a ordem dos métodos cria um fluxo de leitura melhorando a legibilidade do código. Isso tem haver com o fato de colocar os métodos próximos e tentando seguir um fluxo.



Uma boa indentação é fundamental, mas a indentação não deve passar de dois. Imagine o código abaixo:



if(a&gt;1){

 if(b&gt;1){

  if(c&gt;1){

   if(z&gt;1){

    …

   }

  }

 }

}



Essa “escada” acaba dificultando a compreenssão do código.



Tratamento de erros

Tratamento de erro é de responsabilidade do desenvolvedor e garantir que o código vai ter um tratamento para cada situação. Use exceptions ao invés de retornar códigos de erros. Dentro do seu método você já pode ver o erro que está sendo retornado e trata-lo ali mesmo sem retornar um código para ser tratado.



Procure utilizar exceptions para coisas inesperadas, tipo, seu código está lendo um arquivo e a rede ficou fora. Não utilize tratamentos de erros para fazer outra coisa. Imagine o seguinte exemplo:



try{

 total=total + 1;

}catch(ArithmeticException e){

 total=total-1;

}



Isso é mais difícil de ser mantido e testado. Tratamento de erro é para tratar algo inesperado e não para uma regra de negócio e procure não retornar e não passar “null”.



TDD

Uncle Bob também fala que um programador que não escreve testes unitários não pode ser considerado um desenvolvedor profissional.



Expliquei mais acima a importância dos testes e dei exemplos da importância que os mesmos tem na minha vida hoje em dia.



As 3 regras do TDD são:

 1-) Você não pode escrever um código até que tenha criado um teste falhando

 2-) Você não pode escrever mais teste do que seja suficiente para falhar

 3-) Você não pode escrever mais código do que o suficiente para passar no teste que está falhando.



Outras coisas faladas no TDD é que você não pode ter mais que um conceito por teste. Se você tiver que testar se um CPF é válido, por exemplo, você deve criar alguns testes tais como:



*Se o CPF for em branco

*Se o CPF estiver com menos caracteres

e etc



Ou seja, os testes tem que estar muito bem definido em cada caso.



Os testes devem ter as características F.I.R.S.T:

*F (Fast) - Deve ser rápido. Testes demorados tiram a motivação das pessoas rodarem.

*I (Independent) - Não podem depender um do outro pois se um falha o outro vai falhar também. Você aqui não está testando teste e sim testando funcionalidade.

*R (Reapetable) - Executando mais de uma vez eles devem retornar sempre o mesmo resultado

*S (Self-Validating) - Devem se auto-validar. Respostas booleanas sem precisar de interpretação.

*T (Timely) - Serem feitos antes do código.



Vale ressaltar que os códigos de testes devem ter o mesmo carinho que os códigos que você escreve no seu sistema. Eles também podem sofrer refatorações para melhorar.



A importância da refatoração

Escrever um bom código muitas vezes pode não parecer uma missão tão fácil. Muitos programadores tem o costume de olhar códigos mal feitos e pensar daquela forma : "Foi fulano que fez e não sou eu quem vai consertar.". Muitos ainda tem o costume terrível de propagar o que foi feito e ainda colocar mais código ruim no meio.



Vamos imaginar o seguinte código:



private boolean isStringVazia(String texto){

&nbsp; &nbsp; if (!StringUtils.isNullOrEmpty(texto) &amp;&amp; !texto.equals("")) {

&nbsp; &nbsp; &nbsp; &nbsp; //...

&nbsp; &nbsp; }

}



Concordamos que o "!texto.equals("")" não serve para nada ? Pois é, se fizermos a refatoração abaixo vamos obter o mesmo resultado:



private boolean isStringVazia(String texto){

&nbsp; &nbsp; if (!StringUtils.isNullOrEmpty(texto)) {

&nbsp; &nbsp; &nbsp; &nbsp; //...

&nbsp; &nbsp; }

}



Agora, digamos que ainda assim você estivesse com receio de fazer essa refatoração por algum receio, concorda que a presença de um simples teste unitário poderia resolver o seu receio ? Se realmente o "!texto.equals("")" pudesse influenciar em alguma coisa o seu teste seria o primeiro a quebrar e você poderia voltar com o código anterior.



A refatoração é uma das melhores práticas para você melhorar seu código. Seu código pode ser eficaz, ou seja, fazer o que se deseja, mas pode ser eficiente, fazer o que se deseja da melhor maneira possível.