Durante o início da minha carreira não me importei em como ficava meu código final. O “bom e velho”contém ironia go horse era meu modus operandi. Simplesmente codificava sem parar e sem pensar demais. Muito control+c/control+v, gerando vários pontos de duplicidade. Achava que para programar bastava entender a sintaxe da linguagem, ter lógica de programação e entregar o que era solicitado funcionando.
Isso fazia com que eu escrevesse, mesmo que indiretamente, um código somente para que eu mesmo pudesse lê-lo.
Entre a experiência que adquiri com o tempo e os estudos, conheci um conceito que entendo como fundamental para se tornar um desenvolvedor melhor e o qual defendo e compartilho com meus pares. O código limpo.
E porque essa importância tão grande? Simples, quando escrevemos código na empresa onde trabalhamos ou no projeto open-source que contribuímos, compartilharemos este código com outras pessoas. O código desenvolvido por nós não nos pertence. E, por se tratar de algo que será utilizado e evoluído por outras pessoas, é de suma importância que seja legível. Nosso trabalho é, em algum nível, comunitário e, portanto, não é feito de nós para nós mesmos apenas. Temos que nos preocupar, enquanto membros de uma equipe, com todo o organismo responsável por aquela aplicação.
E é exatamente isso que o código limpo prega, que devemos escrever nossos softwares de forma coesa. Não somente para nós mesmos, mas para que as demais pessoas desenvolvedoras que peguem o código feito por nós consigam ler e entender rapidamente, podendo evoluí-lo (ou corrigi-lo quando necessário) de forma eficiente sem precisar de gambiarras workarounds ou grande esforço mental para entendê-lo. É importantíssimo compreendermos que não trabalhamos sozinhos e que desenvolver código testável, manutenível e legível é benéfico para todas as pessoas envolvidas. Estamos todos trabalhando para alcançar um mesmo objetivo e se todos assimilarem que código bem escrito é essencial para a vida útil e evolução do software, estaremos um passo mais próximo do sucesso.
Robert C. Martin (mais conhecido como Uncle Bob) escreveu um livro de título homônimo ao conceito, onde explica, com exemplos, formas de se escrever código limpo. Nele, Uncle Bob inicia brincando que a métrica para qualidade do código é quantidade de “WTF por minutos” que falamos ao lê-lo. Quanto mais vezes, pior.
Vou trazer à tona dois pontos que acho importante para que possamos plantar a sementinha do código limpo em nossas mentes e começar a entender o conceito e sua necessidade.
NOMES
Devemos dar nome significativos às coisas. Nomes legíveis dão contexto às coisas. Não devemos escrever código que seja lido apenas para os interpretadores e máquinas. Em um primeiro momento, pode parecer legal e diferentão, no entanto, fazer a leitura deste código dias ou meses depois pode se tornar um tormento.
Martin Fowler, outro grande arquiteto de software, foi categórico ao dizer “qualquer idiota pode escrever código que o computador entende. Bons programadores escrevem código que outros humanos entendem”.
Vejamos o exemplo abaixo:
O que significam as variáveis cmt e p? Qual é o contexto desta aplicação? Somente com este pequeno trecho de código é impossível dar qualquer informação acerca da aplicação na qual está inserida.
Perceba que no segundo exemplo a leitura é fluída. Você compreende em qual contexto esse trecho está inserido sem nem conhecer o resto do código fonte do sistema. Ler uma função de cima para baixo como se fosse texto corrido é um bom indicativo que a função está bem escrita, enquanto no exemplo de cima, é necessário mais conhecimento sobre outros trechos da aplicação para alcançar o mesmo nível de entendimento. O esforço mental para entendê-lo é maior e devemos evitar a todo custo esse mapeamento mental.
Selecione uma palavra por conceito. Imagine que uma aplicação qualquer tem vários pontos onde objetos são inseridos no banco de dados, devemos utilizar sempre a mesma palavra para descrever a ação. Funções como “adicionarUsuario”, “incluirMensagem”, “salvarRegistro” podem causar confusão em outra pessoa que estiver trabalhando no sistema pois a falta de padrão pode dar a entender que essas funções executam coisas diferentes. Selecione uma - neste caso, entre adicionar, incluir ou salvar - e mantenha sempre ela por todas as funções.
Utilize nomes passíveis de busca, por exemplo, uma constante “SEGUNDOS_POR_DIA” é mais fácil de ler e entender seu objetivo do que “SGS_DIA” ou “SPD”. Não devemos ter medo de dar nomes grandes para as coisas. É preferível que façamos isso, desde que a intenção e o objetivo daquela coisa fique explícita, do que economizar teclas e deixar um nome obscuro.
Além disso, use nomes pronunciáveis. No exemplo anterior, cmt, p e cmtArr não são palavras conhecidas da nossa língua, por isso, fica difícil pronunciar seus nomes. Na refatoração, as variáveis foram nomeadas com palavras que conseguimos pronunciar, são palavras que existem e que conhecemos, isso facilita na leitura e até na hora de conversar com alguma outra pessoa sobre aquele trecho específico.
Seguindo a regra acima vamos evitar também a utilização de notação húngara. Antigamente fazia sentido sua utilização, pois, tanto as linguagens de programação quanto os editores não eram tão avançados a ponto de informar à pessoa quando havia um erro de tipagem. Atualmente, os editores já são capazes de identificar e apontar esse tipo de erro durante o tempo de desenvolvimento. Portanto, colocar algo como public string strNome; não faz sentido, pois o tipo já é atribuído na declaração da propriedade e qualquer valor diferente de string que for passado à propriedade será alertado pelo editor.
FUNÇÕES
Uncle Bob escreve:
“As funções devem fazer apenas uma coisa. Devem fazê-la bem. Devem fazer apenas ela”.
Esta descrição está diretamente ligada ao Single Responsibility Principle, primeiro conceito do SOLID. O qual não irei me estender aqui. Mas #ficaAdica de estudo.
Um indicativo de que a função é responsável por executar mais de uma coisa é tentar nomeá-la deixando explícito tudo o que ela faz. Se este nome tiver algo como ValidarEAdicionar, obviamente a função está executando duas funcionalidades distintas e, portanto, é uma função passível de refatoração. Como a regra é que a função seja responsável por apenas uma coisa, dar nome para ela se torna algo mais fácil caso a regra seja seguida.
Outra forma de saber se uma função é responsável por mais de uma coisa, é o tamanho dela. Muitas linhas de código, geralmente, indicam que existe mais de uma coisa acontecendo ali. Como expliquei anteriormente, para que o código seja legível, ele deve ser escrito de forma que possamos lê-lo de forma corrida “como um texto” e com uma função com poucas linhas de código é mais fácil alcançar este método de leitura.
Um ponto importante é que, como uma função deve executar apenas uma tarefa, consultas e comandos devem ser funções distintas. Ou seja, sua função de obter dados deve ser uma e a função que atribui o valor outra. No livro, Uncle Bob exemplifica com:
E sua utilização da seguinte forma:
A função set deve ser responsável unicamente por atribuir o valor ao atributo. Até porque o retorno dela não deixa claro em quais momentos será retornado true ou false.
Neste caso, ele refatora o código para ficar da seguinte maneira:
Desta forma fica claro qual o objetivo de cada função.
Vale lembrar que um código limpo é, também, um código testável. Para tanto, é preferível que as funções tenham nenhum, um ou dois parâmetros apenas. Claro que devemos avaliar a necessidade de cada parâmetro e pode haver casos onde é preciso utilizar três ou, em alguns pouquíssimos casos, mais. Porém, é aconselhável que não utilizemos mais do que dois parâmetros, pois, a quantidade de combinações possíveis de valores para ambos os parâmetros ainda é aceitável quando trabalhamos com dois ou menos. A partir de três, as combinações começam a expandir em nível exponencial, o que torna a cobertura de teste mais complexa e, portanto, mais difícil de atingir um nível satisfatório.
Quando uma função recebe três ou mais parâmetros, é preferível que, em vez disso, se crie uma classe e uma instância dela seja o único parâmetro para aquela função.
Por fim, uma função não deve conter efeitos colaterais. O efeito colateral é quando sua função promete fazer uma coisa, mas, por trás dos panos, faz outra também. E esta segunda coisa não era prevista por quem faz a chamada à função. No livro, Uncle Bob exemplifica esta parte da seguinte forma:
Podemos ver que, além de validar a senha, este método também é responsável por inicializar a sessão. Isto é gravíssimo, pois, outra pessoa que chamar o método sem conhecer o código fonte irá esperar que ele apenas faça a validação da senha. Essa sessão inicializada não é esperada e, provavelmente, em algum momento isso será motivo de dor da cabeça.
OUTRA DICA
Além do código limpo, outro conceito que me ajudou a melhorar a legibilidade do meu código é o Object Calisthenics. Não irei falar sobre aqui, pois o link acima já é bem detalhado sobre cada uma das regras que o regem.
CONCLUSÃO
Veja, neste artigo apenas introduzi dois pontos iniciais sobre o código limpo. O livro de Robert Martin é muito mais denso e detalhado do que isso.
A intenção aqui é provocar você a compreender que, enquanto membro de uma equipe, deve se preocupar com que o código desenvolvido seja legível para todas as pessoas envolvidas e que, se todos pensarem dessa mesma forma, a vida útil do software será maior, seu tempo de resolução de problemas será menor e a sanidade mental das pessoas será mantida.
Top comments (0)