A relevância da expressividade no código – Parte 3

A relevância da expressividade no código - Parte 3Saudações, leitores!
O artigo de hoje é a finalização da série sobre expressividade no código-fonte. Nos dois últimos artigos, ressaltei a importância de escrever nomes expressivos para métodos e parâmetros, bem como apresentei alguns exemplos. A terceira parte é apenas um conjunto de recomendações para fechar esse assunto com chave de ouro. Confira!

 

A expressividade no código vai um pouco além do que foi apresentado nos artigos anteriores. Como bons programadores, também devemos nos atentar a outros detalhes que contribuem para essa atividade. A seguir, listo três recomendações para que você, programador, lembre-se delas ao escrever suas próximas linhas de código!

 

1) Nome de variáveis
Se escrever nomes melhores para os nossos métodos é uma boa prática, porque não fazer o mesmo para as nossas variáveis? Assim como acontece com os métodos, nomes objetivos irão melhorar a leitura do nosso código, facilitando a interpretação. Considere as seguintes variáveis:

var
  Soma: real;
  Qtd: integer;
  Nome: string;

Ao ler essas declarações, eu pensaria: “Soma do quê? Quantidade do quê? Nome de quem?”. E sabe qual seria a única forma de descobrir suas finalidades? Lendo os valores que são atribuídos à elas. Aí já é tarde. Isso demonstra a evidência de que essas variáveis não são nada expressivas. Imagine, então, se elas forem declaradas com palavras compostas:

var
  SomaDoFaturamento: real;
  QuantidadeDeVendas: integer;
  NomeDaTransportadora: string;

Bem melhor, concorda? Pelo nome, já tenho uma ideia do tipo de informação que cada variável irá receber. A propósito, o uso de preposições nos nomes (“do”, “de”, “da”) são opcionais. Se a variável “QuantidadeDeVendas” fosse declarada somente como “QuantidadeVendas”, a interpretação seria essencialmente a mesma. Eu apenas optei por inclui-las para que o código se assemelhe à leitura natural de um texto.
Agora, uma dica importante que aprendi na empresa em que trabalho: procure adquirir o hábito de utilizar notação húngara e adicionar um prefixo no nome da variável para indicar o seu tipo. Confira:

var
  rSomaDoFaturamento: real;
  iQuantidadeDeVendas: integer;
  sNomeDaTransportadora: string;
  bClienteComPendencias: boolean;

Dessa forma, em qualquer linha do código será possível identificar o tipo da variável, evitando a necessidade de mover a barra de rolagem para o início do método para verificá-lo. Olha só que interessante: só pelo fato de aprimorarmos o nome da variável, conseguimos deixar explícito tanto o tipo quanto o propósito!
No exemplo acima, utilizei a inicial de cada tipo (“r”, “i”, “s” e “b”) como prefixo, mas nada impede que você mesmo crie suas próprias convenções! Caso queira se aprofundar mais sobre essa prática, pesquise por “Notação Húngara” no Google.

 

2) Condições booleanas
Cuidado com elas! Essas condições podem ser o motivo de uma falha de interpretação que pode resultar em um tempo longo (e chato) de depuração. Observe a condição abaixo:

if (iQtdeVendas > 0) and (Query.FieldByName('Cancelado').AsString <> 'N')
  and (not DataSet.FieldByName('Status').AsString = 'P')
  and (RadioGroup.ItemIndex = 1) then
  GerarRelatorio;

Acho que nem preciso comentar, não é? 🙂
Seria algo como: “Se isso for verdade, e aquilo for diferente que N, e o status não for igual a P e opção 1 estiver marcada, então…” – observe que só a leitura da condição como um todo já denota um princípio de dificuldade. Bom, sem dizer que utilizei apenas 4 condições como exemplo. Imagine se fossem 6, 8? (Sim, elas existem!)
A recomendação é transformar toda essa condição em uma função que retorne um valor booleano:

if ValidarGeracaoRelatorio then
  GerarRelatorio;

A função declarada acima, por sua vez, também pode ser simplificada:

function ValidarGeracaoRelatorio: boolean;
var
  bVendaEncontrada: boolean;
  bVendaCancelada: boolean;
  bClientePendente: boolean;
  bConfirmaGeracao: boolean;
begin
  bVendaEncontrada := iQtdeVendas > 0; // essa variável seria global ou parametrizada
  bVendaCancelada := Query.FieldByName('Cancelado').AsString = 'S';
  bClientePendente := DataSet.FieldByName('Status').AsString = 'P';
  bConfirmaGeracao := RadioGroup.ItemIndex = 1;
 
  result := (bVendaEncontrada) and (not bVendaCancelada)
    and (not bClientePendente) and (bConfirmeGeracao);
end;

Sentiu-se incomodado com a quantidade de vezes que a palavra “and” foi utilizada? Eu também! Alternativamente, podemos empregar uma lógica diferente para o retorno dessa função:

begin
  ...
 
  // o retorno inicia-se como falso
  result := False;
 
  // se não há registros, o método é interrompido (retorno falso)
  if not bVendaEncontrada then
    Exit;
 
  // se a venda estiver cancelada, o método é interrompido (retorno falso)
  if bVendaCancelada then
    Exit;
 
  // se o cliente estiver pendente, o método é interrompido (retorno falso)
  if bClientePendente then
    Exit;
 
  // se o usuário não confirmou a geração, o método é interrompido (retorno falso)
  if not bConfirmaGeracao then
    Exit;  
 
  // logo, o retorno somente será verdadeiro se todas as condições forem satisfeitas
  result := True;
end;

 

3) Métodos pequenos
A terceira e última recomendação é relacionada ao tamanho dos nossos métodos. Quanto menores eles forem, mais objetivos serão. Digo isso por dois motivos: primeiro, métodos grandes ferem o princípio de responsabilidade única (SRP), ou seja, tendem a realizar mais do que deveriam, assumindo mais de uma responsabilidade; segundo, a leitura fica comprometida, já que, dependendo dos loops e condições, teremos que mover a barra de rolagem várias vezes para interpretar o método ou acompanhar o fluxo de depuração.
Quando notar que o método está tomando uma dimensão extensa, considere imediatamente a possibilidade de refatorá-lo. Ou então, quando se deparar com um método grande, divida-o em vários pedaços, de modo que cada um deles fique pequeno. Releia a segunda recomendação desse artigo para compreender essa vantagem.
Para finalizar, vale mencionar uma frase cômica que Uncle Bob, autor do livro “Clean Code”, escreveu sobre essa prática:

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

 

Abraço, leitores!
Na próxima semana, bateremos um papo sobre avanço tecnológico.


Confira as outras partes desse artigo:

A relevância da expressividade no código – Parte 1
A relevância da expressividade no código – Parte 2
A relevância da expressividade no código – Parte 3


 

Compartilhe!
Share on FacebookTweet about this on TwitterShare on LinkedInShare on Google+Pin on PinterestEmail this to someone

4 comentários

  1. Excelente artigo!
    Já utilizo os métodos apresentados.
    Mas achei muito interessante da forma que foi descrita, muito objetiva.

    Parabéns

  2. Gosto muito dos seus artigos! Parabéns pela didática.
    Uso Scrum, então as nomenclaturas fazem parte …mas ainda não consigo (Não sei se por falta de interesse ou por falta de vergonha!) programar totalmente OO. ai sai pecando em não usar algumas de suas dicas.

    1. Olá, Benedito, tudo bem? Obrigado pelo retorno sobre o artigo!
      Não se torture por ainda não utilizar OO em sua totalidade. Isso é uma prática adquirida aos poucos!
      O importante é que você está preocupado com a qualidade do seu código. Parabéns!

      Abraço!

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Preencha o campo abaixo * Time limit is exhausted. Please reload CAPTCHA.