Você está na página 1de 13

Anti-Padrões de Software e Refactorização

"Lava Flow", "Jumble" e "Moving Features Between Objects"


Moreirinha, Délio; Aguiar, Jaime; Santos, Miguel Ângelo; Amaral, Vítor

Resumo

Este documento insere-se no processo de Avaliação da Unidade Curricular "Engenharia de Software"


do Mestrado em Engenharia Informática e de Computadores do Instituto Superior de Engenharia de
Lisboa para o semestre de Inverno do ano lectivo de 2010/2011, e aborda a temática dos Anti-padrões de
Software "Lava Flow" e "Jumble" e, o padrão de Refactorização MFBO ("Moving Features Between
Objects").

Palavras-chave: Software, Anti-Padrão, Refactorização.

1. - Introdução
"O que é um Anti-Padrão de Software e Refactorização ?"

Um Anti-Padrão no contexto do desenvolvimento de Software é uma metodologia para detectar


problemas indicando processos para os corrigir. Na realidade, um Anti-Padrão pode ser visto
como um Padrão para a detecção de incorrecções no desenvolvimento e manutenção de
Software. Os Anti-Padrões apresentam, para além de métodos para a detecção de problemas,
padrões para a sua correcção definindo processos de reengenharia (Refactorização).

Como causa de muitos dos problemas encontrados, estão o que se designa por "7 Pecados
Mortais":

- "A Pressa" - Prazos muito apertados levam muitas vezes ao


negligenciar de actividades importantes.

- "A Apatia" - A atitude de não resolver problemas


conhecidos... o "deixa andar...".

- "Eu sei tudo..." - Recusa dos participantes (Gestores,


Programadores, etc.) no processo de desenvolvimento de aprender e
implementar soluções e metodologias já testadas e com resultados
positivos.

1
- "A Preguiça" - A utilização das soluções mais simples e
menos trabalhosas ao invés das adequadas.

- "O Complicar..." - A impetuosidade na criação de


um Sistema pode levar a que o mesmo seja demasiado
complexo e de difícil manutenção.

- "A Ignorância" - A falta de motivação para entender as


coisas.

- "O Orgulho" - A política do "Orgulhosamente Sós..." recusando a


utilização de componentes que não tenham sido desenvolvidos pela
equipa/empresa.

Estes denominados "Pecados" são transversais ao processo de desenvolvimento de Software e


podem ser encontrados nos vários níveis e etapas do mesmo. Por esta razão, os Anti-Padrões
de Software são normalmente agrupados em três categorias:

 Anti-padrões de Desenvolvimento - São normalmente aqueles que se dedicam à


identificação e correcção de falhas e más práticas no código desenvolvido.
 Anti-padrões de Arquitectura - Específicos para a identificação de erros na
Arquitectura de um Sistema.
 Anti-padrões de Gestão de Projectos de Software - Anti-padrões relacionados com
as falhas na Gestão de um Projecto de Desenvolvimento de Software (por exemplo:
Incorrecta alocação de recursos).

Os Anti-Padrões são organizados de forma a fornecerem uma descrição da forma geral,


identificação de sintomas e causas e, descrever as consequências. Para ser considerado um
Anti-Padrão, deverá ainda fornecer padrões para correcção dos problemas, ou seja, estratégias

2
para a sua resolução. Alguns autores denominam como Pseudo-Anti-Padrão a todos aqueles
que apenas oferecem estratégias para detecção e não apresentam metodologias para correcção.
A esses processos de correcção é dado o nome de reengenharia ou refactorização (" Software
Refactoring").

É de realçar que a utilização de Anti-Padrões é considerada actualmente como uma forma de


melhorar o Software desenvolvido devendo ser aplicado periodicamente ao longo de todo o
processo.

Este documento aborda o Anti-Padrão de Desenvolvimento "Lava Flow", o Anti-Padrão de


Arquitectura "Jumble" e o Padrão de Refactorização "Moving Features Between Objects" e
está organizado da seguinte forma:

1.- Introdução
2.- Anti-Padrão de Desenvolvimento "Lava Flow" - Descrição deste Anti-Padrão
3.- Anti-Padrão de Arquitectura "Jumble" - Descrição deste Anti-Padrão
4.- Padrão de Refactorização "Moving Features Between Objects" - Descrição deste Padrão
5.- Conclusões

2. - Anti-Padrão de Desenvolvimento "Lava Flow"[1]


Actualmente é fundamental acautelar a escalabilidade de um Sistema e garantir uma fácil
manutenção do mesmo. Para tal, é fundamental utilizar as principais regras de boas práticas no
desenvolvimento de Software. No entanto, a realidade é que ainda hoje os processos de
desenvolvimento de Software são maioritariamente caóticos acontecendo muitas vezes que a
estrutura dos Sistemas implementada desvia-se substancialmente do planeado através da análise,
desenho e arquitectura.

Muitas vezes as equipas de desenvolvimento não seguem as regras de boas práticas durante o
processo de programação o que leva a situações de uma quase total incompreensão de
funcionamento do Sistema e do código que o suporta.

De forma a resolver estas situações foram definidos Anti-Padrões de Desenvolvimento que


ajudam a identificar problemas e que fornecem Padrões de Refactorização para a sua correcção.
O Anti-Padrão "Lava Flow" (Fluxo de Lava) é um deles.

Este Anti-Padrão é identificado ao nível aplicacional e é também designado por "Dead Code"
(código morto). É muitas vezes encontrado em Sistemas (ou partes de um Sistema) que são
originalmente desenvolvidos como métodos de investigação mas que acabam em produção.
Caracteriza-se por resultar de fluxos de versões implementadas e ao longo das quais vai ficando
código que não é documentado e que poucos, ou ninguém sabe posteriormente qual a sua
funcionalidade, código que não é utilizado, excertos com comentários não compreensíveis, entre
outras causas. A analogia com a expressão "Fluxo de Lava" resulta do facto de, estes tipos de
incoerências terem um efeito similar ao da lava de um vulcão, ou seja, ao longo do processo de
desenvolvimento, actualização e manutenção de um Sistema vão se criando como que rochas de
código que já ninguém consegue ou quer remover.

3
Este Anti-Padrão é muito encontrado em Sistemas com alguns anos e nos quais, as equipas de
desenvolvimento, estando ainda em fase de pesquisa, procuravam várias soluções para atingir
um determinado objectivo, muitas vezes com o único intento de conseguir protótipos para
realizar uma demonstração descurando aspectos importantes como a documentação. O código
então desenvolvido ia ficando não sendo removido ou sequer documentado... predominava
então a lógica de "Se está a funcionar é melhor deixar ficar como está...".

Exemplo de Código Morto:

Destas situações resulta um código fragmentado, classes e procedimentos que não são
imediatamente enquadráveis com o Sistema, variáveis não utilizadas, etc.. Os fluxos de código
que daqui derivam são muitas vezes de uma complexidade tal que dão a ideia de se estar perante
algo realmente importante no Sistema mas que na realidade ninguém sabe explicar o que faz ou
porque existe.

Mesmo quando existe um programador que se recorda de parte da funcionalidade do código, a


tendência dos restantes membros da equipa é decidir não mexer visto o "código não provocar
quaisquer problemas em lá estar e, até pode ser crítico para o funcionamento do Sistema... e
nós não temos tempo para mexer nele !". A opção seguida é a de trabalhar à volta desse código
sem lhe tocar.

No entanto este tipo de atitude apenas agrava o problema aumentando o "Fluxo de Lava" do
Sistema e é, naturalmente, uma má prática por várias razões:

4
 O código que se vai "deixando estar" pode se tornar extremamente pesado em termos de
memória consumida comprometendo o desempenho do Sistema
 Ao reutilizar código acabamos por estar a proliferar o "Código Morto" aumentando o
"Fluxo de Lava"
 Os "Fluxos de Lava" são difíceis de analisar, verificar e testar consumindo muito tempo
e, consequentemente, recursos financeiros e humanos.

Sintomas da existência de "Fluxos de Lava"

 Existência de variáveis não utilizadas ou que não se entende a sua função


 Fragmentos de código espalhados pelo Sistema
 Funções, Classes ou segmentos de código complexos e que são aparentemente
importantes para o funcionamento do Sistema mas que não estão documentados não se
percebendo claramente a sua relação com a Arquitectura do Sistema
 Difícil percepção da Arquitectura do Sistema
 Blocos inteiros de código comentado sem uma explicação ou documentação
 Existência de vários comentários do género "A alterar", "A remover", "Testes", etc.
 Interfaces não utilizadas, obsoletas ou inexplicáveis

Consequências

 "Código Morto" deixado no Sistema


 Proliferação do "Fluxo de Lava" conforme o código é reutilizado
 A não detecção e respectiva correcção do "Fluxo de Lava" poderá levar a um
crescimento exponencial do problema à medida que outros programadores intervêm no
processo de desenvolvimento
 Com o aumento do Fluxo rapidamente se torna impossível de documentar o código ou
até compreender suficientemente a sua Arquitectura de forma a realizar melhorias ao
Sistema

Principais Causas

 Código resultante do processo de I&D (Investigação e Desenvolvimento) colocado em


Produção sem um planeamento da Gestão de Configurações
 Distribuição descontrolada de código inacabado. Implementação de várias abordagens
experimentais desenvolvidas para atingir determinadas funcionalidades
 Código escrito por programadores isolados
 Inexistência de Gestão de Configurações ou inconformidade com políticas de Gestão de
Processos
 Falta de uma definição da Arquitectura do Sistema ou processos de desenvolvimento
não guiados por Arquitectura. Esta situação ocorre frequentemente quando existem
equipas de desenvolvimento transitórias
 Objectivos do projecto pouco claros ou que sofrem frequentes mutações.

5
 Tendo em vista a realização de demonstrações dentro dos prazos existe muitas vezes
uma tendência a efectuar precipitadamente alterações ao código. Este código não é
posteriormente revisto comprometendo a Arquitectura definida não sendo produzida
qualquer documentação que justifique as alterações realizadas.
 Falhas na Arquitectura definida. Alguns dos compromissos assumidos durante a fase de
Análise de Requisitos revelam-se ao fim de muito trabalho desenvolvido inviáveis.
Muitas vezes o código produzido até então não é removido

Solução de Refactorização

Quando o "Fluxo de Lava" é detectado é fundamental evitar que ocorram alterações à


Arquitectura. No entanto, isso poderá ser necessário, pelo que os responsáveis pelo Projecto
deverão suspender o processo de desenvolvimento até ser definida claramente a Arquitectura a
implementar e esta ser divulgada a todas as equipas de desenvolvimento.

A definição da Arquitectura poderá exigir uma ou mais actividades de "descoberta" do actual


Sistema. Esta actividade é necessária para localizar os componentes que realmente são
utilizados e necessários ao Sistema, assim como, para identificar as linhas de código que podem
ser apagadas de forma segura não influenciando o seu funcionamento. Esta actividade é morosa
e complexa devendo ser realizada por pessoas com experiência na realização deste tipo de
processos.

Durante o processo de eliminação do "Código Morto" surgem muitas vezes "bugs" no Sistema.
Quando tal acontecer, deverá evitar-se ao máximo a correcção desse erro sem antes perceber
totalmente a causa do mesmo. Devemos investigar todas as dependências que o código
removido possuía pois, desta forma, iremos conseguir definir com maior clareza a Arquitectura
que deverá ser implementada.

Como evitar "Fluxos de Lava"

Para evitar a ocorrência de "Fluxos de Lava" no desenvolvimento de um Sistema é fundamental


que, para além de uma correcta Análise de Requisitos e Desenho da Arquitectura, seja bem
definido o processo de Gestão de Configurações por forma a que este garanta o cumprimento do
que foi determinado nessa mesma Arquitectura e, em particular, quando ocorrem alterações aos
requisitos inicialmente definidos.

É importante que os interfaces de Software sejam claramente definidos, estáveis e bem


documentados. Um forte investimento em interfaces de software de qualidade irá certamente
produzir grandes dividendos no futuro, principalmente quando comparado com os custos que o
processo de refactorização em situações de "Fluxo de Lava" provocará.

Os responsáveis pela processo de desenvolvimento devem ter autoridade suficiente para


suspender o processo sempre que detectem situações de "Fluxo de Lava" até que uma
Arquitectura possa ser claramente definida e divulgada.

6
Em todos os Anti-Padrões a prevenção é sempre mais barata do que a correcção. É portanto
fundamental que em qualquer Projecto se faça um forte investimento numa boa Arquitectura e
na formação das equipas de desenvolvimento logo no começo.

3. - Anti-Padrão de Arquitectura "Jumble"[2]

Este Anti-Padrão identifica as situações em que os elementos horizontais e verticais de um


Sistema são misturados originando uma Arquitectura instável.

Os elementos verticais dependem de cada componente aplicacional e especificidades do


Software enquanto que os elementos horizontais são aqueles que são comuns entre componentes
e implementações especificas.

Normalmente os dois são misturados pelas equipas de desenvolvimento e arquitectos, mas ao


fazer isto, estão a limitar a capacidade de reutilização e robustez dos vários componentes de
Software do Sistema e da sua Arquitectura. Os elementos verticais provocam dependências do
Software que limitam a sua reutilização e escalabilidade. A mistura dos dois elementos
(verticais e horizontais) torna os Sistemas menos estáveis e inviabiliza muitas vezes a
reutilização.

Solução de Refactorização

O primeiro passo deverá ser o de reconhecer os elementos horizontais e identificá-los numa


camada separada da Arquitectura. Posteriormente deveremos utilizar esses elementos de forma
a capturar as funcionalidades comuns na interoperabilidade da Arquitectura.

Por exemplo, os elementos horizontais são abstracções das implementações específicas do


subsistema:

1. Adicionar elementos verticais como extensões de funcionalidades especificadas e para


melhoria da performance.

2. Introduzir metadados na Arquitectura

3. Substituir os elementos estáticos do design (horizontal e vertical) pelos elementos


dinâmicos (metadados).

7
Um equilíbrio entre os elementos horizontais, verticais e metadados numa Arquitectura conduz-
nos a um Software bem estruturado, reutilizável e escalável.

4. - Padrão de Refactorização "Moving Features Between Objects"[3]


"Refactoring is the process of changing a software system in such a way that it does not alter the
external behavior of the code yet improves its internal structure."

MartinFowler, "Refactoring - Improving The Design Of Existing Code"

O Padrão de Refactorização MFBO ("Moving Features Between Objects") fornece um


conjunto de processos que nos permitem mover elementos do código entre objectos de forma a
melhorar a sua estrutura e, consequentemente, a sua performance.

São definidos oito processos de quando e como realizar essas operações. A descrição de
quando usar cada um dos processos é a seguir apresentada.

"Move Method"

Quando um método utiliza mais recursos de outra classe do que na que está definido ou,
quando um método será usado mais vezes por outra classe do que na que está definido.

Deveremos criar um novo método na segunda classe e removê-lo da primeira.

Ao movermos métodos podemos fazer classes mais simples tornando mais nítida a
implementação de responsabilidades de cada uma. No entanto, devemos ponderar sempre se ao
efectuar este processo estamos realmente a obter algum ganho no nosso Sistema.

"Move Field"

Devemos utilizar este processo quando verificamos que um determinado campo é, ou será,
usado mais por outra classe do que na qual está definido.

Criamos um novo campo da segunda classe, alteramos em todos os locais onde era utilizado e
removemo-lo da primeira classe.

8
Deveremos ponderar mover um determinado campo quando constatamos que existem mais
métodos noutra classe a utilizá-lo. Essa utilização pode ser indirecta com o objectivo de obter
ou definir métodos. Se verificarmos que tal movimentação faz sentido então deveremos fazê-la.

"Extract Class"

Verificando que possuímos uma classe que faz o trabalho de duas deveremos utilizar este
processo.

Criamos uma nova classe e movemos os campos e métodos relevantes da primeira para a nova
classe.

Este processo deve ser utilizado quando uma classe tem muitos métodos e muitos dados, ou
seja, quando uma classe se tornou demasiado grande e complexa para ser facilmente
compreendida.

"Inline Class"

Em situações em que existam classes que têm poucas funcionalidades deveremos removê-las.

Movemos o seu código para outra classe e apagamos a primeira.

Este processo é o inverso do "Extract Class" e deve ser utilizado sempre que constatamos que
uma determinada classe contribui pouco para o Sistema. Estas classes resultam muitas vezes do
próprio processo de refactorização que vai movimentando responsabilidades de uma classe para
outras até a deixar praticamente sem funcionalidade. A classe de destino deverá ser aquela que
mais utilizará os recursos da primeira.

9
"Hide Delegate"

Quando existem situações onde estamos a invocar métodos de duas classes distintas de forma a
obter uma determinada informação devemos utilizar este processo.

Deveremos criar um método no "servidor" ocultando a terceira classe da primeira.

Um dos principais objectivos, talvez mesmo "O Objectivo" da programação orientada a


objectos é o encapsulamento. O encapsulamento permite aos vários objectos saberem menos
sobre outras partes do Sistema. Isto possibilita que quando ocorrem alterações numa
determinada parte do Sistema o seu efeito sobre os restantes objectos seja praticamente nulo ou
mesmo nulo.

Com este processo podemos melhorar substancialmente o nosso Sistema tornando-o resistente
a alterações.

"Remove Middle Man"

Utilizar quando uma classe ("servidor") está a fazer demasiadas delegações para uma terceira.

Fazer com que o Cliente invoque directamente a terceira classe.

10
No processo anterior ("Hide Delegate") era mencionadas as vantagens do encapsulamento, no
entanto existem também desvantagens. No exemplo dado, sempre que um "cliente" desejar um
novo recurso da terceira classe teremos que adicionar um novo método ao "servidor". Depois de
adicionar vários métodos podemos atingir uma situação em que não se revela produtivo ter um
intermediário. Neste caso deveremos ponderar invocar o método directamente. Estes dois
processos ("Remove Middle Man" e "Hide Delegate") devem ser usados de forma equilibrada
ao longo do desenvolvimento do Sistema.

"Introduce Foreign Method"

Quando necessitamos adicionar um método a uma determinada classe mas não a podemos
alterar deveremos utilizar este processo.

Criamos o método na classe "cliente" com uma instância da classe "servidor" como primeiro
argumento.

Esta situação ocorre muitas vezes. Podem existir momentos em que necessitamos de adicionar
um novo método mas não podemos alterar o código dessa classe. Isto acontece, por exemplo,
em situações onde o código pertence a terceiros estando protegido por direitos de autor. De
forma a contornar esta situação devemos utilizar este processo.

Se chegarmos a um ponto em que tivemos que utilizar muitas vezes este processo devemos
ponderar a utilização do processo "Introduce Local Extension" ou então solicitar a quem detém
os direitos do código que introduza os métodos em questão.

"Introduce Local Extension"

Devemos utilizar este processo quando necessitamos de adicionar vários métodos a uma
determinada classe mas não a podemos alterar.

Criamos uma nova classe que contém os métodos extra. Fazemos desta classe uma subclasse da
primeira.

11
Uma extensão local ("Local Extension") é uma classe separada mas que é um subtipo da classe
que é estendida. Isto significa que ela suporta tudo o que a classe original faz e acrescenta novas
funcionalidades. Em situações em que apenas necessitamos de adicionar 2 ou 3 novos métodos
devemos ponderar a utilização do processo "Introduce Foreign Method".

5. - Conclusões

O Desenvolvimento de Software deve seguir uma disciplina rigorosa de programação e um


desenvolvimento de arquitectura de software saudável que impeça o aparecimento dos Anti-
padrões. Contudo são ainda muitos poucos os que trabalham nesse mundo. Necessitamos
portanto de metodologias para identificar e eliminar os Anti-padrões.

O Anti-Padrão de Desenvolvimento "Fluxo de Lava" ("Lava Flow") e o Anti-Padrão de


Arquitectura "Jumble" são boas ferramentas para melhorar os Sistemas desenvolvidos.

Revisões de código (especialmente as informais) e refactorização normalmente conduzem a


bons resultados, ou seja, na maioria das vezes os Anti-padrões são detectados e eliminados dos
nossos Sistemas.

12
REFERÊNCIAS

[1]
Texto adaptado de http://sourcemaking.com/antipatterns/lava-flow
[2]
Texto adaptado de http://sourcemaking.com/antipatterns/jumble
[3]
Texto adaptado de http://sourcemaking.com/refactoring/moving-features-between-objects

Antipatterns [Online]. Última Actualização: 11 de Março de 2002 [Consultado em Dezembro


de 2010]. Disponível na WWW: <http://www.antipatterns.com >

13

Você também pode gostar