Orientações sobre parâmetros de um método

Orientações sobre parâmetros de um métodoFala, pessoal, tudo certo?
Sabemos que refatoração, extração de métodos e subrotinas nos ajudam bastante na programação, principalmente quando o assunto é reutilização de código. Na declaração de novos métodos, algumas vezes é necessário criar alguns parâmetros para que o método execute adequadamente as operações internas. O artigo de hoje é justamente relacionado com estes parâmetros! Acompanhe!

 

Como parte das técnicas de melhoria da expressividade no código, os parâmetros de métodos também devem receber uma atenção especial. Durante o desenvolvimento de um projeto, estaremos em um constante trabalho de criação e consumo de vários métodos e gostaríamos que a interpretação de cada um deles fosse simples. Desejamos que, ao acessar a declaração ou implementação de um método, seja fácil compreendê-lo. Por isso, a seguir, apresento 5 dicas sobre como aplicar as técnicas de Clean Code na escrita e utilização de parâmetros de métodos.

 

1) Nomenclatura
Essa dica é primordial, claro! Quando declaramos variáveis internas, empregamos prefixos e nomes que sejam condizentes com o que elas armazenarão, não é? Para os parâmetros de métodos, devemos seguir o mesmo critério, porém, com um detalhe: nomeá-los de uma forma particular para indicarmos que são parâmetros ao invés de variáveis. Uma sugestão é adicionar o prefixo “p” (de parâmetro), acompanhado do prefixo do tipo e, finalmente, do nome. Veja o exemplo abaixo:

procedure VerificarPedidosPendentes(
  pdtDataInicial, pdtDataFinal: TDateTime; pnCodCliente: integer);

Na implementação do método, saberemos que as variáveis que começam com o prefixo “p” são, na realidade, parâmetros. Saberemos também que, se o prefixo “dt” vem logo em seguida, significa que o parâmetro é do tipo data. Uma das vantagens dessa dica é permitir uma melhor orientação durante a leitura do método, caso seja necessário realizar uma manutenção ou interpretar a regra de negócio.

 

2) Parâmetros constantes
Opa, tem algo faltando na dica anterior! Na implementação do método, não gostaríamos que as datas inicial e final recebam valores diferentes, já que podem comprometer a funcionalidade ou mesmo o retorno. Devemos “proteger” os valores que vieram por parâmetro para que não sejam modificados. Para isso, podemos adicionar a palavra-chave const na declaração dos parâmetros, indicando que só a leitura é permitida:

procedure VerificarPedidosPendentes(
  const pdtDataInicial, pdtDataFinal: TDateTime; const pnCodCliente: integer);

No exemplo acima, os valores de “pdtDataInicial”, “pdtDataFinal” e “pnCodCliente” não poderão ser alterados dentro do método.

 

3) Parâmetros default
Algumas vezes, pode ser necessário definir um valor padrão para um método, caso ele não seja informado. Dessa forma, o método irá funcionar como esperado, sem apresentar erros ou inconsistências devido à falta de algum dado. Bom, talvez você tenha pensado na seguinte solução:

procedure CalcularIPI(const pnCodProduto: integer; pnPorcentagemIPI: real);
begin
  if pnPorcentagemIPI = 0 then
    pnPorcentagemIPI = 5;
 
  ...
end;

Porém, há uma forma mais “limpa” de definir este valor padrão. Basta indicá-lo na própria assinatura do método:

// declaração
procedure CalcularIPI(const pnCodProduto: integer; pnPorcentagemIPI: real = 5);

No método chamador, por sua vez, nem precisaremos informar um valor para este parâmetro, já que, em sua ausência, o valor “5” será assumido!

var
  nCodProduto: integer;
  nValorIPI: real;
begin
  nCodProduto := StrToInt(Edit1.Text);
  nValorIPI := CalcularIPI(nCodProduto); // apenas um parâmetro foi informado
end;

 

4) Quantidade de parâmetros
Já comentei essa dica na segunda parte do artigo sobre expressividade no código. Vale dar uma passadinha por lá!
Quando o número de parâmetros começa a crescer (diga-se, mais de três parâmetros), o recomendado é criar um objeto que contenha todos esses valores e seja passado como um parâmetro único, dispensando o uso excessivo de vírgulas na chamada do método. Sendo assim, ao invés da chamada abaixo:

if EnviarEmailCliente(Edit1.Text, Memo1.Lines.Text,
   RadioGroup1.ItemIndex, ComboBox1.Text, ListBox1.Items.Text, OpenDialog1.FileName) then
    ShowMessage('E-mail enviado com sucesso!');

Eu recomendaria a forma a seguir:

var
  objParametros: TParametros;
begin
  objParametros := TParametros.Create;
  try 
    objParametros.Assunto := Edit1.Text;
    objParametros.Mensagem := Memo1.Lines.Text;
    objParametros.TipoFormatacao := RadioGroup1.ItemIndex;
    objParametros.ContaEmail := ComboBox1.Text;
    objParametros.Destinatarios := ListBox1.Items.Text;
    objParametros.Anexo := OpenDialog1.FileName;
 
    if EnviarEmailCliente(objParametros) then
      ShowMessage('E-mail enviado com sucesso!');
  finally
    FreeAndNil(objParametros);
  end;
end;

O número de linhas de código pode ser relativamente maior, mas, por outro lado, o código definitivamente se torna mais autoexplicativo.

 

5) Parâmetros de saída
A diferença entre procedimentos e funções é que essas retornam um valor para o método chamador, como a função abaixo, que retorna um valor do tipo integer:

// declaração
function SomarQtdeComprasClientes: integer;
 
// chamada do método
var
  nQtdeCompras: integer;
begin
  nQtdeCompras := SomarQtdeComprasCliente;
  ...
end;

Porém, em algumas ocasiões, é necessário que um método retorne mais de um valor! É aqui que os parâmetros de saída entram em ação como uma alternativa. No exemplo abaixo, duas variáveis são criadas no método chamador e passadas como parâmetros de saída para outro método (utilizando a palavra reservada out do Delphi), no qual irá preenchê-las. Tecnicamente, então, podemos dizer que o método “retorna” dois valores.

// declaração
procedure ConsultarDadosComprasCliente(out pnQtdeCompras: integer; out pnTotalCompras: real);
 
// chamada do método
var
  nQtdeCompras: integer;
  nTotalCompras: real;
begin
  ConsultarDadosComprasCliente(nQtdeCompras, nTotalCompras);
  // após a chamada, as duas variáveis "voltam" preenchidas
end;

A minha dica será controversa. Muitos desenvolvedores provavelmente irão discordá-la, mas acho interessante compartilhar a minha visão. De modo geral, devo dizer que sou bastante cético quanto ao uso de parâmetros de saída. Um dos motivos é que, parâmetros, por si só, já são interpretados como entrada. Quando utilizamos um método, assumimos que os parâmetros que informaremos serão subsídios para que ele funcione, e, convenhamos, é a maneira lógica de se pensar. Na minha opinião, ao invés de criar um método que retorne dois valores, é melhor criar dois métodos que retornem apenas um valor.
Além disso, parâmetros de saída também podem confundir o desenvolvedor em alguns casos. Considere a chamada abaixo, baseada no livro de Robert Martin:

AdicionarTexto(sTexto);

Como você a interpreta? A variável “sTexto” é uma entrada (será adicionada a um texto já existente), ou uma saída (um texto será adicionado à variável “sTexto”)? A solução, claro, é verificar a declaração do método. Se estiver em outra classe, será necessário acessá-la. Embora imperceptível, esse esforço consome um tempo e interrompe o raciocínio. A minha sugestão é evitar parâmetros de saída sempre que possível.

 

E você? Tem mais alguma recomendação?
Deixe um comentário!

Abraço!


 

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

2 comentários

  1. Excelente Artigo, muito bom mesmo, Parabéns! Continue escrevendo que está ajudando muitos desenvolvedores como eu. Obrigado!

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.