Refatoração de código usando a IDE

Um dos aspectos mais valorizados num código é ele não ter trechos repetidos sem necessidade, se há código repetido, provavelmente pode ser refatorado. Refatorar significa manter a funcionalidade quebrando um trecho grande de código em pedaços menores, onde os pedaços menores poderão ser reutilizados por serem transformados em procedimentos ou funções e no caso do pascal, um subprocedimento.

Imagine um botão cujo código seja:

var
  ACaption:String;
  ATitle:String;
  AText:String;
  AButtonText1:String;
  AButtonText2:String;
  AResult:TModalResult;
begin
  AResult:=mrNone;
  ACaption:='Ser ou não ser';
  ATitle:='Eis a questão:';
  AButtonText1:='Sim';
  AButtonText2:='Não';
  AText:='Escolha sim ou não';
  with TTaskDialog.Create(self) do
  try
    Caption := ACaption;
    Title := ATitle;
    Text := AText;
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText1;
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText2;
      ModalResult := mrNo;
    end;
    MainIcon := tdiQuestion;
    if Execute then
    begin
      AResult:=ModalResult;
    end;
  finally
    Free;
  end; 

O Objetivo do código é simplesmente mostrar uma mensagem ao usuário:

Refatorando para um método ou função

Daí você decide criar um segundo botão com uma funcionalidade diferente, porém reutilizará uma mensagem de confirmação similar ao utilizado no primeiro botão, e decide dar um Ctrl+C/Ctrl+V e apenas modifica as variáveis que representam o texto a ser exibido:

var
  ACaption:String;
  ATitle:String;
  AText:String;
  AButtonText1:String;
  AButtonText2:String;
  AResult:TModalResult;
begin
  AResult:=mrNone;
  ACaption:='Tem certeza?';
  ATitle:='Vai apagar tudo?';
  AButtonText1:='Sim';
  AButtonText2:='Não';
  AText:='Isso eliminará todos os dados!';  
  with TTaskDialog.Create(self) do
  try
    Caption := ACaption;
    Title := ATitle;
    Text := AText;
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText1;
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText2;
      ModalResult := mrNo;
    end;
    MainIcon := tdiQuestion;
    if Execute then
    begin
      AResult:=ModalResult;
    end;
  finally
    Free;
  end;
(...) 

Provavelmente vocẽ fez isso porque está com pressa, e verdadeiramente é isso que acontece com prazos apertados. Mas depois de um exaustivo trabalho, você concluiu as funcionalidades do programa e agora vem a parte chamada de “melhorias”, onde removeremos comentários desnecessários e …. refatoração. Para refatorar observamos em nosso código, as repetições e daí percebemos que isso aqui:

  with TTaskDialog.Create(self) do
  try
    Caption := ACaption;
    Title := ATitle;
    Text := AText;
    CommonButtons := [];
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText1;
      ModalResult := mrYes;
    end;
    with TTaskDialogButtonItem(Buttons.Add) do
    begin
      Caption := AButtonText2;
      ModalResult := mrNo;
    end;
    MainIcon := tdiQuestion;
    if Execute then
    begin
      AResult:=ModalResult;
    end;
  finally
    Free;
  end;

Esta sendo repetido nos dois botões. Daí você sabe e tem noção que é possivel criar uma função com ela e trocar o trecho acima por uma função. Claro que dependendo de sua experiência isso será fácil fazer, mas porque não usar a IDE do Lazarus para isso. Faça assim:

1. Marque o trecho repetido:

Marcando o trecho que se repete em várias partes de nosso código

2. Vá em Source|Refactoring|Extract Procedure…

3. Selecione o que a extração deverá fazer, geralmente transformando-a método privado quando o trecho será reutilizado no próprio form ou publico quando o mesmo será reutilizado em unidades/formulários diferentes. Há um checkbox quando a IDE detecta que pode ser transformando em uma função, neste caso você pode determinar o tipo de retorno e o nome do método(name of new procedure):

E ao clicar extract….O sistema então criará um código:

O trecho selecionado tornar-se-á um método.

4. A ordem importa?

Em nosso exemplo foi criado o método:

PerguntarDlg( AButtonText2, AButtonText1, AText, ATitle, ACaption);

Mas note que a ordem dos parâmetros não foi decidida por mim, assim, caso não goste vá até o método gerado e acerte a ordem do jeito que planeja usá-los, eu inclusive coloco minhas personalizações:

Personalizando o refactoring automático

Quando você modifica a assinatura do método, use Ctrl+Shift+C para que a IDE faça o ajuste também na declaração.

Agora você tem um método que pode ser usado em dois OnClicks de botões sem duplicações de linhas, apenas modificando os parâmetros usado no método PerguntarDlg.

Refatorar para subprocedimento(sub procedure)

Veja o que há de errado neste código:

Trechos repetidos no mesmo trecho de código

Há trecho de código repetido, nele o programador se preocupou em destruir um objeto chamado “q1” quando o usuário desistisse de executar uma query, mas aí houve repetição do mesmo código, será que há como refatorar já que se trata de objetos locais?

  1. Sim, novamente vamos marcar apenas as linhas repetidas:
Marcamos as linhas a serem refatoradas

2. Selecionamos Source|Refactoring|Extract Procedure…

3. Selecione o que a extração deverá fazer, mas dessa vez marcaremos a opção Sub Procedure e daremos um nome adequado de LiberarMemoria já que o objetivo do trecho de código é destruir objetos:

Usamos sub Procedure quando desejamos refatorar um trecho de um código local

4. Note agora como ficou o código:

A função LiberarMemoria é um subprocedimento para nosso usufruto

Um procedimento LiberarMemoria tornou-se um subprocedimento para que possamos reutilizá-lo em todos os trechos que antes tinham:

q1.close;
q1.free;

Assim nosso código tornou-se menor, mais eficiente e muito melhor de entender.

Conclusão

É sempre preferível começar um projeto tomando a iniciativa em refatorá-lo desde o inicio, mas sabemos como às vezes é necessário correr contra o tempo para entregar as coisas dentro do prazo e deixamos de tomar essa iniciativa desde o principio. No final do projeto é bom saber que podemos usar a IDE do Lazarus para nos ajudar a refatorar nossas repetições de código.