/ Agile

Clean Code - Nomes significativos.

Olá pessoal, este é o primeiro artigo sobre Clean Code e prometo que no final desta série você terá uma nova visão sobre seu código. Esta série de artigos foi baseada no livro de Robert C. Martin, chamado Clean Code - A Handbook of a Agile Software Craftsmanship, o livro relata as experiências profissionais de Robert com o propósito de exemplificar e realçar os pontos positivos da utilização do Clean Code.

Então iniciaremos falando sobre o custo de ter um código confuso. Se você é desenvolvedor há mais de 3 anos, provavelmente já se deparou com um código confuso que o fizesse trabalhar mais lentamente ou lhe trouxe problemas ao tentar entender as funcionalidades do código. Em um código confuso a produtividade da equipe de desenvolvimento tende à zero, com o passar do tempo a única alternativa será investir mais recursos no projeto sem haver segurança de retorno.

grafico

O gráfico demonstra a redução da produtividade sobre o tempo de manutenção em um código confuso. O Clean Code oferece benefícios a longo prazo, que proporcionam uma melhor leitura da codificação, otimização no tempo de refatoração, melhoria contínua nas funcionalidades e melhor aproveitamento do tempo dedicado a testes.

O conceito do Clean Code é baseado nos 3 R’s da Arquitetura de software, que são Readability (legibilidade), Reusability (reuso) e Refatoring (refatoração). Os 3 conceitos se complementam para a obtenção de um projeto sustentável à empresa.

3Rs

A legibilidade prioriza a clareza na escolha de nomes, padronização da escrita e formatação da codificação, tendo como principais características:

  • Nomes de variáveis;
  • Nomes de funções;
  • Formatação;
  • Níveis de aninhamento;
  • Quantidade de linhas em funções;
  • Quantidade de Argumentos passados a uma função.

A reutilização diz respeito à criação de funcionalidades que possam ser reutilizadas dentro do sistema, priorizando fatores como:

  • Um nível de abstração;
  • Tamanho da função;
  • Indentação;
  • Níveis de aninhamento;
  • Efeitos colaterais;
  • Parâmetros de saída.

O refatoramento diz respeito à capacidade do sistema em permitir a otimização da estrutura sem que outras funcionalidades sejam afetadas. Nesta etapa são priorizados os seguintes fatores:

  • Efeitos colaterais isolados;
  • Testes constantes de funcionalidades;
  • Refinamento sucessivo.

A partir desta introdução aos conceitos da Arquitetura de Software vamos aprofundar nossos conhecimentos sobre a legibilidade do código. Iniciaremos falando sobre a parte mais importante do seu código, nomes.

Nomes Significativos

Os nomes estão presentes em todos os componentes de nosso projeto, sendo quase tão importantes quanto as funcionalidades codificadas nele. Criamos nomes para projetos, pastas, módulos, arquivos, classes, variáveis, funções, entre outros. Os nomes dizem muito sobre o desenvolvedor responsável, eles devem expressar as vontades de seu criador, os propósitos para que foi criado e todo o seu apreço pelo projeto. O livro nos traz algumas recomendações para atender essa regra, abaixo vamos citar e exemplificar cada uma delas.

Nomes que Revelem seu Propósito

Todos os nomes usados no projeto, principalmente nomes de funções e variáveis, devem revelar o propósito do desenvolvedor. Esta tarefa parece ser de fácil adoção, porém escolher bons nomes leva tempo, portanto, sempre dedique um tempo para nomear ou melhorar os nomes contidos no código e lembre-se que o nome deve ter sentido para outras pessoas. Para criar nomes que revelem seu propósito devemos seguir os seguintes conceitos:

  1. Nomes de variáveis devem informar seu conteúdo ou sua finalidade.
  2. Nomes de funções devem informar a atividade executada pela função.
  3. Nomes bons dispensam comentários, sempre troque comentários sobre variáveis por um nome que facilite o entendimento.
  4. Faça um bom uso do Naming Convention. Nomes de constantes no padrão SNAKE_CASE e demais nomes no padrão CamelCase.

Para exemplificar vamos tomar uma aplicação que possui uma funcionalidade que calcula os dias passados após uma data de vencimento e as variáveis são declaradas da seguinte forma:

Date dvencimento;
int sumD;

A variável não passa a ideia do programador, ela se torna um enigma dentro do código que exigirá um tempo para que o leitor do código a decifre. Mesmo que o trecho tenha comentários explicativos se torna uma maneira ruim de declarar a variável, ferindo várias regras impostas a nomenclatura. A melhor forma é se expressar por meio dos nomes, sendo claro e objetivo, demonstrando a sua intenção para aquele trecho.

Date diaDoVencimento;
int somaDiasAposvencimento;

Podemos notar que a leitura do código se torna mais intuitiva dessa maneira, podemos passar ao leitor o que será feita com essa variável ou a finalidade para que foi criada. Claro que quantidade não é sinal de qualidade, então procure minimizar os nomes o quanto puder e, durante o desenvolvimento, sempre pensar em nomes melhores para atribuir aos elementos para gerar maior clareza. Quando pensamos em expressividade através dos nomes podemos ser levados a alguns erros que ocorrem apenas pela perspectiva do leitor, então a próxima recomendação é sobre informações transmitidas de forma errada.

Evite Informações Erradas

Desenvolvedores devem evitar a transmissão de ideias falsas, que têm o intuito de esclarecer mas apenas passam visões erradas. Informações erradas ocorrem com muita frequência na codificação, utilizando siglas, acrônimos ou nomes de outros elementos. Por exemplo, hp aix e sco são nomes usados em plataformas Unix ou variantes, levando à má interpretação do trecho.

Utilize a IDE para a seu favor, geralmente os Ambientes de Desenvolvimento oferecem listas com nomes existentes no sistema e no projeto. Evite nomes que contenham objetos utilizados pelo Ambiente, como: List ou String. Busque palavras no plural que revelem o conteúdo da variável.

Durante o desenvolvimento também devemos evitar nomes muito parecidos, pois podem ocasionar em confusão no momento em que seja preciso utilizar aquele elemento e também dificulta a uma funcionalidade importante da IDE de autocompletar palavras. Lembre-se que ao criar um objeto levamos em conta o nome dado àquela classe, não os comentários ou lista de métodos que ela contém.

Nunca utilize as letras "l" ou "O" para nomear variáveis, o problema ocasionado é a similaridade com os números um e zero. Além de dificultar a localização da variável pela IDE essa prática fere a próxima recomendação, nomes pronunciáveis.

Faça Distinções Significativas

As IDE’s não possibilitam que dois elementos tenham o mesmo nome, isso implica ao desenvolvedor utilizar nomes semelhantes ou em sequência como: a1, a2, a3, esta prática além de dificultar a leitura vai contra a regra anterior. Não há problemas em usar prefixos, porém sempre pensando em distinção significativa, devemos analisar os nomes para retirar trechos desnecessários como ambiguidades. Também devemos evitar palavras muito comuns ou vagas, pois podem passar ao leitor vários significados e permitir que ele entenda da forma que quiser dentro das possibilidades.

Podemos exemplificar por meio dos métodos de acesso disponibilizados em um sistema de controle de usuários:

getConta();
getContas();
getContasInfo();

Neste exemplo como podemos identificar as ações executadas por cada método e em que situação utilizar?
Sempre utilize nomes que passem ao leitor a importância da diferença entre os elementos e quais as ações executadas por ela.

Use Nomes Pronunciáveis

Uma das maiores habilidades do ser humano é se comunicar, para isso utilizamos palavras e somos bons com elas. Todas as palavras utilizadas na comunicação são pronunciáveis, portanto devemos tirar proveito dessa habilidade criando nomes pronunciáveis. Um nome que não se pode pronunciar dificulta a comunicação entre a equipe sobre aquele elemento e também o repasse de informação para novos desenvolvedores, consumindo tempo para explicação.

Suponha a seguinte situação, você está criando um código em que é extremamente necessário armazenar a data e hora de criação e modificação do perfil de seus usuários, você precisa conversar com algum membro da equipe sobre as características e ações do método, este foi criado da seguinte forma:

private Date gerDMAHM;
private Date ModDMAHM;
ou então
const yyyymmdstr = moment().format('YYYY/MM/DD');

Muito provavelmente não haverá uma comunicação objetiva sobre essas variáveis. A melhor forma é transcrever este nome para um que seja mais explicativo como:

private Date gerarDataHora;
private Date modificarDataHora;
const DATA_ATUAL =moment.format('YYYY/MM/DD');

Devemos tomar cuidado também ao utilizar números mágicos, aquela constante presente somente naquela funcionalidade e que temos a certeza de que o código funcionará bem com ele ali.

setTimeout(blastOff, 86400000);

Qual é a responsabilidade desse parâmetro? Como seu leitor poderá ligar o parâmetro à funcionalidade? Vamos melhorar este exempo:

const MILISEGUNDOS_EM_UM_DIA = 86400000;
setTimeout(blastOff, MILISEGUNDOS_EM_UM_DIA);

Use nomes passíveis de busca

Nomes compostos por uma só letra ou números dificultam a busca. A utilização de nomes com apenas uma letra traz confusão ao código, além de ferir as regras anteriores pode gerar desperdício de tempo. Devemos facilitar a busca pela IDE, evitando utilizar nomes que gerem conflitos com outras partes do código. Apenas utilize nomes com uma única letra em variáveis locais no interior de métodos pequenos, o tamanho do nome deve ser proporcional ao tamanho do escopo.

for (int j=0; j < 34; j++){
    s += (t[j]*4)/5;
}

Podemos reescrever o código da seguinte forma:

int diasIdeais = 4;
const int DIAS_TRABALHADOS_POR_SEMANA = 5;
int soma = 0;
for(int j=0; j < NUMERO_DE_TAREFAS; j++){
    int diasTrabalhados = tarefasEstimadas[j] * 
    diasIdeais;
    int color = "#005cc5">semanasTrabalhadas = (diasTrabalhados / 
    DIAS_TRABALHADOS_POR_SEMANA);
    sum += semanasTrabalhadas;
}

Evite Codificações

Durante a execução do projeto temos de lidar com muita codificação, portanto não devemos acrescentar mais. Codificar as informações de escopo apenas adiciona uma tarefa extra ao leitor. Nomes codificados raramente são pronunciáveis, além de ser fácil escrevê-los incorretamente.

A Notação Húngara

A notação húngara era praticada em linguagens antigas, quando era necessário indicar o tipo de dados que se está declarando. O Fortran, linguagem criada pela IBM na década de 1950, torna a primeira letra em uma indicação do tipo, utilizar uma ou duas letras dificultava o entendimento do desenvolvedor sobre o tipo em que se estava trabalhando. Com essa limitação surgiu a notação húngara que propõe a utilização do tipo da variável logo após seu nome.

As linguagens modernas oferecem tipos muito melhores e os compiladores os tornam obrigatórios. As IDE’s atualmente oferecem várias funcionalidades que auxiliam o desenvolvedor, como exceções que informam quando o uso dos tipos foi feita inadequadamente. Com o avanço dos editores a notação húngara apenas causa obstáculos e dificultam a leitura.
Ex:

String emailString;
int somaInt;

A notação húngara não é mais necessária e não agrega valor ao código, apenas polui a leitura.

Evite Mapeamento Mental

Devemos evitar a tradução mental de nomes, atribuindo nomes de domínio ou de solução que sejam diretos e objetivos. Esta regra ressalta o problema em utilizar nomes com apenas uma letra, pois permite que seu leitor interprete de maneira livre, apenas levando em conta o conceito contido naquele trecho de código.
De maneira geral, desenvolvedores são muito espertos e provavelmente consigam mapear uma variável apenas pelo contexto do trecho, porém devemos pensar em todos os possíveis leitores. Uma diferença entre um programador esperto e um programador profissional é o entendimento sobre a clareza em que expressa seu código.

Nomes de Classes

Classes e objetos devem ter nomes com substantivos e deve-se evitar palavras que gerem conflitos com componentes da linguagem.
Ex:

class Cliente{

Nomes de Métodos

Os nomes utilizados para métodos devem conter verbos, seus nomes devem descrever a intenção do desenvolvedor naquele trecho, como excluirPagina, salvar… Devemos nomear métodos de acesso, alteração e autenticação segundo seus valores e adicionar os prefixos get, set ou is de acordo com os padrões java.

Selecione uma Palavra por Conceito

Faça uma análise de palavras do domínio e coloque um padrão na utilização de conceitos. Por exemplo, é confuso utilizar pegar, recuperar e obter como métodos equivalentes em classes diferentes. Os ambientes de desenvolvimento, como o Eclipse ou IntelliJ, oferecem dicas relacionadas ao contexto como listas com métodos e nomes de variáveis que você pode chamar em determinado objeto. Mas devemos notar que a lista retornada não oferece os comentários sobre a função, então deve-se ter clareza na escolha dos nomes para que nesta etapa não seja necessário revisar trechos de código.

Use Nomes a partir do Domínio da Solução

Lembre-se sempre de que serão programadores que lerão seu código, então utilize termos da área, nomes de padrões e termos matemáticos. Não é prudente utilizar um nome a partir do domínio do problema, pois seria um transtorno identificar o conceito do problema para saber o significado do nome.
Nomes como AccountVisitor ou JobQueue se expressam muito bem ao programador, então nomes técnicos, normalmente, são os mais adequados.

Adicione um Contexto Significativo

Há poucos nomes significativos por si só, portanto devemos utilizar nomes que tragam contexto ao leitor. Utilize nomes expressivos e que se complementam para formar uma linha de raciocínio, os nomes em uma classe devem se complementar e transmitir a ideia de seu desenvolvedor.

Observe que é fácil de identificar variáveis com os seguintes nomes nome, sobrenome, telefone, cidade, estado e cep. Utilizando essas palavras em conjunto podemos passar ao leitor a ideia da composição de um endereço, mas caso as variáveis sejam isoladas será difícil passar o contexto, a exemplo vizualizar somente a palavra estado e associar ao contexto de um endereço.

Não Adicione Contexto Desnecessário

Em sistemas desenvolvidos no domínio da AZ, seria uma péssima ideia adicionar prefixos "AZ" em todas as classes. Este contexto adicionado vai contra as suas ferramentas, pois a busca resultará um resultado enorme de todas as classes que tenham o prefixo.

Nomes curtos geralmente são melhores, apenas precisam ser claros. Sempre revize seu código e melhore os nomes utilizados, gaste um tempo a mais com o objetivo de criar um código legível.

Conclusão

As maiores dificuldades em escolher bons nomes são boas habilidades em descrição de sua intenção e um histórico cultural compartilhado. Sempre devemos melhorar a legibilidade do código, revisar a atribuição de nomes e não ter receio em fazer mudanças que possam contribuir para a melhoria do código.

Lembre-se que "qualquer idiota escreve código para a máquina interpretar. Bons programadores escrevem código para que outros humanos entendam"

Referências

Robert C. Martin, Clean Code: A Handbook of Agile Software Craftsmanship.
Disponível em https://www.investigatii.md/uploads/resurse/Clean_Code.pdf.

Augusto, Felipe. Conceitos de Código Limpo.
Disponível em https://github.com/felipe-augusto/clean-code-javascript#Índice