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

Expressividade no código - Parte 2Hello, pessoal! Tudo certo?
No último artigo, iniciei uma discussão sobre a expressividade no código-fonte e decidi dividi-lo em várias partes para que não ficasse muito extenso. Confira mais alguns argumentos envolvendo este assunto e não hesite em deixar um comentário, caso queira fazer alguma observação!

 

Semana passada, mencionei a importância de uma nomenclatura objetiva, não somente dos métodos, mas também dos parâmetros. Concordo que a clareza dos parâmetros pode parecer uma questão óbvia, porém, tenho quase certeza de que você já encontrou uma chamada de método parecida com essa:

GerarRelatorio(True, False, True, 1, nil, 'C', False);

Embora o nome do método esteja relativamente compreensível, é praticamente impossível desvendar o seu comportamento! Claro, pelo nome, sabemos que um relatório será gerado, mas essa quantidade de parâmetros obscuros nos deixa inseguros de como será a saída real deste relatório. Um simples “chaveamento” em um destes parâmetros (por exemplo, alterar o primeiro parâmetro de True para False) pode modificar consideravelmente o resultado. A única solução é abrir a classe que contém o método e conferir a finalidade de cada parâmetro, que, por ventura, pode não ser agradável:

procedure GerarRelatorio(const GerarDuasVias: boolean;
  const ImprimirDiretoNaImpressora: boolean; const AtivarAgrupamento: boolean;
  const ColunaAgrupamento: integer; var ObjetoExportacao: TExportacao;
  const TipoPapel: string; const SalvarEmPDF: boolean);

 

Na busca pela expressividade, a minha sugestão é utilizar tipos enumerados e constantes para aprimorar a legibilidade dessa chamada. Provavelmente, ainda teríamos que verificar a declaração do método, porém, a própria chamada já seria meramente auto-explicativa. No exemplo abaixo, foi utilizado o prefixo enum para tipos enumerados e letras maiúsculas para constantes. Observe como a chamada se torna mais explícita:

GerarRelatorio(enumGerarDuasVias, enumNaoImprimir, enumAtivarAgrupamento,
  AGRUPAMENTO_POR_DATA, nil, PAPEL_CONTINUO, enumNaoSalvar);

Os tipos enumerados, por sua vez, poderiam ser declarados dessa forma:

type
  TenumNumeroDeVias = (enumGerarViaUnica, enumGerarDuasVias, enumGerarFrenteVerso);
  TenumAcaoImpressao = (enumNaoImprimir, enumImprimirAutomatico, enumExibirPrompt);
  TenumFormaAgrupamento = (enumNaoAtivarAgrupamento, enumAtivarAgrupamento);
  TenumSalvarRelatorio = (enumNaoSalvar, enumSalvarPDF, enumSalvarDOC, enumSalvarHTML);

Diga-se de passagem: o código fica bem mais envolvente!

 

Entretanto, tenho mais uma crítica a respeito do método acima. Mesmo utilizando tipos enumerados e constantes, a quantidade de parâmetros ainda continua a mesma, ferindo o nosso compromisso com a expressividade. Várias vezes já tive que contar o número de parâmetros para saber qual deles se referia à minha necessidade. Algo como: “Vamos ver… 1… 2… 3… 4… 5… sexto parâmetro! É esse que preciso alterar!”. Chato, não? Imagine se houver 20 parâmetros e você precisa alterar o 14º?
Usando uma analogia ao código acima, é como se alguém nos pedisse, apenas verbalmente, para fazer compras em 7 lugares diferentes na mesma viagem. Podemos nos confundir sobre os lugares e o que devemos comprar em cada um deles. Seria mais fácil se nos entregassem, por exemplo, um único papel com as 7 tarefas descritas.
Boa ideia! É isso que também podemos aplicar ao nosso caso! Em vez de passar 7 parâmetros, poderíamos criar uma classe que tenha todos estes valores e utilizá-la como um parâmetro único, conforme abaixo:

type
  TParametrosRelatorio = class
  // como é apenas um exemplo, não vou detalhar os aspectos de visibilidade aqui
  public
    NumeroDeVias: TenumNumeroDeVias;
    AcaoImpressao: TenumAcaoImpressao;
    FormaAgrupamento: TenumFormaAgrupamento;
    ColunaAgrupamento: integer;
    ObjetoExportacao: TExportacao;
    TipoPapel: string;
    SalvarRelatorio: TenumSalvarRelatorio;
  end;

Em seguida, basta alterar a definição do método “GerarRelatorio” para que ele receba um objeto do tipo “TParametrosRelatorio” como parâmetro. Na chamada do método, será preciso apenas preencher um objeto dessa classe com os mesmos valores que estávamos passando como parâmetros anteriormente:

var
  objParametrosRelatorio: TParametrosRelatorio;
begin
  objParametrosRelatorio := TParametrosRelatorio.Create;
  try
    objParametrosRelatorio.NumeroDeVias := enumGerarDuasVias;
    objParametrosRelatorio.AcaoImpressao := enumNaoImprimir;
    objParametrosRelatorio.FormaAgrupamento := enumAtivarAgrupamento;
    objParametrosRelatorio.ColunaAgrupamento := AGRUPAMENTO_POR_DATA;
    objParametrosRelatorio.ObjetoExportacao := nil;
    objParametrosRelatorio.TipoPapel := PAPEL_CONTINUO;
    objParametrosRelatorio.SalvarRelatorio := enumNaoSalvar;
 
    GerarRelatorio(objParametrosRelatorio);
  finally
    FreeAndNil(objParametrosRelatorio);
  end;
end;

 

Nossa, mas compensa mesmo trocar apenas aquela chamada por todas essas linhas de código?
Lembre-se de que o nosso objetivo aqui é aprimorar a expressividade do código-fonte, mesmo que isso implique no acréscimo de algumas linhas, desde que elas realmente sejam necessárias. Além disso, essa mesma classe de parâmetros poderá ser utilizada em outros locais do software, proporcionando uma padronização.
Por outro lado, vale ressaltar que o excesso de expressividade também pode ser ruim, tornando o código maçante. Eventualmente, para encontrar o equilíbrio adequado, é necessário “sacrificar” algumas diretrizes de expressividade. Neste caso, uma alternativa é fazer uso de comentários ou anotações no código-fonte, mas, novamente, só se forem realmente úteis.

 

Na próxima semana, voltarei com a terceira e última parte dessa série de artigos.
Abraço!


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

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.