CODEsign: Faça duas vezes!

CODEsign: Faça duas vezes!E aí, pessoal, tudo certo?
Há algumas semanas, compartilhei um dos artigos do blog no grupo Clean Code Alliance do LinkedIn e recebi alguns comentários na publicação. Um dos membros, chamado Max Kleiner, mencionou uma técnica bem bacana que pode colaborar com a escrita de código limpo. Trata-se do CODEsign. Leia o artigo e conheça as propostas dessa técnica!

 

Como de costume, para facilitar a associação do termo, vale apresentar um exemplo logo de início!
Suponha que você desenvolveu, pela primeira vez, um aplicativo para exportar um conjunto de dados para uma planilha do Excel. Durante o desenvolvimento, você estudou e utilizou bibliotecas de I/O para gravar arquivos e algumas funções para trabalhar com exportação de dados. Perfeito.
Agora, faço uma pergunta: se fosse necessário desenvolver o mesmo projeto novamente, você faria diferente?

Eu aposto que sim!

Levando em conta o conhecimento que você adquiriu desenvolvendo o projeto na primeira vez, é bem provável que, ao implementá-lo pela segunda vez, o código ficaria bem melhor. O motivo é óbvio. Com base na experiência anterior, aprimora-se a capacidade de elaborar algo mais profissional. O simples fato de criar um método com um nome mais expressivo já traz um aspecto mais profissional ao código.

Essa é a ideia do CODEsign: implementar a mesma funcionalidade duas vezes! Considera-se que, na segunda vez, há uma possibilidade significativa de escrever um código mais limpo. Você, desenvolvedor, já deve ter passado por essa experiência e sabe do que estou falando. 🙂

Coincidentemente, isso aconteceu comigo há alguns dias. Desenvolvi um miniprojeto para ler um arquivo texto e importar o conteúdo para uma base de dados (semelhante a um processo de ETL), porém, depois de finalizado, mesmo funcional, não fiquei satisfeito com a quantidade de linhas e com a estrutura do código. Decidi refazer o projeto, mas, como já tinha conhecimento das deficiências da primeira tentativa, considerei formas diferentes de escrever o código. O resultado foi surpreendente! Criei uma classe de leitura chamada TLeitor, herdando de TStringList, e declarei vários métodos que antes haviam sido repetidos, melhorando notavelmente o projeto como um todo.

Na prática, apliquei o CODEsign! 🙂

 

Só isso?
Não, claro que não! O conceito do CODEsign é relativamente amplo, no entanto, para não estender o artigo, decidi reunir as partes mais voltadas para programação e aproveitei para incrementar um pouco do meu conhecimento nessa ideia.
Para ter um efeito realmente satisfatório, o CODEsign consiste em ponderar cinco aspectos ao reescrever a funcionalidade, conforme listados abaixo.

 

1) Simplicidade
Reflexão: “Existe uma forma mais simples de implementar a funcionalidade?”
Pode parecer óbvio, mas muitas vezes a simplicidade passa despercebida. O código abaixo faz a leitura de uma string e exibe os valores que estão separados por vírgula (nome, sobrenome e cidade):

const
  VALORES = 'Andre;Celestino;Maringa;';
var
  nPosicaoSeparador, nPosicaoTexto: smallint;
  sNome, sSobrenome, sCidade: string;
begin
  nPosicaoSeparador := PosEx(';', VALORES, 1);
  nPosicaoTexto := 1;
  sNome := Copy(VALORES, nPosicaoTexto, nPosicaoSeparador - nPosicaoTexto);
 
  nPosicaoTexto := nPosicaoSeparador + 1;
  nPosicaoSeparador := PosEx(';', VALORES, nPosicaoTexto);
  sSobrenome := Copy(VALORES, nPosicaoTexto, nPosicaoSeparador - nPosicaoTexto);
 
  nPosicaoTexto := nPosicaoSeparador + 1;
  nPosicaoSeparador := PosEx(';', VALORES, nPosicaoTexto);
  sCidade := Copy(VALORES, nPosicaoTexto, nPosicaoSeparador - nPosicaoTexto);
 
  ShowMessage(sNome);
  ShowMessage(sSobrenome);
  ShowMessage(sCidade);
end;

Diga-se de passagem: o código ficou confuso, não?
Se pesquisarmos na documentação da linguagem, ou mesmo na internet, é possível encontrar funções exclusivas (e, claro, mais simples) para essa finalidade, poupando toda a complexidade criada anteriormente:

const
  VALORES = 'Andre;Celestino;Delphi;';
var
  oListaValores: TStringList;
  i: smallint;
begin
  oListaValores := TStringList.Create;
  ExtractStrings([';'], [' '], VALORES, oListaValores);
  for i := 0 to oListaValores.Count - 1 do
  begin
    ShowMessage(oListaValores[i]);
  end;
  FreeAndNil(oListaValores);
end;
 

 

2) Performance
Reflexão: “Existe uma forma mais rápida de executar a operação?”
Considere o código abaixo. Para cada produto, há um cálculo de desconto:

DataSetProdutos.First;
while not DataSetProdutos.Eof do
begin
  if DataSetProdutos.FieldByName('Valor').AsFloat > 0 then
  begin
    AplicarDesconto(DataSetProdutos.FieldByName('Codigo').AsInteger);
    DataSetProdutos.Next;
  end;
end;

 

A condição IF é realmente necessária? Imagine que, de 1000 produtos, apenas 200 deles possuem valor maior que zero. 800 iterações do loop de repetição seriam, na prática, em vão. Se aplicarmos um filtro antes do loop, teríamos um ganho considerável de performance:

DataSetProdutos.Filter := 'Valor > 0';
DataSetProdutos.Filtered := True;
DataSetProdutos.First;
while not DataSetProdutos.Eof do
begin
  AplicarDesconto(DataSetProdutos.FieldByName('Codigo').AsInteger);
  DataSetProdutos.Next;
end;

 

3) Integridade
Reflexão: “O código está suscetível a erros?”
O código a seguir carrega o conteúdo de um arquivo dentro de um componente TMemo:

Memo1.Lines.LoadFromFile('C:\Importacao\Entrada.txt');

Ops, mas espere aí… se o arquivo não existir, ocorrerá uma exceção! É nosso dever garantir a integridade da execução do aplicativo.

if not FileExits('C:\Importacao\Entrada.txt') then
begin
  ShowMessage('O arquivo de importação não está disponível.');
  Exit;
end;
 
Memo1.Lines.LoadFromFile('C:\Importacao\Entrada.txt');

 

 

4) Confiabilidade
Reflexão: “O código é capaz de tratar exceções e se recuperar de falhas?”
Dessa vez, o método abaixo faz o download de um arquivo em um diretório FTP para o computador:

IdFTP.Connect;
IdFTP.Get('ftp/Arquivo.xml', 'C:\Aplicativo\Arquivo.xml');

Primeiramente, o que acontecerá se a conexão com a internet for interrompida durante o download? Em segundo lugar, é importante garantir que a conexão FTP seja fechada após a transferência do arquivo. Estes eventos podem ser solucionados com os tradicionais try..except e try..finally:

try
  try
    IdFTP.Connect;
    IdFTP.Get('ftp/Arquivo.xml', 'C:\Aplicativo\Arquivo.xml');
  except
    ShowMessage('Falha no download. Verifique a conexão com a internet.');
    ExcluirArquivosCorrompidos;
  end;
finally
  IdFTP.Disconnect;
end;

 

5) Redundância
Reflexão: “É possível evitar a duplicação de código?”
Algumas vezes, a redundância no código pode prejudicar a leitura do código. Veja o exemplo abaixo:

ConsultarVendasDoCliente(Query.FieldByName('Codigo').AsInteger);
ConsultarPagamentosPendentes(Query.FieldByName('Codigo').AsInteger);
EnviarEmailParaCliente(Query.FieldByName('Codigo').AsInteger);

Notou a quantidade de vezes que o FieldByName é utilizado? Para evitar essa redundância, podemos declarar uma simples variável:

var
  nCodigoCliente: integer;
begin
  ...
  nCodigoCliente := Query.FieldByName('Codigo').AsInteger;
 
  ConsultarVendasDoCliente(nCodigoCliente);
  ConsultarPagamentosPendentes(nCodigoCliente);
  EnviarEmailParaCliente(nCodigoCliente);
end;

 

Pessoal, os exemplos são bem básicos e não devem ser tomados como referência didática da empregabilidade do CODEsign. Na prática, ao codificar uma funcionalidade pela segunda vez, além dos aspectos acima, o desenvolvedor pode descobrir novas abstrações, resultando na criação de novos componentes, bibliotecas ou classes, como foi o meu caso!

Creio que você já tenha se deparado com um projeto antigo e pensado: “Nossa, que código feio. Hoje eu faria completamente diferente…”, não é? Tecnicamente, não deixa de ser a prática do CODEsign! 🙂

 

Até a próxima, pessoal!


 

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

2 comentários

  1. Muito bom, passei por isso na época de tcc na faculdade, a linguagem era PHP. Seis meses depois de entregue, voltei e modifiquei varias funções, muitas coisas, enfim.
    Como agora a ferramenta é Delphi, aprendendo um pouco a cada dia com posts como esse. Valeu André, forte abraço!

    1. Olá, Alex!
      Obrigado pelo comentário! Acredito que a maioria (ou todos) programadores já passaram por uma situação parecida. Isso é gratificante, pois indica que adquirimos mais experiência desde que programamos pela primeira vez.

      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.