|
Melhorando a manutenibilidade das
aplicações
Autores: Jefferson Carlos Martins
e Manoel Flávio Leal
1. Introdução
Martin Fowler descreve a técnica de programação
chamada Refactoring como sendo um caminho disciplinado de reestruturação
de código-fonte, seja em programação estruturada
ou Orientada a Objetos [1]. A principal idéia do Refactoring é
fazer pequenas alterações no código com o objetivo
de melhorar sua manutenibilidade, aumentando desta forma sua simplicidade,
flexibilidade, clareza e desempenho. É importante ter sempre em
mente que Refactoring não se trata de adicionar novo código
ou novas funcionalidades, mas sim de melhorar os já existentes.
Quando aplica-se as técnicas de Refactoring deve-se tomar alguns
cuidados, pois ao alterar o código-fonte de um programa há
um grande risco de introduzir novos erros, principalmente se estiver realizando
uma manutenção não-estruturada, onde o único
elemento disponível é o código-fonte e a atividade
de manutenção inicia-se com uma penosa avaliação
do código, freqüentemente complicada pela documentação
interna ruim [2].
Também deve-se tomar cuidado para não confundir Refactoring
com Design Pattern.
2. Médodos de Refactoring
Existem noventa e três métodos de Refactoring catalogados
por Martin Fowler, e neste artigo serão demonstradas as principais
e mais utilizadas técnicas de Refactoring [3].
2.1. Extract Method (extração de métodos)
Este é o principal método de Refactoring, pois é
amplamente utilizado por desenvolvedores que começaram suas carreiras
na era da programação estruturada e que tiveram de se adequar
às técnicas de Orientação a Objetos para reduzir
o tempo gasto no desenvolvimento dos projetos, facilitar a manutenibilidade
dos programas e aumentar a reusabilidade de partes do código. O
Extract Method nada mais é que a transformação de
parte do código em um novo método, para aumentar a usabilidade
de uma parte ou para aumentar a legibilidade das funções/procedimentos.
Este método deve ser aplicado quando ocorrerem duplicação
de linhas de código ou quando as funções/procedimentos
forem muito longos e/ou de difícil entendimento, exigindo muitos
comentários no código. Mas lembrem-se de sempre colocar
um nome para o novo método que explique sua utilidade.
Dicas para a aplicabilidade deste método:
1. Analise seu código periodicamente;
2. Quando encontrar partes de código que possuam grande semelhança
entre eles, transforme-o em um método dinâmico (com parâmetros);
3. Quando copiar o código para dentro do novo método,
procure por variáveis locais e parâmetros utilizados pelo
código extraído;
4. Quando o código extraído utilizar variáveis
locais do método de onde ele foi extraído, passe essas variáveis
como parâmetros ao novo método;
5. Sempre execute testes em seu código para verificação
de possíveis erros gerados.
2.2. Extract Class (extração de classes)
Este método é semelhante ao Extract Method, exceto pelo
fato de que ele trata apenas com classes. O Extract Class parte do pressuposto:
se uma classe for muito grande, deve-se transformá-la em duas ou
mais classes.
Dicas para a aplicabilidade deste método:
1. Somente aplique este método para classes que não fazem
parte de nenhum Design Pattern de seu projeto;
2. Não confunda o método Extract Class do Refactoring
com Design Pattern;
3. Utilize este método para criação de classes
abstratas que podem ser generalizadas ou especializadas por outras classes.
2.3. Inline Method (método na linha)
Este método é o inverso do Extract Method, pois ele prevê
a substituição da chamada de uma função/procedimento
pela sua implementação, ou seja, pelo código da função/procedimento.
O Inline Method é utilizado para eliminação de
chamadas desnecessárias de funções/procedimentos,
aumentando assim a performance da aplicação.
Dicas para a aplicabilidade deste método:
1. Quando sua aplicação possuir funções/procedimentos
mal organizados dentro do código, aplique o Inline Method em todos
eles, depois aplique o Extract Method para melhorar a legibilidade do
código;
2. Verifique se o método não é polimórfico
ou se as suas subclasses o especializam;
3. Aplique este método para eliminar funções pequenas
que não sejam reutilizadas em outras partes do código.
2.4. Replace Inheritance With Delegation (substitua herança por
instância)
Este método é utilizado quando uma subclasse usa apenas
parte das funcionalidades da sua superclasse ou não necessite herdar
dados da mesma, então cria-se um campo para a superclasse e ajusta-se
os métodos apropriados para esta, removendo-se a herança.
Deve-se ter em mente que herança é uma técnica
excelente, mas não se deve descuidar ao realizar heranças
de uma classe, pois em muitos casos pode-se notar que utilizamos apenas
alguns métodos ou atributos da superclasse.
Dicas para a aplicabilidade deste método:
1. Crie um campo na subclasse que se refere a uma instância da
superclasse e remova a herança;
2. Mude cada método na subclasse para que use a instância
da superclasse;
3. Verifique as chamadas de métodos da superclasse.
2.5. Replace Conditional With Polymorphism (substitua condições
por polimorfismo)
Este método consiste em dividir uma função/procedimento
que possua muitas condições dentro da mesma em duas ou mais
funções/procedimentos.
Dicas para a aplicabilidade deste método:
1. Caso exista uma função/procedimento que possua várias
condições para funcionamento, divida-a em outras funções/procedimentos,
aumentando, assim, sua legibilidade.
3. Aplicando Técnicas de Refactoring
As técnicas de Refactoring devem ser aplicadas durante o ciclo
de desenvolvimento de uma aplicação para que o software
gerado no fim desse processo seja de fácil manutenibilidade
e legibilidade, mas é aconselhável que se utilize
essas técnicas na fase de manutenção, onde o desenvolvedor
tem a oportunidade de: melhorar o código existente por meio de
revisões do código-fonte, refazer parte de um programa para
melhorar sua legibilidade e eliminar códigos duplicados
para facilitar sua manutenibilidade.
Apesar das técnicas de Refactoring aumentarem a manutenibilidade
do software gerado não devemos aplicá-las quando um código
estiver muito complexo e o recomendável seja recomeçar do
zero, ou quando o projeto estiver muito próximo de sua entrega
final, nesse caso é recomendável se terminar o software
e nas futuras versões aplicar as técnicas de Refactoring.
A maneira mais simples para a aplicabilidade das técnicas de
Refactoring é renomear as variáveis e métodos para
nomes que sejam auto-explicativos como, por exemplo, eliminar variáveis
com o nome i, j, c, x, y, muito utilizadas para controle/contadores, pelos
nomes cont (de contador) ou pos (de posição).
Outra forma seria a limpeza e rearranjo do código, ou seja, dividir
grandes partes de códigos em funções/procedimentos
e criar variáveis temporárias para a simplificação
de expressões complexas.
3.1. Exemplo Prático
Em seguida é apresentado um exemplo de utilização
das técnicas de Refactoring, onde foi utilizado parte de um código-fonte
de um sistema Web, que antes de se aplicar as técnicas de Refactoring
o mesmo possuía 2.710 linhas de código-fonte, sendo que
ainda faltavam adicionar algumas funcionalidades e realizar manutenções
em pequenos procedimentos. Após a aplicabilidade do Extract Method
e do Inline Method, seguindo as orientações de como aplicá-las,
esse código ficou com 1.587 linhas e isso depois de adicionar algumas
funcionalidades e realizar as manutenções que faltavam.
Exemplo:
Código-fonte antes da aplicabilidade das
técnicas de Refactoring
<script language=”JavaScript”>
function validarDados() {
…
valor1590 = docuent.frm.PercRetido400.value;
valor800 = document.frm.PercRetido200.value;
valor100 = document.frm.PercRetido100.value;
valor050 = document.frm.PercRetido050.value;
valor025 = document.frm.PercRetido025.value;
valor0125 = document.frm.PercRetido0125.value;
valor0062 = document.frm.PercRetido0062.value;
valorNR = document.frm.PercRetidoNR.value;
if (valor1590 == “”)
{
alert (“Entrada obrigatória
para o Diâmetro 15,90.”);
document.frm.PercRetido1590.focus();
return (false); }
if (valor800 == “”)
{
alert (“Entrada obrigatória
para o Diâmetro 8,00.”);
document.frm.PercRetido800.focus();
return (false); }
…
if (valorNR == “”)
{
alert (“Entrada obrigatória
para o campo %Retido no Diâmetro NR.”);
document.frm.PercRetidoNR.focus();
return (false); }
…
}
</script>
Neste caso foram renomeados todos
os campos PercRetido para que ficassem seqüenciais, depois eliminou-se
a duplicidade de linhas de código através do Extract Method
transformando aproximadamente 70 linhas em apenas 8 linhas de código.
Código-fonte após a aplicabilidade das
técnicas de Refactoring
<script language=”JavaScript”>
function validarDados() {
…
validarPercRetido();
...
}
function validarPercRetido()
{
for (pos = 1; pos < 11; pos++)
{
if (eval(“document.frm.PercRetido”+pos+”.value”)
== “”) {
alert (“Entrada obrigatória
para o campo %Retido.”);
eval(“document.frm.PercRetido”+pos+”.focus()”);
return false;
}
}
}
</script>
4. Refactoring e Design Patterns
É necessário deixar claro ao leitor que Refactoring e Design
Patterns são metodologias diferentes. A tabela abaixo apresenta
de forma objetiva o que é necessário entender de cada uma
das metodologias.

5. Conclusão
A documentação interna dos sistemas geralmente
é ruim ou quase inexistente, pois muitos desenvolvedores estão
mais preocupados em desenvolver rapidamente suas aplicações
e mostrar produtividade, do que documentar as linhas de código,
visando a manutenibilidade futura pelos seus colegas e até
mesmo por si próprio.
As novas ferramentas de desenvolvimento com o aumento da demanda de
software faz com que as organizações tendam a gastar grande
parte de seus recursos humanos com a manutenção de softwares
antigos, pois a vida útil do software é muito maior do que
a do hardware, e é comum que os softwares sofram manutenções
dos tipos: perfectiva (adicionar novas funcionalidades), adaptativa (adequar
o programa a novas plataformas de software e hardware) e preventiva (prevenir
possíveis erros, ex. bug do milênio). Com isso os desenvolvedores
tornam-se escravos das aplicações que criaram, pois além
de estar em evolução, existe o fato de as manutenções
inferidas poderem introduzir novos erros.
Devido à demanda das manutenções, o que exigia
grandes esforços das equipes, foram realizados estudos e catalogadas
técnicas de manutenção durante a fase de codificação,
chamadas agora de Refactoring.
As técnicas de Refactoring foram divididas em vários métodos
para facilitar o entendimento dos desenvolvedores, bem como a comunicabilidade
entre os mesmos.
Conclui-se que as técnicas de Refactoring devem ser aplicadas sempre
que possível para facilitar o entendimento do código por
outros desenvolvedores e com isso tentar diminuir o tempo gasto no entendimento
do código.
6. Referências
1. FOWLER, M. et al. Refactoring: improving the design of existing code.[S.l]:
Addison-Wesley, 2000.
2. PRESSMAN, R. S. Engenharia de software. São Paulo: Makron Books
do Brasil, 1995. 879 p.
3. Refactorings in alphabetical order. Disponível em: <http://www.Refactoring.com/catalog/index.html>
Acesso em: 08 out. 2003.
jeffecm@pr.gov.br
mfleal@pr.gov.br

|