Clean Code
Autor: Ademir Braga | Publicado: 2010-12-08T05:52:00-08:00

O primeiro objetivo dos desenvolvedores quando criam uma funcionalidade é fazê-la funcionar. Tudo bem, está funcionando, mas e o código, como esta? Será que o código que faz tudo funcionar está legível, fácil de ser entendido, ou seja, será que está limpo?  &nbsp;É preciso preocupar-se com o código, garantir que &nbsp;está legível e bem escrito, pois somente o próprio código pode dizer de forma confiável o que o software realmente faz.  
Mas afinal, o que é código limpo?Em suma um código limpo deve ser:<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Elegante (distinto)<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Eficiente<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Legível<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Simples<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Direto<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Único, sem duplicidades<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Bem escrito<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Deve ser escrito cuidadosamente<!--[if !supportLists]-->·&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->E deve sempre possuir UMA responsabilidade
O código é importante e deve agregar valor ao negócio. Somente um código limpo pode oferecer a qualidade e entendimento que esperamos quando abrimos uma classe. Portanto é necessário que seu código seja limpo e legível para que qualquer um que encontrá-lo possa facilmente entendê-lo evitando perda de tempo e facilitando o trabalho de todos.
Nomes significativosVamos começar pelos nomes. Escolhemos nomes para tudo, desde variáveis até métodos e classes, por causa disso devemos escolhê-los bem.Os nomes devem nos dizer três coisas:&nbsp;Porque existem, o que fazem e como são usados.&nbsp;Devem revelar sua intenção e ser significativos, devem dizer o que estão fazendo e o que significam.Faça distinções significativas, use nomes diferentes dentro de um mesmo escopo. Nomes como a1, a2, a3 são o oposto de nomes que demonstram intenção. São confusos e não informam nada. Evite também usar abreviações ou trocadilhos, escreva exatamente o que você quer dizer, o nome deve ser auto-explicativo. É comprovado que um desenvolvedor passa muito mais tempo lendo código do que escrevendo, por isso não se preocupe em economizar caracteres ao escolher um nome, o fato de um ser claro e objetivo poupará muito mais tempo do futuro do que os caracteres a menos que você digitar ao escolher um nome curto e ruim.Métodos e funçõesO que os tornam&nbsp;métodos e funções&nbsp;fáceis de se ler e entender? A primeira regra dos métodos é que eles devem ser pequenos, a segunda é que eles devem ser menores ainda.Métodos devem conter no máximo 20 linhas e seu nível de identação não pode ser maior que dois.&nbsp;Quanto ao conteúdo, um método deve ter somente UMA responsabilidade. É difícil dizer o que é “uma responsabilidade”, mas uma maneira de descobrir se um método está fazendo mais de uma coisa, é tentar extrair uma parte dele em outro método. Se for possível, realmente o primeiro método tinha mais de uma responsabilidade.Evite passar muitos parâmetros para um método, porque isso pode causar confusão além de dificultar a escrita de testes unitários, pois assegurar que todas as combinações de parâmetros diferentes funcionarão é bem mais trabalhoso. Passar parâmetros booleanos (verdadeiro ou falso) também não é uma boa prática, além complicar a assinatura do método, claramente a função tem mais de uma responsabilidade.&nbsp;Outro detalhe importante &nbsp;que devemos nos preocupar são os efeitos colaterais, esses efeitos são mentiras. Seu método diz que fará uma coisa, mas faz outras “escondidas”.
Observe o método abaixo:public boolean checkPassword(String username, String password) {String passwordStatus = cryptographer.decrypt(password);if(passwordStatus.equals(“OK”)) {&nbsp;&nbsp;&nbsp;&nbsp; Session.initialize();&nbsp;&nbsp;&nbsp;&nbsp; return true;}return false;}O método&nbsp;checkPassword&nbsp;tem o objetivo de verificar a validade da senha, mas além disso está abrindo um sessão, o que não está coerente com a finalidade do método. Não se esqueça,&nbsp;seu método deve sempre ter somente um objetivo.ComentárioComentários podem ser úteis se colocados nos lugares certos, mas também podem ser mentirosos e trazer desinformação. Na verdade,&nbsp;o melhor comentário é aquele que não precisa ser escrito.&nbsp;Podemos usá-los de forma benéfica para informar o leitor de alguma conseqüência ou fornecer a intenção de uma decisão tomada, mas um dos principais motivos para você escrever um comentário é porque o código está difícil de ser entendido. Você acha que o código ficou meio confuso e acha melhor adicionar um comentário?&nbsp;Não, você acha melhor refatorarQuando você pensa em adicionar um comentário em seu código, é um forte indício que ele não está muito bom, não está claroNão use comentários quando você pode usar métodos ou variáveis,explique-se no código, lembre-se que apenas o código pode dizer o que ele realmente fazFormataçãoA formatação do código é importante, pois se trata da forma de comunicação do desenvolvedor, um código todo bagunçado e sem formatação dificulta o entendimento de quem o está lendoA legibilidade do código terá profundo efeito sobre todas as mudanças que serão feitas, seu estilo e disciplina sobrevive sobre estas mudanças.Procure escrever &nbsp;classes com no máximo 500 linhas, classes menores são mais fáceis de se entender. Já para as linhas de código, tente estabelecer um limite de caracteres por linha.&nbsp;Uma boa identação ajuda a visualizar melhor todo o escopo e facilita a identificação de situações e regras relevantes.&nbsp;Tente manter conceitos relacionados mais próximos verticalmente, para criar um fluxo na leitura do código. Use espaços entre operadores, parâmetros e vírgulas. Evite deixar o código todo grudado.Tratamento de erroQuando estamos programando devemos tratar os possíveis erros que nossa aplicação poderá lançar, as coisas podem dar errado e temos que estar certos que nosso código fará o que deve fazerPrefira lançar uma exception ao invés de retornar um código de erro, estes retornos desorganizam a chamada do método e pode-se facilmente esquecer de verificá-losDefina o fluxo do método separando as regras de negócio de erros ou outras situações. Para seus erros crie mensagens informativas, mencionando a operação que falhou e o tipo de falha.
Testes unitáriosHá alguns anos atrás, pouco se ouvia falar de&nbsp;TDD (Test Driven Development). Para muitos TDD erá apenas trechos de código que garantia que o programa “funcionasse”. Mas essa idéia amadureceu bastante entre todos nós, hoje em dia programar com TDD é um conceito de alto nível, por isso, todos os testes que criamos devem ser escritos com código limpo.Queremos dizer muito em nossos testes, por isso que eles devem ser legíveis, claros e simples de entender. Um teste com código ruim e difícil de entender é muito mais trabalhoso para se dar manutenção.&nbsp;Cada teste deve possuir apenas um conceito para facilitar seu entendimento, também deve sofrer alterações da mesma maneira que o código que está testando, tudo isso para manter a flexibilidade e a manutenabilidade do código.
Lembre-se que o código do teste é tão importante quanto o código da produção.Todos sabem que o TDD nos manda escrever o teste antes do código de produção em si, considere essas três regras do TDD:<!--[if !supportLists]-->1.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Você não pode escrever o código até que você tenha criado um teste que falhe.<!--[if !supportLists]-->2.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Você não pode escrever mais testes do que seja suficiente para falhar.<!--[if !supportLists]-->3.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->Você não pode escrever mais código do que o suficiente para passar o teste que está falhando.Se você conseguir seguir essas regras ao desenvolver, você estará praticando TDD corretamente.
ClassesPara começarmos a falar de classes limpas podemos partir da organização das classes. De acordo com os padrões Java, uma classe deve começar com uma lista de variáveis de preferência nesta ordem:<!--[if !supportLists]-->1.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->variáveis publicas e estáticas<!--[if !supportLists]-->2.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->variáveis privadas e estáticas<!--[if !supportLists]-->3.&nbsp;&nbsp;&nbsp;&nbsp; <!--[endif]-->variáveis privadasDepois das variáveis vêm os métodos públicos. Os métodos privados aparecem depois de suas chamadas.&nbsp;Assim como os métodos, as classes também devem ser pequenas. Ninguém gosta de encontrar classes gigantes onde é difícil até mesmo de se encontrar dentro delas. Mas a pergunta é: O quão pequenas elas devem ser?O nome da classe deve representar a sua responsabilidade. Tentar fazer uma breve descrição da classe, explicando o que ela faz pode ajudar a escolher o nome certo. Esta descrição deve ter no máximo 25 palavras e não &nbsp;conter palavras como “mas”, “e”, ”ou”, “se”, pois expressam mais de uma coisa mostrando que há mais de uma responsabilidade.Outra maneira de descobrir o tamanho ideal da classe é analisarmos suas responsabilidades. O Princípio da Única Responsabilidade (Single Responsibility Principle) diz que uma classe deve ter uma, e apenas uma razão para mudar. Quando uma classe possui mais que um motivo para ser alterada é porque provavelmente ela esta fazendo mais coisas do que devia, ou seja, ela têm mais de um objetivo.&nbsp;O princípio nos dá definições de responsabilidade e uma diretriz para o tamanho de uma classe. Tentar identificar responsabilidades nos ajuda a melhorar nosso código e criar melhores abstrações.Para concluir, queremos nosso sistema com pequenas classes, cada uma com uma única responsabilidade, tendo uma razão para mudar e colaborando com outras para alcançar o comportamento desejado do sistema.Design emergenteDesign emergente é um design que nunca é o final,&nbsp;sempre está em evolução. Para conseguirmos criar boas estruturas de código tornando mais fácil de aplicar princípios como SRP e DIP, e assim facilitar a criação de um de bom design de software, Kent Beck estipulou 4 regras para um design simples (Simple Design):1. Rode todos os testesFazer um sistema testável nos obriga e usar boas práticas como classes e métodos pequenos de apenas uma responsabilidade.Quanto mais testes fazemos mais e melhores maneiras e princípios seguiremos para evitar o acoplamento de nosso código. Lembre-se, um sistema testável possui sempre todos os seus testes passando. Um sistema que não é testável, não é verificável e assim não pode ser entregue para produção.2. Remova duplicaçãoDuplicação é o primeiro inimigo de um bom design, ela representa trabalho e riscos adicionais além de uma maior e desnecessária complexidade. Ela se manifesta em linhas de códigos iguais ou parecidas além de aparecerem nas implementações. Usar padrões como Template Method é uma saída para remover duplicações mais complexas.3. Expresse sua intençãoEscrever código que nós entendemos é fácil pois estamos concentrados e ligados no problema que estamos tentando resolver. Mas o próximo que pegar o código para fazer manutenção, não estará tão ligado ao problema como você estava quando implementou a solução.Expressar-se bem no código pode trazer grandes benefícios para o desenvolvimento de um sistema. Além de poupar tempo de quem o mantém. Você pode expressar-se bem em seu código escolhendo bons nomes, deixando métodos e classes pequenas, separando responsabilidades. Lembre-se que você pode sem o próximo a ler este código.4. Diminua o número de classes e métodosSempre que possível, nosso objetivo é manter sistemas pequenos enquanto ao mesmo tempo se mantém &nbsp;métodos e classes pequenas.Princípios e boas práticas não substituem a experiência, mas a partir delas pode se dar o primeiro passo para desenvolver um bom design.
Conclusão
Ao longo do tempo, comecei a perceber a diferença que estas técnicas fazem no meu dia-a-dia como desenvolvedor, pois, elas ajudam a pensar de uma forma mais&nbsp; clara e objetiva sobre o código que escrevo. Pequenas coisas podem fazem grandes diferenças. Tendo em mente estas observações, passei a escrever códigos mais legíveis, de fácil manutenção e mais eficientes. Sempre que vejo um trecho de código que não está muito legível, sinto-me na obrigação de refazê-lo, tornando-o legível limpo e eficiente.