17
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. 1

AntiPadrões e Refactorização (Grupo 3)

Embed Size (px)

Citation preview

Page 1: AntiPadrões e Refactorização (Grupo 3)

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

Page 2: AntiPadrões e Refactorização (Grupo 3)

- "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 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.

2

Page 3: AntiPadrões e Refactorização (Grupo 3)

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.

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

3

Page 4: AntiPadrões e Refactorização (Grupo 3)

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:

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"

4

Page 5: AntiPadrões e Refactorização (Grupo 3)

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. 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

5

Page 6: AntiPadrões e Refactorização (Grupo 3)

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.

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]

6

Page 7: AntiPadrões e Refactorização (Grupo 3)

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).

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]

7

Page 8: AntiPadrões e Refactorização (Grupo 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

Page 9: AntiPadrões e Refactorização (Grupo 3)

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.

"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.

9

Page 10: AntiPadrões e Refactorização (Grupo 3)

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.

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.

10

Page 11: AntiPadrões e Refactorização (Grupo 3)

"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.

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".

11

Page 12: AntiPadrões e Refactorização (Grupo 3)

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

Page 13: AntiPadrões e Refactorização (Grupo 3)

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