Universidade Federal do Amazonas – UFAM Instituto de Ciências Exatas – ICE
Departamento de Ciência da Computação – DCC Programa de Pós-Graduação em Informática – PPGI
Aperfeiçoamento do Processo de Detecção de Padrões de Projeto: Variações e Relacionamentos
Dissertação apresentada ao Departamento de Ciência da Computação do Instituto de Ciências Exatas da Universidade Federal do Amazonas como requisito para obtenção do título de Mestre em Informática
Gustavo Costa Dias Manaus – Março de 2007
Universidade Federal do Amazonas – UFAM
Livros Grátis
http://www.livrosgratis.com.br
Milhares de livros grátis para download.
Instituto de Ciências Exatas – ICE Departamento de Ciência da Computação – DCC
Programa de Pós-Graduação em Informática – PPGI
Aperfeiçoamento do Processo de Detecção de Padrões de Projeto: Variações e Relacionamentos
Gustavo Costa Dias Orientador : Dr. Ilias Biris
DCC – UFAM
Manaus, Março de 2007
Agradecimentos À minha família, em especial à minha mãe, Helena Maria Costa Dias, que sempre me
apoiou e se fez presente mesmo estando muito longe.
Ao meu orientador, Ilias Biris, que apesar de todas as restrições de tempo, me deu toda
atenção necessária e conseguiu me orientar muito bem.
Á todos os professores do PPGI, por todo conhecimento compartilhado e pela sua
competência.
Aos amigos Ricardo Paiva Garcia, Eduardo Abinader e Fuad Abinader, pelo exemplo de
vida, dedicação e companheirismo.
À Fundação Desembargador Paulo Feitoza (FPF), por proporcionar condições
favoráveis à realização das atividades e pela confiança depositada.
À Elienai Nogueira, pelo apoio administrativo.
Á Priscila Pereira, por todo carinho e paz transmitidos. Sua participação foi fundamental
na reta final do trabalho.
A todos os amigos de Manaus, que contribuíram direta ou indiretamente para realização
deste trabalho, meus sinceros agradecimentos.
Sumário
1. Introdução ............................................................................................................... 1 1.1. Definição do Problema....................................................................................... 1 1.2. Motivação........................................................................................................... 2 1.3. Objetivo .............................................................................................................. 2 1.4. Organização da Dissertação ............................................................................... 3 2. Conceitos Básicos ................................................................................................... 4 2.1. Padrões de Projeto .............................................................................................. 4 2.2. O Processo de Detecção de Padrões................................................................... 6 2.2.1. A Formalização dos Padrões .............................................................................. 7 2.2.2. Definição dos Domínios ..................................................................................... 9 2.2.3. A Identificação dos Padrões ............................................................................... 9 2.3. Problema de Satisfação de Restrições (PSR) ................................................... 10 2.3.1. Técnicas para Resolução de PSR’s .................................................................. 11 2.3.1.1. Técnicas de Busca Baseadas em Retrocesso ............................................... 11 2.3.1.2. Propagação de Restrições ............................................................................ 13 2.3.1.3. Manutenção da Consistência de Arco Dentro do Backtracking Dinâmico . 13 2.3.1.4. Técnicas Flexíveis ....................................................................................... 14 2.4. Os Padrões de Projeto e os Problemas de Satisfação de Restrições (PSR’s) ... 15 3 Proposta de Trabalho ............................................................................................ 17 3.1 Variações dos padrões de projeto.......................................................................... 17 3.2 Relacionamentos entre os diversos padrões de projeto......................................... 20 3.3 Metodologia .......................................................................................................... 25 4 Experimentos ........................................................................................................ 27 4.1 Relacionamentos ................................................................................................... 27 4.1.1 Identificação dos Pontos de Extensão .............................................................. 27 4.1.2 Os Padrões Facade e Singleton ........................................................................ 28 4.1.2.1 A Implementação do Cenário de Testes ...................................................... 28 4.1.2.2 A Implementação da Solução ...................................................................... 29 4.1.2.3 Execução dos Testes e Análise dos Resultados........................................... 31 4.1.3 Generalização da Solução ................................................................................ 32 4.1.4 Os Padrões Command e Composite.................................................................. 34 4.1.4.1 A Implementação do Cenário de Testes ...................................................... 34 4.1.4.2 A Implementação da Solução ...................................................................... 34 4.1.4.3 Execução dos Testes e Análise dos Resultados........................................... 35 4.1.5 Aplicabilidade da Solução para Sistemas Reais............................................... 36 4.2 Variações............................................................................................................... 38 4.2.1 A Implementação do Cenário de Testes........................................................... 38 4.2.2 Execução dos Testes e Análise dos Resultados................................................ 39 5 Conclusão e Trabalhos Futuros............................................................................. 42 5.1 Trabalhos Futuros ................................................................................................. 43 Referências ..................................................................................................................... 45
Lista de Figuras Figura 1 - Estrutura do padrão Facade ............................................................................. 5 Figura 2 - Visão geral do processo de detecção dos padrões ........................................... 7 Figura 3 - Grafo de restrições de um PSR...................................................................... 11 Figura 4 - Thrasing causado pelo Backtracking ............................................................. 12 Figura 5 - Estrutura do padrão class adapter. ................................................................ 18 Figura 6 - Estrutura do padrão object adapter................................................................ 18 Figura 7 - Estrutura do padrão Observer. ....................................................................... 19 Figura 8 - Estrutura do padrão Command ...................................................................... 21 Figura 9 - Estrutura adaptada do padrão Command. ...................................................... 22 Figura 10 - Estrutura do padrão Composite ................................................................... 22 Figura 11 - Possíveis relacionamentos entre os padrões ................................................ 24 Figura 12 - Diagrama de classes - Facade e Singleton................................................... 29 Figura 13 - Definição do método isSingleton. ................................................................ 30 Figura 14 - Gráfico comparativo das estratégias de detecção (Facade e Singleton)...... 31 Figura 15 - Diagrama de classes - Command e Composite ............................................ 34 Figura 16 - Gráfico da relação entre a economia e o número de classes do sistema...... 37 Figura 17 - Cenário original (1) e da variação (2) do padrão Bridge. ............................ 39
Lista de Tabelas Tabela 1 - Classificação dos Padrões de Projeto .............................................................. 6 Tabela 2 - Definição do padrão Facade ......................................................................... 15 Tabela 3 - Resultados dos testes de detecção (Facade e Singleton) ............................... 31 Tabela 4 - Resultados dos testes de detecção (Command e Composite)........................ 35 Tabela 5 - Resultados dos testes de detecção para bases maiores .................................. 36 Tabela 6 - Comparação entre a abordagem clássica e as novas abordagens. ................. 41
Lista de Siglas OWL Web Ontology Language
PSR Problema de Satisfação de Restrições
POR Programação Orientada a Restrições
MAC Maintaining Arc-Consistency
DBT Dynamic Backtracking
1
1. Introdução
A fase do ciclo de vida de um sistema que demanda a maior parte dos recursos é a de
manutenção. Cerca de 75% do custo total é gasto nesta fase [5]. Essa realidade se deve
ao fato de que os sistemas, depois de desenvolvidos, precisam ser constantemente
atualizados. O surgimento de novas leis, novas oportunidades de negócio ou mesmo a
identificação de defeitos que precisem ser corrigidos são alguns dos motivos que
justificam essas atualizações.
Apesar desse contexto, a maioria das pesquisas acadêmicas busca melhorias nos
processos envolvidos no desenvolvimento, tais como: metodologias e ferramentas.
Algumas dessas metodologias, como é caso das metodologias ágeis [13], até prejudicam
a manutenção do software evitando documentações que seriam essenciais para um
entendimento futuro do que está sendo construído. Enfim, muito pouco é feito para
auxiliar a fase de manutenção do software.
A fase de manutenção é constituída basicamente das seguintes atividades:
1. Análise do código fonte da aplicação, sua estrutura e comportamento,
2. Identificação dos pontos que deverão ser modificados, seja para implementação de
novos requisitos ou para correção de defeitos e por último,
3. Modificação do código sem afetar o que já estava funcionando.
Os padrões de projeto [4] vem sendo muito utilizados para facilitar o projeto,
entendimento e reengenharia de software. O entendimento, neste caso, diz respeito à
habilidade de identificar partes do sistema que implementam um determinado padrão e a
manutenção envolve a identificação de possíveis melhorias no projeto dessas partes.
1.1. Definição do Problema
Apesar das vantagens da utilização dos padrões, o processo de identificação de
padrões de projeto não é simples e não existem ferramentas que o automatizem de
forma satisfatória. Existem algumas iniciativas acadêmicas que se propõem a resolver o
problema, tais como: Ptidej [6], Hedgehog [2] e WebOfPatterns [3]. Todas essas
implementações apresentam limitações. A Hedgehog [2] exige que as entidades do
código sejam marcadas para que a busca possa identificá-las. A WebOfPatterns [3], que
se destaca pela sua estratégia de formalização bastante flexível, falha na identificação de
2
padrões parcialmente implementados. Além das limitações específicas, o principal
problema apresentado por todas as soluções é o tempo de busca que é gasto para se
conseguir resultados de qualidade.
1.2. Motivação
A eficiência é essencial porque os principais usuários desse tipo de ferramenta
são projetistas e desenvolvedores de software que desejam aumentar seu entendimento
sobre sistemas grandes e complexos para realizar algum tipo de manutenção ou
melhoria. Quanto maior o número de entidades presentes no código fonte da aplicação
analisada, mais difícil é a sua análise. Isso se deve ao fato das inúmeras combinações
entre as entidades do sistema precisarem ser analisadas.
1.3. Objetivo
Independentemente de ferramenta, existe um processo comum que é seguido. O
objetivo deste trabalho é melhorar esse processo de forma a viabilizar o seu uso em
ambientes reais. Num ambiente real o número de entidades no código do sistema é
relativamente grande e os padrões de projeto não são implementados exatamente como
estão descritos na literatura. Duas propriedades dos padrões de projeto são consideradas:
as possíveis variações de implementação e as relações entre os diversos padrões. Essas
propriedades ainda não tinham sido exploradas nas ferramentas pesquisadas: Ptidej [6],
Hedgehog [2] e WebOfPatterns [3].
A ferramenta Ptidej [6] foi escolhida como base para o desenvolvimento deste
trabalho. A estratégia de busca da ferramenta foi refinada de forma que as novas
propriedades fossem utilizadas. Para que isto fosse possível, foram feitas várias
melhorias na arquitetura do sistema. A principal contribuição foi a remoção das
definições dos padrões do código do sistema. Foi criada uma base de dados com essas
definições possibilitando assim a geração dinâmica dos problemas de detecção que
servem de entrada para o solucionador de restrições. Além das definições básicas
existentes, as novas propriedades também foram incluídas na base.
3
Alguns cenários foram implementados para servir de base para os experimentos.
Para a propriedade dos relacionamentos, os cenários foram analisados utilizando a
implementação original da ferramenta Ptidej [6] e depois utilizando a nova estratégia de
busca. Os testes mostraram resultados bastante positivos. No geral, o número de
soluções falso-positivas diminuiu e houve um ganho de desempenho de até 70%. O
comportamento da solução também foi testado em bases de tamanhos reais, com um
número maior de classes. Pode-se perceber que a economia no tempo de processamento
aumenta significativamente com o aumento do número de classes do sistema.
Os testes envolvendo as variações constataram uma melhoria na qualidade das
soluções encontradas. Duas abordagens foram experimentadas: primeiro o relaxamento
das restrições variantes e depois a busca pelas definições clássica e variante do mesmo
padrão. A última estratégia obteve um resultado superior pois conseguiu detectar as
soluções exatas para os padrões.
1.4. Organização da Dissertação
O restante da dissertação está organizado da seguinte forma: O capítulo 2
introduz os conceitos básicos necessários ao entendimento do contexto do trabalho.
Neste capítulo são apresentados conceitos sobre padrões de projeto, o processo atual de
detecção dos padrões utilizado pelas principais ferramentas pesquisadas, os problemas
de satisfação de restrição e sua relação com os padrões de projeto. O capítulo 3 detalha
as melhorias propostas no processo atual de identificação de padrões. Neste capítulo,
são apresentadas as novas propriedades que foram exploradas. A metodologia utilizada
para o desenvolvimento também é apresentada. O capítulo 4 descreve os experimentos
realizados, os resultados obtidos e as análises sobre estes resultados. Os cenários que
foram implementados são detalhados neste capítulo. Por último, o capítulo 5 traz uma
conclusão geral sobre todo o trabalho e propostas de possíveis trabalhos futuros.
4
2. Conceitos Básicos
2.1. Padrões de Projeto
O precursor da idéia de padrão de projeto foi o engenheiro civil Christopher Alexander
que escreveu sobre sua experiência em resolver problemas de projeto em suas
construções. Alexander percebeu que certas idéias de projeto sempre levam aos mesmos
efeitos. Ele documentou e publicou sua experiência de forma que os outros pudessem se
beneficiar dela. Alguns anos depois, os projetistas de software começaram a incorporar
esses princípios. Esse trabalho culminou na publicação, em 1995, do livro: Design
Patterns: Elements of Reusable Object-Oriented Software [4]. Até hoje, o livro continua
sendo uma das principais referências na área.
O uso dos padrões de projeto facilita a reutilização de designs e arquiteturas que
já foram utilizadas com sucesso em outros sistemas, ajuda na escolha de alternativas que
tornam o sistema mais reutilizável e melhora a documentação e manutenção dos
sistemas existentes fornecendo uma especificação explícita das interações entre as
classes, os objetos e seus objetivos. Este trabalho explora principalmente essa última
característica dos padrões.
Segundo [4], um padrão é composto basicamente dos seguintes elementos
essenciais:
1. Nome. Tenta dar uma idéia do problema de design, suas soluções e conseqüências
em uma ou duas palavras.
2. Problema. Descreve quando o padrão deve ser aplicado. Explica o problema e seu
contexto.
3. Solução. Descreve os elementos que compõem o design, seus relacionamentos,
responsabilidades e colaborações. A solução não descreve um design concreto
particular ou uma implementação porque o padrão é como um modelo que pode ser
aplicado em muitas situações diferentes. Ao invés disso, e feita uma descrição
abstrata do problema de design e uma disposição geral dos elementos.
4. Conseqüências. Mostra os resultados e a relação custo-benefício da aplicação do
padrão.
A Solução é elemento de maior interesse neste trabalho. Esta descrição pode ser
utilizada por ferramentas que detectam automaticamente os padrões a partir do código
fonte do sistema. A seção 2.2 mostra o processo que é seguido por essas ferramentas.
5
O padrão de projeto Facade [4] é utilizado para resolver o problema de
complexidade em sistemas muito grandes. Esse tipo de sistema apresenta um grande
número de classes e isso faz com que as responsabilidades fiquem misturadas. Isso
dificulta a compreensão. A idéia do padrão é organizar o sistema em vários subsistemas
menores reduzindo a complexidade global. Este isolamento é possível através da
definição de uma interface única e simplificada para todos os serviços de cada
subsistema. A Figura 1 extraída de [4] ilustra a estrutura da solução do padrão citado.
Figura 1 - Estrutura do padrão Facade
Os seguintes componentes fazem parte desta solução:
1. Facade. Conhece as classes do subsistema e delega as requisições de serviço para as
mesmas.
2. Classes do subsistema. Implementam a funcionalidade do subsistema e
desconhecem o objeto Facade.
3. Classes clientes. Solicitam serviços para o objeto Facade e desconhecem as classes
de subsistema.
Os padrões de projeto são classificados de acordo com seu propósito. Existem
três classificações principais para os padrões:
1. Padrões de criação. Estão relacionados com o processo de criação dos objetos.
2. Padrões Estruturais. Responsáveis pela organização estrutural dos elementos. Por
exemplo: a composição de classes ou objetos.
6
3. Padrões Comportamentais. Caracterizam as interações ente os elementos e as
responsabilidades de cada um.
Outro critério utilizado para classificar os padrões é o seu escopo. Existem dois
tipos de escopo: o de classe e o de objeto. No escopo de classe os relacionamentos entre
classes e subclasses são definidos através de herança e em tempo de compilação. O
escopo de objeto diz respeito aos relacionamentos entre os objetos e é definido em
tempo de execução. A Tabela 1 classifica os padrões de acordo com seu propósito e
escopo.
Tabela 1 - Classificação dos Padrões de Projeto
Dentre todos os tipos de padrões citados acima, os padrões do tipo
comportamental são os mais difíceis de serem identificados pois uma simples análise
estática não é suficiente para detectá-los.
2.2. O Processo de Detecção de Padrões
Existem algumas iniciativas de ferramentas que se propõem a resolver o problema
de detecção de padrões, tais como Ptidej [6], Hedgehog [1] e WebOfPatterns [3].
Podem-se observar algumas atividades que são comuns a todas as implementações. A
Figura 2 ilustra esse processo e o fluxo básico que existe essas atividades. A atividade
de Identificação depende dos resultados das atividades de Formalização e Definição dos
Domínios.
7
1. Formalização
dos Padrões
2. Definição dos
Domínios
3. Identificação dos
Padrões
Figura 2 - Visão geral do processo de detecção dos padrões
2.2.1. A Formalização dos Padrões
Primeiramente é preciso representar formalmente os padrões. Em geral, os
padrões vêm descritos em livros com alguns exemplos de implementação. Não é
possível processar os padrões a partir desse tipo de representação textual. Os padrões
são representados formalmente através de restrições. Existem dois tipos de restrições
que precisam ser especificadas:
1. Estruturais. Representam as relações entre os elementos que compõem o padrão, por
exemplo: relações de herança ou associação entre duas classes.
2. Semânticas. Restrições sobre a maneira que os métodos são implementados, por
exemplo: um método pode instanciar outras classes ou afetar o relacionamento entre
duas classes durante o tempo de execução.
Alguns tipos de restrições estruturais apresentadas pelo padrão facade mostrado
na Figura 1 são:
1. Associação. Todo componente cliente deve estar associado ao componente facade.
8
2. Conhecimento. Nenhum componente de subsistema deve conhecer outro
componente cliente.
3. Igualdade. Um mesmo elemento não pode representar o componente facade e um
componente de subsistema simultaneamente. Esses dois papéis são exclusivos.
Além das restrições estruturais, a necessidade de cada método do componente
facade delegar a solicitação do cliente para um componente de subsistema constitui uma
restrição semântica. A relação estrutural de associação entre os dois componentes não
garante que um esteja executando algum método do outro.
Segundo [1], um dos principais problemas enfrentados na tentativa de formalizar
os padrões é que a implementação e a descrição de um padrão são dependentes da
linguagem de programação. Para resolver este problema existem duas opções: (1) A
criação de uma especificação abstrata para os padrões ou (2) A criação de uma
especificação concreta para uma linguagem específica. Levando em consideração que a
verificação a partir de uma especificação abstrata seria muito complexa, decidiu-se por
uma especificação concreta tendo Java como linguagem alvo.
As ferramentas pesquisadas implementam diferentes estratégias de formalização
dos padrões. A ferramenta Hedgehog [1] especifica os padrões diretamente em uma
linguagem baseada em lógica de primeira ordem tipada chamada SPINE. O formato da
linguagem é parecido com Prolog, porém cada termo tem um tipo associado e pode ser
avaliado.
Um Problema de Satisfação de Restrições (PSR) é usado para modelar os
padrões na ferramenta Ptidej [6]. As classes que compõem o padrão são representadas
por variáveis e as relações entre essas classes representam as restrições. Maiores
detalhes sobre essa modelagem podem ser encontrados na seção 2.4.
A ferramenta WebOfPatterns [3] utiliza web ontology language (OWL). A OWL
é uma linguagem para publicação e compartilhamento de dados usando ontologias na
web. Uma ontologia é uma especificação de um conceito de um domínio do
conhecimento. Dentre as alternativas de formalização pesquisadas, a OWL é que
apresenta maior número de vantagens. Além da fácil representação do conceito, a
possibilidade de compartilhamento com a comunidade é muito interessante. A criação
de um repositório único de padrões seria inviável sem contribuições de especialistas.
9
2.2.2. Definição dos Domínios
O código fonte da aplicação representa o domínio a ser considerado. Existem
diversas formas de manipulação das informações desse domínio. Algumas ferramentas,
tais como Hedgehog [2] e WebOfPatterns [3], lêem diretamente o código durante a
busca pelos padrões, outras, como a ferramenta Ptidej [6], extraem as informações e as
carregam em um modelo.
Para cada classe do sistema as seguintes informações são extraídas:
1. Nome. O nome da classe.
2. Superclasses. A lista de todas as superclasses.
3. Componentes. A lista com os componentes agregados pela classe juntamente com
tipo das superclasses desses componentes.
4. Relacionamentos. A lista de todas as classes que se relacionam com a classe.
O modelo é utilizado posteriormente pelo solucionador durante o processo de busca.
A utilização do modelo é um diferencial da ferramenta, pois a torna mais extensível.
Novas linguagens podem ser suportadas simplesmente adicionando módulos específicos
que extraíam as informações e as carreguem no modelo. Essa modificação não afeta os
outros componentes do sistema.
2.2.3. A Identificação dos Padrões
Uma vez que os padrões estão formalizados e o domínio definido, pode-se
submeter essa especificação ao solucionador de restrições. O solucionador, por sua vez,
verifica se uma determinada classe ou grupo de classes atende as restrições de um
determinado padrão. Essa atividade é chamada de Identificação de Padrões no fluxo
básico mostrado na Figura 2.
As restrições estruturais são verificadas diretamente através de uma análise
estática do código fonte da aplicação. Entretanto, para as restrições semânticas são
necessárias análises em tempo de execução pois elas estão relacionadas a aspectos
dinâmicos do programa. O trabalho atual considera apenas restrições estruturais.
Um sistema de prova que tenta verificar se um determinado padrão está sendo
corretamente implementado por uma classe ou conjunto de classes é implementado na
10
ferramenta Hedgehog [2]. A ferramenta necessita de uma marcação no código que
indique qual classe deve ser verificada. Essa restrição inviabiliza a utilização da solução
no contexto desse trabalho. A seleção de todos os elementos suspeitos em um sistema
com muitas classes seria extremamente complexa.
A ferramenta WebOfPatterns [3] traduz as definições OWL em restrições. Um
padrão é definido como um conjunto de regras lógicas. As regras juntamente com os
fatos que representam o código fonte são utilizadas para identificação dos padrões.
Segundo [7], a técnica é limitada. Ela apenas detecta classes cujos relacionamentos são
descritos pelas regras. Apenas micro-arquiteturas idênticas podem ser detectadas. As
regras precisam ser estendidas para introduzir todas as soluções parciais possíveis dos
padrões e isso se torna difícil de gerenciar. Jens Dietrich [3] admiti a limitação e sugere
uma generalização da sua solução na qual certas restrições pudessem ser
desconsideradas.
A maioria dos solucionadores é projetada para identificar soluções completas:
soluções que atendem todas as restrições. No contexto deste trabalho, as soluções
interessantes são justamente as que não atendem todas as restrições pois elas mostram o
que não está corretamente implementado, ou seja, o que pode ser melhorado. A
ferramenta Ptidej [6] consegue identificar essas soluções parciais. Para isso ela usa
internamente um sistema chamado PaLM [8] composto por uma linguagem de
programação orientada a restrições baseada em explicações [7] e um solucionador de
restrições. A seção 2.4 detalha melhor esse conceito.
2.3. Problema de Satisfação de Restrições (PSR)
Um PSR é definido por uma tupla (V, C, D), onde V é um conjunto de variáveis,
C é um conjunto de restrições relacionadas às variáveis e D é o domínio das variáveis
[14]. Um PSR pode ser visualizado como um grafo de restrições onde os nós
representam as variáveis e os arcos as restrições entres essas variáveis. A Figura 3
adaptada de [11] ilustra um PSR através de um grafo de restrições. Cada nó representa
uma variável com o seu respectivo domínio. Um arco representa uma restrição qualquer
entre duas variáveis. Uma possível solução para este problema seria composta das
seguintes atribuições: x1 = 5, x2 = 4, x3 = 1 e x4 = 4. Todas as variáveis têm um valor e
todas as restrições estão sendo respeitadas. As próximas seções descrevem as principais
técnicas de resolução desse tipo de problema.
11
Figura 3 - Grafo de restrições de um PSR
2.3.1. Técnicas para Resolução de PSR’s
2.3.1.1. Técnicas de Busca Baseadas em Retrocesso
As técnicas de busca baseadas em retrocesso tratam um PSR como uma árvore.
Cada ramo da árvore representa uma atribuição parcial e cada nível está relacionado a
uma variável de acordo com a ordem em que as variáveis são instanciadas. O algoritmo
mais simples para resolução de um PSR é chamado de Backtracking. É realizada uma
busca em profundidade na árvore que escolhe valores para uma variável a cada vez.
Quando não existem mais valores válidos a serem atribuídos, o algoritmo retorna até a
variável mais recente e experimenta outro valor. No pior caso a complexidade é
exponencial ao número de variáveis, ou seja, O(xn). Outra desvantagem dessa
abordagem é o fato da busca falhar repetidamente pela mesma razão. Essa característica
é chamada de thrashing. A Figura 4 extraída de [11] ilustra o thrashing considerando o
PSR apresentado na Figura 3. Nós brancos e pretos representam respectivamente,
atribuições válidas e inválidas. As duas regiões em destaque na figura mostram a
repetição da mesma falha por causa da restrição (x2 = x4).
12
Figura 4 - Thrasing causado pelo Backtracking
Uma abordagem mais inteligente do que a do Backtracking é percorrer todo o
caminho de volta até um dos conjuntos de variáveis que causaram a falha. Esse conjunto
é chamado de conjunto de conflito. Neste caso, somente as variáveis que estiverem
conectadas com a variável atual através de restrições são consideradas. O algoritmo
retorna ao elemento mais recente do conjunto de conflito. Esse tipo de busca é chamado
de Backjumping. Apesar da idéia do Backjumping ser boa, existem situações onde a
ramificação pesquisada já está condenada bem antes do domínio da variável se tornar
vazio. Para tratar esse caso, o algoritmo foi aprimorado para que o conjunto de conflito
pudesse ser analisado de uma forma mais inteligente. Ao invés de simplesmente
regredir para o elemento mais recente do conjunto é feito um cálculo para encontrar o
ponto correto na árvore de busca responsável pelo conflito. Esse algoritmo chama-se
Conflict-Directed Backjumping.
A estratégia de identificação de erros usada nas abordagens apresentadas até
aqui não evita que os mesmos erros sejam cometidos em outros ramos da árvore. Após
um retrocesso, toda as informações relacionadas com a inconsistência encontrada são
perdidos. Este aspecto é tratado por uma abordagem conhecida com Backtracking
dinâmico ou DBT (Dynamic Backtracking). Uma série de explicações para as
eliminações é mantida. Essas explicações registram a razão pela qual uma determinada
atribuição é desconsiderada. Apenas as explicações relacionadas à atribuição atual são
mantidas. Uma vez que a atribuição muda, todas as explicações envolvidas são
descartadas. Isso reduz a complexidade de espaço que seria necessária para armazenar
todas a explicações geradas durante a busca. No pior caso, o espaço necessário para
manter as explicações é de O (n2d), onde n é o número de variáveis e d o tamanho
máximo dos domínios.
13
2.3.1.2. Propagação de Restrições
Além dos métodos de busca tradicionais, existem também outros métodos para
resolução de PSR que se baseiam na propagação de restrições. Neste caso, as
implicações de uma restrição sobre uma variável são propagadas para outras variáveis.
Um método rápido de propagação de restrições é conhecido como consistência de arco.
O termo arco se refere a um arco orientado no grafo de restrições que representa o PSR.
O algoritmo que implementa esse método mantém uma fila que controla os arcos cuja
inconsistência precisa ser verificada. Sempre que um valor é excluído do domínio de
uma variável para remover uma inconsistência de arco, pode surgir uma nova
inconsistência de arco em arcos que apontam para essa variável. A verificação de
consistência de arco pode ser aplicada como uma etapa de pré-processamento antes do
início do processo de busca ou como uma etapa de propagação depois de cada
atribuição durante a busca. Esse último algoritmo é chamado de Manutenção de
Consistência de Arco ou MAC (Maintaining Arc-Consistency). A complexidade da
verificação de consistência de arco para um PSR binário é de O(n2d3), sendo que n é
número de arcos e d é o número de vezes que cada arco pode ser inserido no programa.
2.3.1.3. Manutenção da Consistência de Arco Dentro do
Backtracking Dinâmico
Como os problemas abordados neste trabalho exigem eficiência na busca de
solução, tanto as buscas baseadas em retrocesso quanto a técnica de propagação de
restrições possuem características interessantes que podem ser exploradas. Para tratar
esse aspecto, existe um algoritmo híbrido chamado MAC-DBT [9]. Este foi elaborado a
partir da integração da técnica de manutenção de consistência de arco (MAC) com o
backtracking dinâmico (DBT). Além de manter o registro das explicações de
eliminação, ele consegue propagar as restrições. Maiores detalhes sobre a integração
entre esses algoritmos estão fora do escopo de trabalho.
O MAC-DBT supera o Backtracking dinâmico pois a propagação de restrições
melhora a eficiência. Para PSR’s aleatoriamente gerados, quando maior a propagação
menor o tempo necessário para obtenção da solução. Em comparação com o algoritmo
MAC, a nova abordagem não apresenta vantagens considerando apenas PSR’s gerados
aleatoriamente. Isso se justifica pelo overhead necessário para gerenciar as explicações
14
de eliminação que não são úteis para este tipo de problema. Por outro lado, [9] realizou
experimentos considerando PSR’s compostos de subproblemas menores. Este tipo de
estrutura não pode ser identificado usando somente a propagação de restrições. MAC-
DBT se mostrou estável conforme o número de variáveis aumenta. O mesmo não
aconteceu com o MAC que se tornou proibitivo. Apesar da construção artificial dos
PSR’s, este tipo de problema é mais comumente encontrado em ambientes reais do que
os problemas gerados de forma aleatória.
2.3.1.4. Técnicas Flexíveis
Outro requisito básico necessário para resolução dos problemas abordados neste
trabalho é a possibilidade de encontrar soluções parciais. Nem sempre o padrão de
projeto está implementado exatamente como foi descrito na literatura. Todas as técnicas
discutidas até agora realizam buscas completas, ou seja, todas as restrições devem ser
atendidas para que haja uma solução. Pode haver restrições demais para que se possa
encontrar uma solução. Neste caso, faz-se necessário que algumas restrições sejam
removidas ou que tenham sua importância diminuída para que se possa encontrar
alguma solução menos restritiva para o problema. Este processo chama-se relaxamento.
Após o relaxamento, é necessário analisar da utilidade da solução encontrada. Para isto,
é preciso ter informação sobre a importância de cada restrição individual. Uma métrica
de qualidade que pode ser usada é o número de restrições satisfeitas em uma
determinada atribuição parcial. A flexibilidade permite que se expresse a preferência e a
prioridade para as restrições de um problema.
O algoritmo mais comum para resolução de PSR flexíveis chama-se branch and
bound. Ele considera a primeira atribuição completa encontrada como a melhor solução
até o momento. Novas atribuições parciais são descartadas quando se percebe que elas
não podem superar a melhor solução atual. Se alguma outra atribuição completa superar
a melhor solução atual, então ela se torna a nova melhor solução.
15
2.4. Os Padrões de Projeto e os Problemas de Satisfação de
Restrições (PSR’s)
Um padrão de projeto pode ser modelado como um PSR. Para isto, uma variável
é associada a cada componente do padrão. O domínio das variáveis é o conjunto de
todas as classes existentes no sistema. Os relacionamentos entre as classes são
representados como restrições entre as variáveis. A Tabela 2 representa as relações entre
as variáveis e restrições do padrão facade ilustrado na Figura 1. As variáveis estão
dispostas nas primeiras linha e coluna da matriz. As restrições representam as relações
entre as variáveis. Os seguintes tipos de restrições são utilizados:
1. Associação (A). Deve existir uma associação entre os dois elementos.
2. Igualdade (I). O mesmo elemento não pode assumir dois papéis ao mesmo tempo.
3. Conhecimento (C). Um elemento não pode ter conhecimento do outro.
Variável Cliente Facade Classe de Sistema
Cliente A, I C, I
Facade C A, I
Classe de Subsistema C
Tabela 2 - Definição do padrão Facade
Os PSR’s são implementados utilizando a Programação Orientada a Restrições
(POR) [1] . A POR é um novo paradigma de programação onde as relações entre as
variáveis são vistas como restrições. Ao contrário das outras linguagens mais comuns
que definem passos ou uma seqüência de passos a serem executados, a POR define
apenas as propriedades a serem encontradas. A maioria das bibliotecas para POR são
inúteis no contexto deste trabalho pelos seguintes motivos:
1. Quando o problema que se deseja resolver não apresenta nenhuma solução
completa, nenhuma solução parcial é considerada.
2. Nenhuma análise mais elaborada sobre o resultado pode ser feita pois nenhuma
informação relacionada à busca é mantida.
Para resolver estes problemas foi utilizada uma extensão da POR chamada POR
baseada em explicações [7]. Essa abordagem usa a técnica de explicações para as
eliminações e também possui flexibilidade para tratar problemas que não apresentam
solução completa. A implementação utilizada neste trabalho chama-se PaLM [8]. Ela se
16
baseia no algoritmo MAC-DBT [9]. O estado de um sistema de restrições é
representado por uma restrição original qualquer e pelo conjunto de decisões tomadas
até o momento. Considerando que este estado seja contraditório, uma explicação seria o
subconjunto de restrições originais que deixa o sistema neste estado, ou seja, sem
nenhuma solução. As explicações ajudam no entendimento da situação atual facilitando
a análise dos seguintes tipos de questões:
1. Por que o problema não tem solução? Esta análise pode ser feita apenas sobre as
restrições relevantes.
2. Por que a variável x não pode receber o valor a? A explicação relacionada a esta
remoção pode ser analisada isoladamente.
3. O que aconteceria se a restrição c fosse adicionada novamente ao sistema? O
rastreamento de todas as explicações relacionadas à restrição ajuda a entender os
efeitos da ativação dessa restrição.
Além do suporte à análise, a partir do mesmo conjunto de restrições que
justificam a ausência de uma solução, é possível remover as restrições
incrementalmente até se chegar a uma solução parcial do problema.
A partir do contexto apresentado e das abordagens escolhidas, o próximo
capítulo detalha a proposta desde trabalho. A idéia é melhorar a solução atual
encontrada reutilizando o máximo de infra-estrutura possível.
17
3 Proposta de Trabalho
O objetivo deste trabalho é o aperfeiçoamento do processo atual de detecção de padrões
através da utilização de características ainda não exploradas pelas implementações
atuais. As seguintes características são exploradas:
1. As variações implementacionais dos padrões e
2. Os relacionamentos entre os diversos padrões.
Este tratamento adicional é de fundamental importância pois o processo atual
ainda é lento e impreciso. A idéia é tornar a busca mais inteligente. Como as
características escolhidas acontecem com muita freqüência em situações reais, espera-se
resultados bastante relevantes. Com isso pretende-se defender a utilização em larga
escala desse tipo de solução possibilitando análises mais realistas e eficientes.
Devido à flexibilidade na identificação de soluções, a ferramenta Ptidej [6] foi
selecionada como base para o desenvolvimento desde trabalho.
Este capítulo esta organizado da seguinte forma: as seções 3.1 e 3.2 detalham
cada uma das propriedades que serão exploradas, respectivamente, variações e
relacionamentos. Por último, a seção 3.3 descreve a metodologia utilizada para o
desenvolvimento do trabalho.
3.1 Variações dos padrões de projeto
Muitas vezes, durante a fase de implementação de um sistema, não é possível
implementar o padrão exatamente com ele está descrito nos livros. Necessidades
específicas fazem com que os padrões clássicos sejam adaptados para situações
específicas, surgindo assim diversas variações. As variações podem ser estruturais ou
semânticas [1].
O padrão Adapter [4] é usado para converter a interface de uma classe para uma
interface que o cliente espera. Desta forma, classes com interfaces incompatíveis podem
trabalhar juntas. Existem duas variações deste padrão. A primeira usa herança múltipla
para adaptar uma classe e é chamada de class adapter. A segunda usa a composição de
objetos e é chamada de object adapater. As estruturas das duas variações são mostradas
na Figura 5 e na Figura 6, ambas extraídas de [4].
18
Figura 5 - Estrutura do padrão class adapter.
Figura 6 - Estrutura do padrão object adapter.
Os seguintes componentes participam deste padrão:
1. Target. Define a interface específica do domínio que o componente Client usa.
2. Client. Interage com os objetos através da interface definida pelo componente
Target.
3. Adaptee. Define a interface existente que necessita de adaptação.
4. Adapter. Adapta a interface do componente Adaptee para a interface do componente
Target.
As seguintes colaborações ocorrem entre os objetos que representam esses
componentes: primeiro o objeto Client usa alguma operação na instância de Adapter. O
objeto Adapter chama as operações em Adaptee que executa as operações para realizar
a solicitação.
Um outro exemplo de variação estrutural é a do padrão Singleton [4]. A
implementação deste padrão em Java pode ter as seguintes variações: o LazySingleton,
19
que instancia o objeto singleton mais tarde apenas quando é solicitado, o
FinalFielSingleton, que instancia um campo final no momento da construção do objeto
e o StaticSingleton, que implementa todos os métodos estáticos. Cada uma dessas
variações implica em mudanças estruturais na implementação da classe.
Além das variações estruturais, existem também as variações semânticas. Estas,
por sua vez, não alteram a estrutura dos componentes do padrão, mas sim o sentido que
os métodos possuem. O padrão Observer [4] é um exemplo deste tipo de padrão. Este
padrão define uma dependência entre um objeto e outros de forma que quando o estado
deste objeto muda, todos os seus dependentes são notificados e atualizados. Isso é muito
útil quando não se sabe quantos objetos precisam ser atualizados. O acoplamento entre
os objetos também diminui. O objeto responsável pela notificação não precisa conhecer
os objetos que serão notificados. A estrutura do padrão Observer é mostrada na Figura 7
extraída de [4].
Figura 7 - Estrutura do padrão Observer.
Os seguintes componentes participam deste padrão:
1. Subject. Conhece os componentes do tipo Observer. Permite que objetos desde tipo
sejam cadastrados ou descadastrados para o recebimento de notificações.
2. Observer. Defini uma interface de atualização para os objetos que devem ser
notificados de mudanças no componente Subject.
3. ConcreteSubject. Armazena o estado que interessa a todos os componentes
Observers. Notifica quando alguma mudança de estado ocorre.
4. ConcreteObserver. Mantém uma referência para o componente ConcreteSubject.
Armazena o estado que deve estar consistente com o estado do objeto Subject.
20
Existem duas variações possíveis para este padrão: a Push e a Pull. Na
abordagem Push, quando o objeto do tipo Subject é atualizado, ele passa todas as
informações relevantes para os objetos do tipo Observer. Já na abordagem Pull, o objeto
Subject notifica o Observer, que então extrai as informações necessárias do objeto
Subject. A diferença entre uma abordagem e outra é apenas a implementação do método
de atualização. A estrutura dos componentes é praticamente a mesma, exceto pela
referência entre o componente ConcreteObserver e ConcreteSubject que deixa de existir
na abordagem Push.
A ferramenta Hedgehog [2] especifica cada uma das possíveis variações dos
padrão. Cada especificação é submetida isoladamente no sistema de prova. A baixa
flexibilidade torna a solução inviável em uma situação real. Podem existir inúmeras
variações para um único padrão e todas teriam que ser especificadas e verificadas. O
solucionador da ferramenta Ptidej [6] pode identificar soluções aproximadas. A idéia é
usar essa informação a respeito das variações e deixar o solucionador mais inteligente a
ponto de otimizar sua busca por padrões.
Para resolver este problema, duas atividades do fluxo básico definido na seção 3
serão alteradas: a formalização e a identificação de padrões. Na formalização, serão
identificadas as possíveis variações dos padrões, os aspectos comuns serão isolados e
cada uma das variações será especializada. A implementação clássica do padrão
também será especificada. Durante do processo de identificação, o sistema irá buscar
grupos de classes que forem compatíveis com a implementação clássica ou qualquer
variação.
3.2 Relacionamentos entre os diversos padrões de projeto
Os relacionamentos entre os padrões representam o segundo aspecto explorado
neste trabalho. O padrão Command [4], por exemplo, se relaciona com o padrão
Composite [4]. Ele encapsula pedidos como objetos de forma que eles possam ser
parametrizados, enfileirados e até mesmo desfeitos. O objeto cliente fica desacoplado
do objeto que tem o conhecimento para realizar as operações. Essa característica dá
muita flexibilidade a aplicação. A estrutura do padrão é mostrada na Figura 8 extraída
de [4].
21
Figura 8 - Estrutura do padrão Command
Os seguintes componentes participam deste padrão:
1. Command. Defini a interface para execução de uma operação.
2. ConcreteCommand. Especifica a ligação entre o componente Receiver e essa
operação. Implementa a operação usando os métodos de Receiver.
3. Client. Cria um objeto ConcreteCommand e especifica seu Receiver.
4. Invoker. Solicita a Command que execute seu pedido.
5. Receiver. Sabe como executar as operações necessárias para realização do pedido.
As seguintes colaborações ocorrem entre os componentes: primeiro, o
componente Client cria um ConcreteCommand e especifica seu Receiver. O objeto
Invoker armazena o objeto ConcreteCommand. O objeto Invoker solicita a execução de
Command. O objeto ConcreteCommand executa as operações no Receiver para atender
a solicitação.
Às vezes um determinado comando precisa executar uma seqüência de outros
comandos. Neste caso, o componente ConcreteCommand é adaptado para executar um
conjunto de comandos. O componente não tem nenhum Receiver porque cada comando
que ele possui já tem seu próprio Receiver. A Figura 9 extraída de [4] mostra a estrutura
final deste cenário. A classe MacroCommand representa o componente
ConcreteComand e é composta de outros comandos. Quando executada, ela
simplesmente executa as operações em cada um dos seus comandos.
22
Figura 9 - Estrutura adaptada do padrão Command.
Para implementar esse caso especial do padrão Command, usa-se um outro
padrão chamado Composite [4]. Este padrão permite que composições de objetos sejam
tratadas como objetos individuais e que hierarquias parte-todo possam ser
representadas. A estrutura deste padrão é mostrada na Figura 10 extraída de [4].
Figura 10 - Estrutura do padrão Composite .
Os seguintes componentes participam deste padrão:
1. Component. Define uma interface para os objetos da composição. Implementa o
comportamento padrão a todas as subclasses.
2. Leaf. Representa os objetos sem subclasses. Define o comportamento para objetos
primitivos da composição.
23
3. Composite. Define o comportamento para componentes compostos de outros
componentes. Armazena os componentes filhos. Implementa operações relacionadas
aos componentes filhos.
4. Client. Manipula os objetos da composição através da interface Component.
A dinâmica entre os componentes se dá da seguinte forma: o componente Client
usa a interface Component para interagir com os objetos da composição. Se o objeto é
um componente Leaf, então o pedido é tratado diretamente por esse objeto. Caso
contrário, se o objeto for um Composite, então o componente encaminha o pedido para
seus componentes filhos.
O relacionamento existente entre os padrões Command e Composite implica na
acumulação de papéis por determinados componentes. Por exemplo, a entidade do
código que representa o componente ConcreteCommand do padrão Command é a
mesma que representa o componente Composite do padrão Composite. Durante a
detecção dos padrões esta informação deve ser levada em consideração.
Outro exemplo que pode ser citado é o do padrão Facade descrito na seção 2.1
deste documento. Geralmente, somente um objeto do tipo Facade é necessário. Neste
caso, usa-se o padrão Singleton para garantir essa unicidade.
Existem vários outros relacionamentos entre os padrões. A Figura 11 extraída de
[4] mostra outros possíveis relacionamentos entre os diversos padrões.
24
Figura 11 - Possíveis relacionamentos entre os padrões
Os possíveis relacionamentos que existem entre os diversos padrões serão
mapeados e esta informação será usada para ajudar no processo de identificação. Para
isso, algumas alterações serão necessárias no processo atual utilizado pelas ferramentas.
Primeiro, no momento da formalização, o modelo de um padrão terá que ser
atualizado para manter as referências de todos os padrões relacionados. Essa relação
será especificada de forma que informações que qualificam a relação também possam
ser armazenadas. Por exemplo, além da relação entre o padrão A e o padrão B, os
componentes que representam essas relações em cada padrão precisam ser
armazenados.
O processo de identificação será alterado para que possa fazer uso dessa
informação sobre os relacionamentos. A partir dos resultados da busca de um
25
determinado padrão, os padrões relacionados aos seus componentes serão buscados.
Esse procedimento irá se repetir até que todos os padrões forem verificados no sistema.
As implementações atuais analisam cada padrão de forma isolada, sendo assim
para se detectar que dois padrões estão sendo realizados por um determinado grupo de
classes são necessárias duas análises: uma para cada padrão. Considerando que o
domínio da análise é todo o código fonte do sistema e que o número de combinações
possíveis é muitas vezes proibitivo, vários padrões podem ser identificados numa fase
inicial dispensando assim outras análises. Como os relacionamentos ocorrem com muita
freqüência e processo de análise é custoso, a nova abordagem será bem mais
interessante.
3.3 Metodologia
A metodologia utilizada pode ser dividida em duas fases. Cada fase é
responsável pelo tratamento de uma nova propriedade: as variações e os
relacionamentos. As seguintes atividades compõem cada fase:
1. Definição dos padrões a serem explorados. Os padrões que possuem o maior
número de ocorrências das propriedades são priorizados.
2. Formalização dos padrões e suas respectivas propriedades. Nesta atividade os
padrões e suas respectivas propriedades são formalizados para serem
posteriormente utilizados durante a busca. A seção 2.4 descreve mais
detalhadamente essa atividade.
3. Criação dos casos de teste para validar nova solução. Micro-arquiteturas que
implementam os padrões e as propriedades desejadas são criadas.
4. Extensão da ferramenta Ptidej [6] para suportar a nova abordagem proposta. As
adaptações necessárias para que as novas propriedades sejam consideradas
durante o processo de busca são implementadas.
5. Execução dos testes e coleta dos dados. Busca-se comprovar aqui a eficácia da
nova abordagem em relação à atual. As métricas utilizadas foram o tempo gasto
durante a busca pelo padrão e qualidade de solução encontrada. A qualidade,
neste caso, será medida pelo percentual de restrições atendidas. Quando menos
restrições forem violadas maior a qualidade da solução.
26
Ao final das duas fases, busca-se ainda simular casos onde os padrões
apresentem as duas propriedades (variações e relacionamentos) para alcançar resultados
ainda mais significativos.
Considerando apenas a propriedade dos relacionamentos, a metodologia
utilizada pode ser exemplificada da seguinte forma: primeiramente os padrões facade e
singleton são escolhidos. Essa escolha se deve ao fato de que existe uma relação entre
os dois padrões. A classe de fachada do padrão facade geralmente só pode instanciada
uma vez, sendo assim um singleton. O segundo passo é de formalização. As
características dos padrões e suas relações são traduzidas em variáveis e restrições
formando assim um PSR. A seção 2.4 descreve em detalhes esse passo. Para dar início
ao desenvolvimento das melhorias é preciso construir um cenário para testes. Um
sistema pequeno que apresente os dois padrões em questão é criado. A partir desse
ponto, já se pode customizar a ferramenta escolhida como base do desenvolvimento
Ptidej [6]. Essa é a etapa mais complicada por exige um entendimento global do
sistema. Durante a atualização, testes são realizados utilizando o cenário desenvolvido.
Assim que as atualizações estiverem concluídas, inicia-se a última atividade: os testes
finais e coleta de dados. Nesta atividade são coletadas as métricas de tempo e qualidade
necessários para avaliação da qualidade da solução.
27
4 Experimentos
O primeiro desafio enfrentado para realização dos experimentos foi o da configuração
do ambiente. Todos projetos que compõem a ferramenta Ptidej [6] foram configurados.
A interface gráfica do sistema foi isolada para realização dos primeiros testes. O uso da
interface gráfica inviabilizaria a execução dos testes pois atrasaria a obtenção dos
resultados. Apesar da documentação disponível da ferramenta ser de alto nível [6] e não
haver outras fontes disponíveis com maiores de detalhes sobre a arquitetura, o código
dos testes de unidade foi utilizado como exemplo do uso dos componentes do sistema.
Com base nesse código as primeiras detecções foram executadas. Juntamente com o
código do sistema havia também alguns exemplos de arquiteturas que implementavam
alguns padrões e que eram utilizadas como base de testes. Algumas dessas arquiteturas
foram analisadas primeiramente com o auxílio da interface gráfica e em seguida de
forma independente. As mesmas soluções foram obtidas mostrando que a remoção da
interface gráfica não alterou os resultados.
4.1 Relacionamentos
Decidiu-se explorar inicialmente o aspecto “Relacionamentos” dos padrões. As
subseções seguintes detalham os passos necessários para implementação da solução.
4.1.1 Identificação dos Pontos de Extensão
Buscou-se identificar os pontos de extensão necessários para suportar o novo
aspecto ainda não tratado. Essa identificação consistiu de um estudo aprofundado no
código fonte da ferramenta para determinar onde seriam feitas as alterações necessárias.
Dois componentes essenciais do sistema foram identificados: o modelo de dados
e o solucionador. O modelo de dados possui a representação de todas as possíveis
entidades encontradas no código fonte assim como a representação dos padrões. O
solucionador usa as informações fornecidas pelo modelo de dados e define o domínio,
as variáveis e as restrições do problema. Além disso, o solucionador também resolve o
problema.
28
Foram identificados dois tipos de solucionadores. O primeiro especifica
automaticamente as restrições a partir do modelo em uma linguagem intermediária que
é resolvida em seguida. O segundo tipo de solucionador é baseado em Java e não há
necessidade de tradução. Decidiu-se pela utilização do segundo solucionador por não
ser preciso dominar outra linguagem para estendê-lo. A desvantagem do solucionador
baseado em Java é que a parte do modelo que define os padrões é redefinida para
criação das restrições. Este solucionador usa do modelo de dados apenas as informações
relacionadas às entidades do código fonte para definição do domínio. Por conta dessa
característica do solucionador escolhido, a idéia inicial de uma simples extensão no
modelo de dados para armazenar informações adicionais que seriam posteriormente
utilizadas pelo solucionador foi descartada.
Existem dois pacotes principais que compõem o solucionador. Um responsável
pelas definições básicas de restrições e outro que define os problemas. Um problema
define um padrão em termos de variáveis e suas respectivas restrições. Todas as
adaptações descritas a seguir se concentram basicamente nesses dois pacotes.
4.1.2 Os Padrões Facade e Singleton
4.1.2.1 A Implementação do Cenário de Testes
Conforme citado na seção 3.2, os padrões Facade [4] e Singleton [4] podem se
relacionar. Um dos exemplos da própria ferramenta foi adaptado. Foram adicionadas
características de Singleton a um dos componentes de uma arquitetura que
originalmente implementava somente o padrão Facade. A Figura 12 ilustra o diagrama
de classes final obtido.
29
Figura 12 - Diagrama de classes - Facade e Singleton
A entidade Compiler que exercia apenas o papel de facade no sistema passa a
exercer o papel adicional de Singleton. As características do padrão Singleton foram
implementadas na classe que representa a entidade Compiler no sistema.
4.1.2.2 A Implementação da Solução
O problema para o padrão Facade já estava definido juntamente com o código
original da ferramenta Ptidej [6] e pôde ser reutilizado. O maior desafio foi definir o
problema para o padrão Singleton e integrá-lo com o problema do padrão Facade.
Os seguintes passos foram seguidos para implementação do problema para o
padrão Singleton:
1. Extensão do modelo de dados. Originalmente, ao se construir uma representação
de uma entidade do código apenas os nomes dos seus membros eram armazenados.
Foram criadas duas novas estruturas de dados para manter os atributos e os métodos
de cada entidade. Isso possibilitou a extração de informações mais específicas para
definição da nova restrição.
2. Implementação da restrição Singleton. Considerando que o padrão Singleton é
composto por apenas um componente, um novo tipo de restrição precisou ser criado.
Ao contrário de todas as outras definições de restrições existentes que relacionavam
duas variáveis, essa nova restrição teria que estar relacionada à apenas uma variável.
Essa nova restrição foi criada a partir da extensão de um tipo abstrato de restrição do
sistema. A lógica responsável pela redução do domínio de uma variável através de
restrições foi mudada. A decisão da eliminação de uma entidade do domínio é
30
tomada avaliando se as características do padrão Singleton estão presentes. O
método isSingleton mostrado na Figura 13 realiza essa verificação.
Figura 13 - Definição do método isSingleton.
O método isSingleton recupera a lista dos campos da entidade (knownFields) e
verifica se existe um campo do mesmo tipo da entidade que possua a visibilidade
privada e que seja do tipo estático. Em seguida, um método que tenha tipo de retorno
igual ao da classe e possua o nome getInstance é buscado na lista de métodos da
entidade (knownMethods). Se as duas propriedades forem verdadeiras, então a entidade
é considera um Singleton.
3. Definição do novo problema. Com a nova restrição implementada foi possível
definir o problema para o padrão Singleton. Criou-se uma variável para representar
o componente Singleton do padrão e adicionou-se a restrição relacionada a esta
variável.
Por último foi feita a integração dos problemas. A definição do problema para
detecção do padrão facade foi atualizada. A nova restrição Singleton foi adicionada a
variável que representava o componente facade do problema. O procedimento de
integração não é tão simples quanto parece. Cada problema é constituído de variáveis e
restrições relacionadas. A simples adição das variáveis e restrições não é possível.
Variáveis e restrições redundantes podem inviabilizar o processo de busca. Em alguns
31
casos, duas ou mais variáveis em problemas diferentes devem ser representadas por uma
única variável no novo problema. Como as variáveis são atualizadas, a restrições
também devem ser revisadas para não se tornarem redundantes ou mesmo incorretas.
4.1.2.3 Execução dos Testes e Análise dos Resultados
Os testes foram executados sobre a arquitetura definida na seção 4.1.2.1. Na
tentativa de comprovar a eficácia da integração dos problemas em relação à solução
anterior algumas detecções foram executadas. Primeiro, a detecção foi feita utilizando
apenas o problema para o padrão Facade, depois apenas para o padrão Singleton e ao
final com os problemas Singleton e Facade integrados. A Tabela 3 e a Figura 14
mostram os resultados observados durante os testes.
Padrão Procurado Estratégia de busca
Número de
soluções
encontradas
Execução 1 Execução 2 Execução 3 Média
Facade Individual 13 4,927 4,186 4,106 4,41
Singleton Individual 1 0,171 0,161 0,18 0,17
Facade + Singleton Integração 7 1,432 1,212 1,282 1,31
14 4,58
Tempo de Busca (segundos)
Total gasto com as buscas individuaisTotal de soluções com as buscas individuais
Tabela 3 - Resultados dos testes de detecção (Facade e Singleton)
4,58
1,31
14
7
0
2
4
6
8
10
12
14
16
Individual Integração
Estratégia de busca
Tempo de Busca (segundos)
Número de soluções encontradas
Figura 14 - Gráfico comparativo das estratégias de detecção (Facade e Singleton)
Analisando os resultados entre a detecção utilizando o problema para padrão
facade e o problema integrado para os padrões facade e singleton, pode-se perceber que
o número de soluções encontradas diminuiu de 13 para 7. Quando apenas as restrições
32
do padrão facade são consideradas, vários grupos de classes da arquitetura atendem
essas restrições. No entanto, quando a busca é realizada utilizando a nova restrição
Singleton, apenas uma classe satisfaz essa restrição e conseqüentemente o número de
possibilidades diminui drasticamente.
Outra melhoria observada foi no tempo de busca. Observou-se uma redução de
cerca de 70%, caindo de 4,41 para 1,31 segundos. Como o domínio da variável facade é
reduzido logo de início pela aplicação da restrição Singleton, as possíveis atribuições de
variáveis também são reduzidas levando a um resultado mais rápido. Se for considerada
a soma dos tempos das duas buscas individuais: Singleton e Facade a diferença é um
pouco maior.
4.1.3 Generalização da Solução
A integração dos problemas que foi descrita na seção 4.1.2.2 apresenta algumas
limitações. Os problemas estão definidos diretamente no código fonte. Para cada padrão
existe uma classe que o define. Nessa arquitetura, para cada relacionamento novo que
fosse definido, seria necessário criar uma nova classe. Essa redundância nas definições
dificultaria a manutenção do sistema. Qualquer alteração na definição de um problema
de um determinado padrão teria que ser replicada nas definições de seus
relacionamentos. O procedimento de integração dos problemas não é simples e está
sujeito a erros. Qualquer variável ou restrição integrada erroneamente poderia afetar a
qualidade da solução ou mesmo impossibilitá-la. Além disso, existe alto acoplamento
entre as definições dos problemas e os módulos do sistema que os usam. Esse
acoplamento exige que o módulo cliente conheça explicitamente a definição do
problema.
Para resolver os problemas citados acima uma nova arquitetura foi
implementada. A idéia foi remover todas as definições de padrões e o mapeamento dos
relacionamentos do código de forma que essas informações pudessem ser carregadas
dinamicamente. Uma base de dados foi definida para o armazenamento em disco dessas
informações. A base de dados foi manualmente alimentada. Foram criados os conceitos
de padrão de origem e padrão de destino. Esses conceitos representam apenas a direção
da relação. Um padrão de origem é qualquer padrão que se relaciona com outros
padrões de destino. Os seguintes campos foram definidos para cada padrão na base de
dados:
33
1. Nome do padrão. O nome do padrão de origem que o identifica unicamente na base.
2. Variáveis. As variáveis do padrão de origem.
3. Restrições. As restrições que existem entre as variáveis do padrão de origem.
4. Padrões Relacionados. Todos os padrões de destino relacionados. Cada relação é
caracterizada pela variável do padrão de origem e a variável correspondente no
padrão destino.
Foi criado um Gerador de Problemas que recupera essas definições da base e
gera os problemas. O Gerador possui a lógica necessária para integração automática do
padrão de origem e os seus padrões de destino. A integração é caracterizada
principalmente pelo processamento do campo “Padrões Relacionados” do padrão de
origem. O algoritmo de integração é composto dos seguintes passos:
1. As variáveis e restrições do padrão de origem são adicionadas ao problema.
2. Para cada padrão de destino do padrão de origem, os seguintes passos são
executados:
a) As variáveis do padrão de destino que não estiverem relacionadas com o padrão
de origem são incluídas no problema. As outras variáveis que possuírem relação
são ignoradas. Isso significa que já existe uma variável no problema que a
representa. Ou seja, em um problema integrado, uma variável pode representar
dois componentes de padrões distintos.
b) Todas as restrições do padrão de destino são adicionadas ao problema. Se
alguma restrição estiver relacionada a uma variável que foi ignorada no passo
anterior, então essa referência é atualizada para uma variável válida.
Ao final do processo é gerado um único problema integrado. Esse processo fica
transparente para o módulo cliente.
34
4.1.4 Os Padrões Command e Composite
4.1.4.1 A Implementação do Cenário de Testes
Conforme descrito na seção 3.2, existe uma extensão do padrão Command [4]
onde um comando é composto de uma seqüência de comandos menores. Essa
composição pode ser implementada através do padrão Composite [4]. A Figura 15
ilustra o diagrama de classes final obtido.
Figura 15 - Diagrama de classes - Command e Composite
A entidade ConcreteCommand1 exerce dois papéis neste sistema. Primeiro
como ConcreteCommand do padrão Command e ao mesmo tempo a de Leaf do padrão
Composite. Da mesma forma, a entidade Command_Component representa o
componente Command do padrão Command e o componente Component do padrão
Composite.
4.1.4.2 A Implementação da Solução
Inicialmente, os padrões escolhidos para o segundo cenário foram modelados. A
base de dados foi atualizada com a descrição dos novos padrões: Command e
Composite. Buscas individuais foram realizadas sobre a arquitetura definida na Figura
15 e os resultados foram coletados. Em seguida foi feita uma busca integrando os dois
padrões. Ao contrário dos resultados do primeiro cenário, não houve nenhuma melhoria
na busca considerando as relações entre os padrões. A partir dessa constatação decidiu-
se por outra abordagem. A idéia foi utilizar os resultados da primeira pesquisa para
parametrizar as pesquisas posteriores. O domínio das variáveis a partir da segunda
35
busca é reduzido gradativamente. Por exemplo: a solução obtida através da busca pelo
padrão Command serviu de entrada para busca pelo padrão Composite. As entidades do
domínio original que foram atribuídas as variáveis Command e ConcreteCommnad
definiram o domínio das variáveis Component e Leaf, respectivamente, do segundo
problema.
4.1.4.3 Execução dos Testes e Análise dos Resultados
A Tabela 4 abaixo mostra os resultados finais obtidos:
Padrão Procurado Estratégia de busca
Número de
soluções
encontradas
Tempo de
Busca
(milisegundos)
Percentual de
Aderência
command Individual 2 871 100
composite Individual 2 991 100
command + composite Integração 2 1733 100
command + composite Redução de domínios 2 1471 100 Tabela 4 - Resultados dos testes de detecção (Command e Composite)
O percentual de aderência da solução é medido pelo número de restrições
atendidas. Como todas as restrições foram atendidas para as soluções, o percentual é de
100%. Todas as buscas encontraram duas soluções. Isso se deve ao fato de duas
entidades do código atenderem todas as restrições relacionadas a uma determinada
variável. O solucionador gera duas soluções, uma para cada entidade. Isso ocorre com a
variável invoker do padrão Command e com a variável client do padrão Composite.
Comparando o tempo de busca gasto utilizando a estratégia de integração (1733
milisegundos) com a soma dos tempos das duas buscas individuais (1862
milisegundos), pode-se perceber que a economia foi mínima. A soma das restrições dos
padrões e a eliminação de algumas variáveis não foi suficiente para diminuir o tempo de
busca total. Por outro lado, utilizando a estratégia de redução de domínios, houve uma
redução considerável. O tempo total de busca reduziu em cerca de 20%. Considerando
apenas o tempo da segunda busca, houve uma redução de cerca de 40%. Esta economia
deve-se quase que exclusivamente a redução do domínio da variável leaf. O tipo das
restrições relacionadas a cada variável que tem seu domínio reduzido também influencia
o tempo total da busca.
Apesar dos resultados obtidos com a redução de domínios terem sido bastante
promissores, esta estratégia apresenta uma limitação. A partir da segunda busca,
algumas variáveis podem ter seus domínios muito reduzidos de forma que a busca
ignore outros padrões presentes no código. Por exemplo, no cenário atual, se o domínio
36
da variável ConcreteCommand na primeira busca fosse reduzido a apenas uma entidade,
a segunda busca pelo padrão Composite iria considerar apenas essa entidade como valor
válido para sua variável Leaf. Se o padrão Composite estiver implementado em outro
ponto do código, ele será ignorado. Uma possível solução para este problema seria a
implementação de nova estratégia de busca onde não houvesse a redução direta dos
domínios mas sim uma priorização nas buscas. Os valores com maior chance de sucesso
seriam atribuídos primeiro e as todas as outras combinações seriam testadas
posteriormente.
4.1.5 Aplicabilidade da Solução para Sistemas Reais
Na tentativa de validar a solução desenvolvida neste trabalho para sistemas reais,
com um número de classes maior, o cenário básico definido na Figura 15 foi estendido.
A partir dessa arquitetura base com 7 classes, foram gerados outros dois cenários
adicionando mais classes. No primeiro, o número de classes total atingiu 14 e, no
segundo, 28. A adição das novas classes foi totalmente aleatória. Não se levou em
consideração a estrutura das mesmas. A partir dos 2 cenários prontos, as seguintes
buscas foram feitas:
1. Busca pelo padrão command.
2. Busca pelo padrão composite.
3. Busca pelo padrão composite com a utilização dos resultados da busca 1, ou seja,
utilizando a estratégia de redução de domínios.
Todas as três buscas foram executadas 3 vezes para cada um dos cenários, com
7, 14 e 28 classes. Ao final foi calculada a média da economia entre as buscas. Os
resultados obtidos podem ser vistos na Tabela 5.
command Individual 265 266 281 609 609 578 875 857 922
composite Individual 312 312 281 422 406 484 719 1265 687
composite Redução de domínios 234 250 234 234 250 359 516 516 469
command + composite Redução de domínios 499 516 515 843 859 937 1391 1373 1391
Economia parcial 0,14 0,11 0,08 0,18 0,15 0,12 0,13 0,35 0,14
Economia média (%)
Estratégia de buscaTempo de Busca (milisegundos) / Número de classes no sistema
Padrão Procurado 7 14 28
10,87 15,12 20,53
Tabela 5 - Resultados dos testes de detecção para bases maiores
37
7
14
28
0
5
10
15
20
25
30
10,87 15,12 20,53
Economia (%)
Número de Classes
Figura 16 - Gráfico da relação entre a economia e o número de classes do sistema
O gráfico da Figura 16 mostra a relação entre a economia obtida nas buscas e o
aumento do número de classes no sistema. Pode-se perceber que a economia aumenta
significativamente com o aumento das classes do sistema. Para 7 classes, temos uma
economia de 10,87%, mas para um sistema 4 vezes maior a economia já é de 20,53%.
Como um sistema de 28 classes ainda pode ser considerado pequeno em termos
práticos, pode-se esperar uma economia final ainda maior.
Houve uma pequena variação com relação ao número de soluções encontradas.
Por exemplo, no sistema com 7 classes, foram encontradas 2 ocorrências do padrão
command, já no sistema com 14, foram encontradas 8. Isso se deve ao aumento da
possibilidade de novas combinações válidas que atentam todas as restrições.
Independentemente dessa variação, um mesmo subconjunto de soluções foi encontrado
em todas as buscas. Esse subconjunto representa as soluções perfeitas que identificam
exatamente cada membro do padrão.
38
4.2 Variações
4.2.1 A Implementação do Cenário de Testes
O padrão escolhido para o desenvolvimento do cenário de testes foi o Bridge [4]. O
objetivo desse padrão é desacoplar as abstrações das implementações de modo que as
duas possam variar independentemente. Geralmente esse problema é tratado com
herança. Uma classe abstrata define uma interface e classes concretas a implementam de
diversas formas. Essa abordagem não é suficientemente flexível. A herança acopla uma
implementação à abstração e isso dificulta a modificação, extensão e reuso das
abstrações e implementações independentemente. Conforme mostrado na Figura 17.1, o
padrão Bridge [4] trata esse problema separando as abstrações e as implementações em
duas hierarquias de classes distintas. A relação entre essas duas hierarquias que é
chamada de ponte. Os seguintes componentes participam deste padrão:
1. Abstration. Define uma interface de abstração. Mantém uma referência para um
objeto do tipo Implementor.
2. RefinedAbstration. Implementa a interface definida por Abstration.
3. Implementor. Define a interface para as classes de implementação. Esta interface
não precisa corresponder exatamente à interface de abstração.
4. ConcreteImplementor. Implementa a interface definida por Implementor e define a
implementação concreta.
A interação entre os componentes é bem simples. O objeto Abstration encaminha
os pedidos de algum objeto Client para um objeto Implementor.
O cenário ilustrado na Figura 17.2 retrata uma variação da estrutura original do
padrão onde só existe uma implementação [4]. Neste caso, não há necessidade da
definição de uma classe abstrata para as implementações. O componente
ConcreteImplementor, assim como todas as suas relações, deixam de existir. A
separação imposta pelo padrão continua sendo útil pois uma mudança na
implementação não afeta os clientes existentes. Eles não precisam ser recompilados.
39
Figura 17 - Cenário original (1) e da variação (2) do padrão Bridge.
4.2.2 Execução dos Testes e Análise dos Resultados
Os testes realizados consideram três estratégicas de busca:
1. Busca Clássica. Utiliza a definição da estrutura clássica do padrão para orientar
o solucionador na busca.
2. Busca com Relaxamento. Relaxa as restrições da estrutura clássica que deixam
de existir na variação do padrão.
3. Buscas Encadeadas. Utiliza as duas definições distintas, uma para o padrão
clássico e outra para a variação.
A Tabela 6 resume os resultados obtidos nos testes. O percentual de aderência da
solução também será considerado para esses testes. Este percentual está relacionado ao
número de restrições atendidas por uma determinada solução. Por exemplo, se todas as
restrições forem atendidas, o percentual será de 100%.
40
Executando a busca clássica pelo padrão Bridge no cenário da variação,
nenhuma solução é encontrada. Isso é de certa forma óbvio. A restrição que envolve o
componente que deixou de existir não pode ser mais atendida. A primeira tentativa foi
de relaxar essa restrição. O peso da mesma foi diminuído de forma que o solucionador
pudesse eliminá-la caso não encontrasse soluções completas. Sendo assim, uma solução
parcial foi encontrada. Apesar de detectar essa solução parcial para o cenário da
variação, a abordagem apresenta algumas desvantagens, tais como:
1. A distorção da solução parcial pode acabar confundindo o usuário. O
componente ConcreteCommand recebe várias atribuições incorretas. Isso porque
a restrição removida era a única que envolvia a variável que representava o
componente no problema. O percentual de aderência caiu para 75%.
2. O relaxamento aumenta o número de soluções no cenário original. Mais
soluções completas são encontradas. Quando maior o número de soluções, mais
complicada é a análise do usuário.
Com o objetivo de evitar essas desvantagens, uma segunda abordagem foi
implementada. Inicialmente a definição da variação do padrão foi adicionada a base de
dados descrita na seção 4.1.3. Depois disso, o solucionador foi atualizado de forma que
ambas as definições (clássica e variação) fossem consideradas na busca. Essa estratégia
é chamada de buscas encadeadas. Primeiro é feita uma busca pela definição clássica do
padrão. Se não forem encontradas soluções completas, então uma segunda busca pela
definição da variação é disparada. Os resultados dessa nova abordagem foram bastante
satisfatórios. Em ambos os cenários, soluções completas foram encontradas. Como o
solucionador sabe qual é definição exata do padrão que está sendo procurado, apenas as
variáveis relevantes são consideradas na busca e apresentadas na solução. Além disso, a
eficiência também é melhor em relação ao relaxamento. Se a soma dos tempos entre as
buscas utilizando a estratégia de relaxamento (337 milisegundos) e as buscas
encadeadas (203 milisegundos) forem comparadas, pode-se perceber um ganho de 40%
no tempo de processamento. Isso ocorre por que com o relaxamento o solucionador
precisa computar um número maior de combinações. Outras comparações entres as
novas abordagens desenvolvidas neste trabalho e a implementação original da
ferramenta Ptidej [6] não são possíveis, visto que a ferramenta não detecta variações.
41
Estratégia de busca Cenário
Número de
soluções
encontradas Aderência (%)
Tempo de Busca
(milisegundos)
Clássica Original 1 100 125Clássica Variação 0 0 0
Relaxamento Original 2 75 187Relaxamento Variação 1 75 150
Total 337
Buscas Encadeadas Original 1 100 125Buscas Encadeadas Variação 1 100 78
Total 203 Tabela 6 - Comparação entre a abordagem clássica e as novas abordagens.
A abordagem das buscas encadeadas pode ser otimizada. Não há um
aproveitamento do conhecimento adquirido em buscas anteriores. O ideal seria utilizar
uma abordagem híbrida onde houvesse o relaxamento da restrição variante e a
interpretação da solução parcial. O solucionador analisaria apenas a parte variante da
solução parcial e verificaria se as restrições não atendidas fazem parte de alguma
variação do padrão. Se fizerem, a solução pode ser aceita como completa. Ao apresentar
essa solução para o usuário, as variáveis que não fizerem parte da variação precisam ser
omitidas.
42
5 Conclusão e Trabalhos Futuros
Antes de qualquer coisa, o trabalho atual evidência o descaso com a fase de
manutenção de software. Muito pouco é feito para auxiliar esta etapa do
desenvolvimento de software. Paralelamente, o uso cada vez mais intenso dos padrões
de projeto no desenvolvimento de sistemas é mostrado como uma tendência. A
detecção desses padrões para auxiliar a manutenção do sistema é uma idéia inovadora
mas que ainda possue limitações.
Com base nas ferramentas pesquisadas, pode-se observar um processo com
atividades comuns. Foram avaliadas as melhores alternativas para cada uma das
atividades. A ferramenta Ptidej [6] foi considerada a mais extensível. Ela foi utilizada
como base para a implementação de todo o trabalho. Além disso, algumas técnicas
puderam ser validadas. A programação orientada a restrições se mostrou bastante
adequada para resolução do tipo de problema abordado no trabalho. Problemas esses
que envolvem flexibilidade. O algoritmo MAC-DBT [9] utilizado para resolução dos
problemas é bastante otimizado. A complexidade de tempo e espaço é a melhor em
relação às outras abordagens.
Durante a implementação da solução, todas as principais decisões de projeto
foram documentadas. O nível de detalhe fornecido é suficiente para que novas
propriedades possam ser futuramente incorporadas. Houve uma evolução entre um
cenário e outro. As soluções anteriores foram reutilizadas e otimizadas. A remoção das
definições dos padrões do sistema para uma base de dados externa merece destaque.
Essa medida agilizou bastante a execução dos testes e coleta de resultados.
O principal objetivo do trabalho foi atingido. Conseguiu-se provar que a
utilização de certas propriedades dos padrões pode ajudar na melhoria do processo de
busca atual. Sendo assim, entende-se que houve uma evolução no sentido de explorar
esses e outros aspectos inerentes aos padrões que ainda não são considerados.
No caso específico dos relacionamentos, o principal ganho foi o de desempenho.
Mesmo em cenários pequenos pôde-se constatar uma melhoria considerável no tempo
de busca. O conhecimento dos possíveis relacionamentos deixa o solucionador
extremamente mais inteligente. Os testes com bases maiores revelaram que a economia
aumenta significativamente com o aumento do tamanho do sistema.
Ao invés de melhorar o desempenho da busca, a exploração das variações teve
um outro efeito. Ela melhorou a qualidade do resultado obtido. O relaxamento da
43
restrição variante ajuda o solucionador a não ignorar soluções parciais que representam
variações. Melhor ainda do que o relaxamento é a busca pelas duas definições, a
clássica e a variação. Neste caso, soluções exatas são encontradas.
Por fim é importante ressaltar o perfil do usuário desse tipo de sistema. O
domínio avançado dos conceitos de padrões de projeto e da lógica de negócios do
sistema é indispensável. De posse dos resultados de detecção, o usuário tem que ser
capaz de entender o papel de um padrão dentro do sistema e eliminar possíveis soluções
falso-positivas. A detecção dos padrões só é útil quando corretamente interpretada. A
automatização da tarefa é muito importante mas não substitui a função do especialista.
Ela apenas agiliza a tomada de decisões e dá dicas de possíveis ocorrências dos padrões.
5.1 Trabalhos Futuros
Durante as pesquisas realizadas neste trabalho, surgiram algumas idéias, que por
serem consideradas fora de escopo, não foram totalmente exploradas. Algumas delas
são citadas abaixo:
1. Exploração simultânea das propriedades. Em ambientes reais, tanto os
relacionamentos quanto as variações podem ocorrer simultaneamente. Diante desse
contexto, seria interessante desenvolver cenários de teste onde as duas propriedades
estivessem presentes. A expectativa é de que os resultados finais sejam ainda
melhores do que encontrados neste trabalho.
2. Novas propriedades. Além das propriedades exploradas neste trabalho, outras
poderiam ser consideradas. Quando maior o conhecimento sobre as características
inerentes aos padrões, melhor será o resultado das buscas.
3. Formalização de outros padrões. Para que a nova abordagem proposta neste trabalho
possa ser utilizada efetivamente, faz-se necessário a formalização de vários outros
padrões. O usuário desse tipo de ferramenta geralmente necessita da detecção de
todos os padrões existentes no sistema para que sua análise possa ser facilitada. A
seleção dos próximos padrões a serem formalizados deve seguir o mesmo critério
utilizado neste trabalho. Padrões que apresentem o maior número de ocorrências das
propriedades estudadas devem ser priorizados, ou seja, padrões que apresentem
relacionamentos e variações.
44
4. Aprimoramento do algoritmo de detecção. As limitações descritas no trabalho são
pontos que também podem ser explorados no futuro. Dependendo da propriedade
escolhida, as seguintes melhorias podem ser implementadas:
a. Relacionamentos. O algoritmo de busca pode ser aprimorado de forma que a
redução dos domínios não exclua precocemente nenhuma solução do
problema. Uma nova estratégia de busca onde não houvesse uma redução
direta dos domínios mas sim uma priorização nas buscas poderia ser
implementada. Os valores com maior chance de sucesso seriam atribuídos
primeiro e todas as outras combinações seriam testadas posteriormente. As
melhores soluções seriam encontradas primeiro enquanto outras soluções
menos prováveis pesquisadas posteriormente.
b. Variações. Ainda não há um aproveitamento do conhecimento adquirido em
buscas anteriores. O ideal seria utilizar uma abordagem híbrida onde
houvesse o relaxamento da restrição variante e a interpretação da solução
parcial.
5. Desenvolvimento de interface gráfica. Uma interface gráfica amigável e intuitiva
seria fundamental para popularização da solução. A exibição simultânea dos vários
padrões detectados seria um requisito básico. O usuário deveria poder alternar entre
essa interface e o código fonte da aplicação. Esse módulo de visualização poderia se
integrar ao ambiente de desenvolvimento do usuário para facilitar ainda mais suas
análises.
Todas os temas elencados acima são de fundamental importância e
complementam o trabalho realizado.
45
Referências
[1] Barták, R. Constraint Programming: In Pursuit of Holy Grail. Proceedings of Week
of Doctoral Students, Prague, 1999.
[2] Blewitt, A; Bundy, A; Stark, I. Automatic Verification of Java Design Patterns. In
ASE'01: Proceedings of the 16th IEEE International Conference on Automated
Software Engineering, November 26-29, 2001, San Diego, California, pages 324-
327. IEEE Computer Society Press, 2001.
[3] Dietrich, J; Elgar, C. Towards a Web of Patterns, Workshop on Semantic Web
Enabled Software Engineering (SWESE) at the 4th Semantic Web Conference
(ISWC 2005), Galway, Ireland, 2005.
[4] Gamma, R; Helm, R; Johnson, R, Vlissides, J. Design Patterns: Elements of
Reusable Object-Oriented Software, Addison Wesley, 1995.
[5] Gueheneuc, Y; Albin-Amiot, H. Using design patterns and constraints to automate
the detection and correction of inter-class design defects. In Quioyun Li, Richard
Riehle, Gilda Pour, and Bertrand Meyer, editors, Proceedings of the 39th conference
on the Technology of Object-Oriented Languages and Systems, pages 296--305.
IEEE Computer Society Press, July 2001.
[6] Gueheneuc, Y. Ptidej: Promoting Patterns with Patterns. Proceedings of the
ECOOP workshop on Building a System with Patterns, 2005.
[7] Gueheneuc, Y; Jussien, N. Using explanations for design patterns identification.
Proceedings of the 1st IJCAI workshop on Modeling and Solving Problems with
Constraints, pages 57--64, 2001.
[8] Jussien, N; Barichard, V. The PaLM system: explanation-based constraint
programming. Proceedings of TRICS: Techniques for Implementing Constraint
programming Systems, a post-conference workshop of CP 2000, pages 118--133,
2000.
[9] Jussien, N; Debruyne, R; Boizumault, P. Maintaining Arc-Consistency within
Dynamic Backtracking. Principles and Practice of Constraint Programming (CP
2000), Lecture Notes in Computer Science, no. 1894, pages 249--261, Springer-
Verlag, 2000.
[10] Jussien, N. e-constraints: explanation-based Constraint Programming. CP01
Workshop on User-Interaction in Constraint Satisfaction, 2001.
46
[11] Miguel, I; Shen, Q. Solution Techniques for Constraint Satisfaction Problems:
Foundations. Artificial Intelligence Review, v.15 n.4, pages 243--267, June 2001.
[12] Miguel, I; Shen, Q. Solution Techniques for Constraint Satisfaction Problems:
Advanced Approaches. Artificial Intelligence Review, v.15 n.4, pages 264--293,
June 2001.
[13] Newkirk, J. Introduction to agile processes and extreme programming.
Proceedings of the 24th international conference on Software engineering, pages
695--696, ACM Press New York, NY, USA, 2002.
[14] Russell, S; Norvig, P. Artificial Intelligence: A Modern Approach, Prentice Hall,
1995.
Livros Grátis( http://www.livrosgratis.com.br )
Milhares de Livros para Download: Baixar livros de AdministraçãoBaixar livros de AgronomiaBaixar livros de ArquiteturaBaixar livros de ArtesBaixar livros de AstronomiaBaixar livros de Biologia GeralBaixar livros de Ciência da ComputaçãoBaixar livros de Ciência da InformaçãoBaixar livros de Ciência PolíticaBaixar livros de Ciências da SaúdeBaixar livros de ComunicaçãoBaixar livros do Conselho Nacional de Educação - CNEBaixar livros de Defesa civilBaixar livros de DireitoBaixar livros de Direitos humanosBaixar livros de EconomiaBaixar livros de Economia DomésticaBaixar livros de EducaçãoBaixar livros de Educação - TrânsitoBaixar livros de Educação FísicaBaixar livros de Engenharia AeroespacialBaixar livros de FarmáciaBaixar livros de FilosofiaBaixar livros de FísicaBaixar livros de GeociênciasBaixar livros de GeografiaBaixar livros de HistóriaBaixar livros de Línguas
Baixar livros de LiteraturaBaixar livros de Literatura de CordelBaixar livros de Literatura InfantilBaixar livros de MatemáticaBaixar livros de MedicinaBaixar livros de Medicina VeterináriaBaixar livros de Meio AmbienteBaixar livros de MeteorologiaBaixar Monografias e TCCBaixar livros MultidisciplinarBaixar livros de MúsicaBaixar livros de PsicologiaBaixar livros de QuímicaBaixar livros de Saúde ColetivaBaixar livros de Serviço SocialBaixar livros de SociologiaBaixar livros de TeologiaBaixar livros de TrabalhoBaixar livros de Turismo