refatora o do framework ocean para … · sua recodificação em linguagem java. este trabalho...
TRANSCRIPT
UNIVERSIDADE FEDERAL DE SANTA CATARINA
CENTRO TECNOLÓGICO
DEPARTAMENTO DE INFORMÁTICA E ESTATÍSTICA
BACHARELADO EM CIÊNCIAS DA COMPUTAÇÃO
REFATORAÇÃO DO FRAMEWORK OCEAN PARA DESACOPLAMENTO DE ESPECIFICIDADES DE INTERFACE
ANDREY MORAIS BRÜGGEMANN
MONOGRAFIA DE CONCLUSÃO DO CURSO DE CIÊNCIAS DA COMPUTAÇÃO
Orientador: Ademir Coelho Co-orientador: Ricardo Pereira e Silva, Dr.
Florianópolis, 2010.
ANDREY MORAIS BRÜGGEMANN
2
REFATORAÇÃO DO FRAMEW ORK OCEAN
PARA DESACOPLAMENTO DE ESPECIFICIDADES
DE INTERFACE
Trabalho de conclusão de curso apresentado como parte das exigências do Curso de Ciências da Computação, da Universidade Federal de Santa Catarina, para obtenção do grau de Bacharel.
Orientador: Ademir Coelho
Co-orientador: Ricardo Pereira e Silva
Florianópolis, 2010
3
Autoria: Andrey Morais Brüggemann
Título: Refatoração do framework OCEAN para desacoplamento de especificidades de interface
Trabalho de conclusão de curso apresentado como parte das exigências do Curso de Ciências da Computação, da Universidade Federal de Santa Catarina, para obtenção do grau de Bacharel.
Os componentes da banca de avaliação, abaixo listad os, consideram este trabalho aprovado.
Nome Titulação Assinatura Instituição
1 Ademir Coelho Graduado Universidade Federal de Santa Catarina
2 Patrícia Vilain Doutora Universidade Federal de Santa Catarina
3 Ricardo Pereira e Silva Doutor Universidade Federal de Santa Catarina
4 Roberto Silvino Mestre Universidade Federal de Santa Catarina
Data da aprovação: ____ de _____________________ de ________.
4
“Dedico este trabalho aos meus pais,
Luiz e Mary, e aos meus irmãos, Rômulo,
Cíntia e Luiz Paulo.”
5
AGRADECIMENTOS
Agradeço a Deus por ter me dado a
capacidade de pensar. Á minha família, por ter
confiado em mim. Ao meu amigo Leonardo
que me apoiou e apresentou à oportunidade de
realizar este trabalho. Ao Ademir, pela grande
ajuda prestada. Ao professor Ricardo, pela
oportunidade dada. Enfim, a todos as pessoas
que me ajudaram na realização deste
trabalho.
6
RESUMO
À medida que um software sofre alterações, a qualidade de seu código e projeto tende a diminuir, apresentando problemas como duplicidade e falta de clareza. O framework OCEAN foi criado por Ricardo Pereira e Silva, em sua tese de doutorado, usando SmallTalk. Suporta a criação de ambientes de desenvolvimento de software que manipulam especificações de projeto. Desde a sua criação, este framework passou por diversas modificações, destacando a sua recodificação em linguagem Java. Este trabalho pretende executar refatorações sobre o framework OCEAN, a fim de reduzir o acoplamento entre sua interface gráfica e suas classes de modelo.
Palavras-chave: framework, reuso, refatoração.
7
ABSTRACT
As a project changes, the quality of your code and design tend to decrease, causing
problems such as duplication and lack of clarity. The OCEAN framework was created by Ricardo Pereira e Silva, in his doctoral thesis, using SmallTalk. Supports the creation of software development environments that handle project specifications. Since its inception, this framework has undergone several changes, highlighting its recoding in Java. This paper intends to refactor the OCEAN framework to promote the decoupling between the GUI and its model classes.
8
SUMÁRIO
1 Introdução ........................................ .................................................................. 10
1.1 Motivação .....................................................................................................................11
1.2 Tema ............................................................................................................................11
1.3 Organização do Texto.................................................................................................. 12
2 Frameworks orientados A objetos ................... ................................................. 13
2.1 Inversão de Controle ................................................................................................... 15
2.2 Classificação dos frameworks ..................................................................................... 16
2.2.1 Classificação quando ao uso ..................................................................................................... 16
2.2.2 Classificação quanto ao escopo ................................................................................................ 19
2.3 Benefícios do uso de frameworks ................................................................................ 20
2.3.1 Modularidade .............................................................................................................................. 20
2.3.2 Reusabilidade ............................................................................................................................. 20
2.3.3 Extensibilidade ........................................................................................................................... 21
2.3.4 Robustez .................................................................................................................................... 21
2.4 Desvantagens dos frameworks ................................................................................... 21
3 O framework OCEAN ................................. ........................................................ 23
3.1 Estrutura...................................................................................................................... 24
3.2 Relacionamentos entre elementos de especificação ................................................... 25
3.3 Reusabilidade do framework OCEAN .......................................................................... 26
3.4 Funcionalidades supridas pelo OCEAN ....................................................................... 27
3.4.1 Especificações ........................................................................................................................... 27
3.4.2 Diagramas UML ......................................................................................................................... 28
3.4.3 Explicitação da flexibilidade de um framework .......................................................................... 30
3.4.4 Navegação ................................................................................................................................. 30
3.4.5 Armazenamento ......................................................................................................................... 31
3.5 Migração para Java ..................................................................................................... 31
4 Refatoração ....................................... ................................................................. 35
4.1 O processo de refatoração .......................................................................................... 36
4.2 Maus cheiros ............................................................................................................... 37
4.2.1 Código duplicado ........................................................................................................................ 38
9
4.2.2 Método longo .............................................................................................................................. 38
4.2.3 Classe grande ............................................................................................................................ 38
4.2.4 Lista de parâmetros longa .......................................................................................................... 38
4.2.5 Alteração divergente .................................................................................................................. 39
4.2.6 Cirurgia com rifle ........................................................................................................................ 39
4.3 Catálogos de refatorações .......................................................................................... 39
4.4 Ferramentas de auxílio à refatoração .......................................................................... 40
4.4.1 Verificadores estáticos ............................................................................................................... 40
4.4.2 Testes de unidade ...................................................................................................................... 42
4.4.3 Ambientes de desenvolvimento com suporte à refatorações automatizadas ............................ 42
4.5 Vantagens da refatoração ........................................................................................... 44
4.6 Problemas com a refatoração ...................................................................................... 44
5 Refatoração do framework OCEAN .................... .............................................. 47
5.1 JOptionPane ............................................................................................................... 48
5.1.1 JOptionPane para exibição de mensagens ............................................................................... 49
5.1.2 Uso do JOptionPane para solicitar parâmetros ao usuário........................................................ 55
5.2 Recuperação da estrutura de editores ......................................................................... 55
5.3 Outros problemas resolvidos ....................................................................................... 58
5.3.1 Substituição da classe OceanVector .......................................................................................... 58
5.3.2 Eliminação de código morto ....................................................................................................... 60
5.3.3 Reescrita de algoritmos .............................................................................................................. 60
5.3.4 Maven para controle do ciclo de vida ......................................................................................... 61
5.3.5 SLF4J ......................................................................................................................................... 62
6 Conclusão ......................................... .................................................................. 63
6.1 Trabalhos futuros ......................................................................................................... 64
6.2 Considerações finais ................................................................................................... 65
7 Referências bibliográficas ........................ ........................................................ 66
8 Anexos ............................................ .................................................................... 68
8.1 Anexo 1 - Tabela com ocorrências do JOptionPane para exibição de mensagens ..... 68
8.2 Anexo 2 – Tabela com ocorrências do JOptionPane para solicitação de valores ......... 75
8.3 Anexo 3 - Artigo ........................................................................................................... 80
10
1 INTRODUÇÃO
Já no inicio da década de 1980, o software passou a ter um papel importante dentro de
empresas e instituições, passando a ocupar o lugar do hardware, que antes resolvia boa parte
dos problemas(PRESSMAN, 1995). O desenvolvimento de software, que até então ficava em
segundo plano, sem uso de qualquer metodologia, passou a ter a necessidade de aumentar a
produtividade e qualidade de seus processos e projetos.
Neste contexto surgiu a engenharia de software, que aplica disciplinas da engenharia no
desenvolvimento de software, através de métodos, ferramentas e procedimentos que tornam o
processo gerenciável, cumprindo o pressuposto de produtividade e qualidade.
Uma importante característica de qualidade de um software é sua reusabilidade, ou seja,
um software de alta qualidade deve ser projetado e codificado de forma que possa ser
utilizado na construção de outros softwares, reduzindo o tempo e o custo de
desenvolvimento(JOHNSON, 1997).
Para estender a possibilidade de reuso fornecida pelas linguagens estruturadas vieram a
linguagens orientadas objetos e juntamente os frameworks. Um framework é um conjunto de
classes que agregam soluções de projeto para um domínio de problemas. Ele define um
esqueleto para a construção de uma aplicação ou parte de uma, especificando componentes e
maneira como estes interagem(FAYAD e SCHMIDT, 1997).
O OCEAN é um framework criado para dar suporte à criação de ambientes de
desenvolvimento de sistemas baseados em notação de alto nível, com ênfase em notação
gráfica(SILVA, 2000). Foi um dos resultados do desenvolvimento do ambiente SEA, o qual
suporta o desenvolvimento e uso de frameworks, componentes e aplicações.
11
1.1 Motivação
Desde sua primeira implementação, o framework OCEAN passou por diversas alterações,
em grande parte para acrescentar funcionalidades.
Em 2007, uma modificação bastante profunda do framework foi concluída, a migração da
linguagem SmallTalk, com a qual foi originalmente implementado, para Java. Com mudança
de linguagem foram necessárias adaptações no projeto do OCEAN (COELHO, 2007), bem
como a substituição de dependências existentes em SmallTalk por equivalentes em Java,
como o framework de interface gráfica (MACHADO, 2007) e de edição de diagramas
(AMORIM, 2006). Mesmo a versão em Java já recebeu novas funcionalidades, como o
suporte à UML 2(VARGAS, 2008).
Ao longo de tantas alterações, muitos problemas foram se acumulando no código fonte,
alguns inseridos durante as adições de funcionalidades, outros provenientes da migração ou
ainda herdados da implementação inicial.
A escassez de documentação aliada à falta de controle sobre a maneira como as
manutenções foram feitas, são fatores que tornaram propício o surgimento de falhas de
projeto e mesmo de implementação.
Entre as falhas de projeto que dificultam o crescimento e continuidade do framework está
o acoplamento existente entre as classes de modelo e classes de interface gráfica de usuário.
1.2 Tema
Este trabalho pretende a realização de refatorações no código do framework OCEAN, a
fim de reduzir a dependência entre suas classes de modelo e as classes de interface gráfica
com o usuário. O código fonte do framework será melhorado, por conseqüência seu projeto,
de maneira a tornar a divisão de responsabilidades de suas classes mais próxima do proposto
pelo padrão MVC.
Como objetivo, tem-se a revisão do código do OCEAN para a identificação dos pontos de
acoplamento entre as classes de modelo e de interface gráfica do framework e a remoção ou
redução destes acoplamentos através de mudanças no código fonte do framework, feitas com
o uso da técnica de refatoração.
12
Após refatorado, o comportamento do framework deve permanecer inalterado, em
relação às funcionalidades existentes anteriormente. Não há a interesse em qualquer adição ou
alteração de funcionalidade.
Para garantir que as funcionalidades do framework não tenham sido modificadas, as
classes alteradas durante a realização do trabalho serão submetidas a testes de unidade. Estes
testes serão feitos com o uso framework JUnit, por ser fácil de utilizar e ser bastante
difundido entre a comunidade Java. A criação de especificações OO com o ambiente SEA
também será utilizada para avaliar, de maneira superficial, a estabilidade do comportamento
do OCEAN.
1.3 Organização do Texto
Este trabalho é composto por seis capítulos. No segundo capítulo é apresentado o
conceito de framework, suas características e classificações. O terceiro capítulo trata o
framework OCEAN e suas principais características. No quarto capítulo é apresentada a
técnica de refatoração. O quinto capítulo discorre sobre as refatorações efetuadas sobre o
framework OCEAN. As considerações finais são apresentadas no sexto capítulo.
13
2 FRAMEWORKS ORIENTADOS A OBJETOS
O reuso de artefatos de software existentes é uma maneira de se reduzir o custo de
desenvolvimento de software. O tempo gasto com atividades, como projeto, implementação e
teste das funcionalidades fornecidas por um artefato existente, pode ser economizado na
construção de um novo artefato que necessite destas funções(FAYAD e SCHMIDT, 1997).
Ao longo da criação de um novo artefato de software, é possível reusar produtos de
diferentes fases do desenvolvimento de um software existente, indo desde requisitos e casos
de uso, resultantes das fases iniciais do desenvolvimento, até o projeto e o código
implementado.
Antes do advento das linguagens orientadas a objetos, o reuso de software era, em grande
parte, baseado no uso de bibliotecas de rotina, também conhecidas como bibliotecas de
função. Estas bibliotecas continham vários algoritmos implementados, prontos para serem
usados, permitindo apenas o reuso de código. Na programação orientada a objetos ainda
existem as bibliotecas de classes, contendo classes concretas, prontas para serem utilizadas,
até esqueletos de classes, ou classes inacabadas, na forma de classes abstratas.
As linguagens orientadas a objetos propiciam um aumento no reuso do software. Seus
conceitos de classe, polimorfismo, herança e composição, permitem uma implementação mais
extensível e modular, o que facilita a reutilização(JOHNSON e FOOTE, 1988).
Grande parte do reuso de classes está baseado no conceito de herança. Através da herança
as subclasses podem reutilizar métodos já implementados em sua superclasse, estendê-los
para adicionar alguma característica nova, ou sobrescrevê-los para alterar completamente o
comportamento deles(JOHNSON e FOOTE, 1988).
O reuso do protocolo de uma classe é tão importante quanto o reuso da implementação. O
protocolo da classe define o conjunto de mensagens que seus objetos podem interpretar, ou
14
seja, quais métodos esta classe suporta. Quando diferentes classes possuem o mesmo
protocolo, os objetos destas são compatíveis e podem ser usados como se representassem uma
mesma classe.
Uma maneira de representar um protocolo de classe é através de classes abstratas. A
classe abstrata especifica o protocolo de suas subclasses (JOHNSON, 1997). As classes
abstratas não possuem instâncias e por isto são usadas como modelos para suas subclasses.
Em algumas linguagens, como Java, pode-se isolar a definição de um protocolo numa
estrutura chamada interface. A interface é um tipo especial de classe abstrata, que pode conter
apenas métodos abstratos e constantes1. Quando os métodos definidos em uma interface estão
presentes em uma classe, diz-se que a classe implementa tal interface. Na linguagem Java é
permitido que uma mesma classe implemente diversas interfaces diferentes.
A vantagem de se especificar protocolos em estruturas como as interfaces da linguagem
Java em vez de classes abstratas é que referenciar uma interface gera um acoplamento mais
fraco que referenciar uma classe abstrata, pois uma interface pode ser implementada por
qualquer classe, enquanto que a classe abstrata só pode ser redefinida por suas subclasses, ou
seja, referenciar uma classe abstrata significa referenciar uma hierarquia de classes.
Os frameworks utilizam as características da orientação a objetos para promover o reuso
de projeto, além do reuso de código(JOHNSON, 1997). Pode-se definir framework como
sendo um projeto abstrato para um tipo de aplicação particular, ou seja, um domínio de
aplicação. São compostos por uma série de classes, abstratas e concretas, que podem ser
provenientes de uma biblioteca ou serem específicas do framework. Frameworks também
podem ser construídos sobre outros frameworks (JOHNSON e FOOTE, 1988).
A estrutura de um framework é propositalmente inacabada, para permitir sua utilização
em artefatos de software com diferentes funcionalidades. Os frameworks impõem uma
estrutura às suas aplicações, pois especificam a maneira como suas classes interagem, o que
propicia a reutilização do projeto do framework(JOHNSON, 1997). Por conseqüência, as
classes da aplicação que estendem as classes do framework não terão sua execução controlada
pela aplicação e sim pelo framework.
Um bom framework pode reduzir o custo de desenvolvimento em até uma ordem de
magnitude porque permite reutilizar tanto o projeto quanto o código fonte(ROBERTS e
1 Variáveis cujo valor inicialmente atribuído não pode ser mais alterado.
15
JOHNSON). Porém, só é vantajoso desenvolver um framework quando há muitas aplicações
a serem desenvolvidas para um mesmo domínio de problema, situação em o tempo gasto para
o desenvolvimento do framework é compensado pela economia de tempo fornecida pelo seu
reuso.
Idealmente, um framework deveria conter todas as abstrações do domínio tratado para
construção de uma aplicação. Bastaria que o usuário completasse o framework com as
informações específicas de sua aplicação. Não deveria ser necessária a criação de novas
abstrações pelo usuário do framework(JOHNSON, 1997).
Prever todas as abstrações do domínio é, normalmente, inviável. Por isto, framework
tende a cresce à medida que é utilizado. Constroem-se aplicações a partir do framework e
então se avalia que abstrações, comuns a estas aplicações, devem ser transferidas para o
framework. Além disso, apenas o uso do framework poderá ratificar se as abstrações que ele
contém são realmente úteis.
Como exemplo do crescimento de um framework com a experiência obtida das
aplicações pode-se citar o OCEAN. Inicialmente o OCEAN previa basicamente uma estrutura
de classes abstratas, sobre a qual poderiam ser construídos ambientes para desenvolvimento
de software. Ao longo da manutenção do ambiente SEA, feito sobre o OCEAN, várias
funcionalidades do SEA, como o suporte à UML e UML 2, foram incorporadas ao
framework. Estas funcionalidades, apesar de terem sido criadas para o SEA, podem ser usadas
na construção de outros ambientes e, por isto, foram adotadas pelo OCEAN.
2.1 Inversão de Controle
Desenvolvedores estão habituados a reutilizar componentes de uma biblioteca tendo
em mãos a decisão de quando serão chamados dentro dos fluxos de controle do software. Em
softwares que utilizam framework, parte do controle da execução do software fica à cargo do
framework. Após o ponto de extensão da aplicação ser chamado, o framework toma o
controle da aplicação, ditando o que deve ser executado.
16
O framework é responsável por chamar suas extensões e não o contrário. As
subclasses criadas pelo desenvolvedor são chamadas pelo framework. Esta característica dos
frameworks é chamada inversão de controle (IOC), ou Princípio de Hollywood2.
Um exemplo bastante prático de IOC ocorre em softwares que utilizam framework de
interface gráfica baseados no MVC, como o Swing do Java. A partir do momento em que a
janela principal do sistema é exibida, o controle da aplicação passa para o Swing e só retorna
para o código do desenvolvedor quando um evento é disparado por um controlador do
framework. O aperto de um botão da janela, ou um clique do mouse são exemplos destes
eventos.
2.2 Classificação dos frameworks
Dentre outros critérios, os frameworks podem ser classificados de acordo com o seu uso e
seu escopo.
2.2.1 Classificação quando ao uso
A classificação quanto ao uso se importa com a maneira com que a aplicação utiliza o
framework, ou seja, quais as ações necessárias para estendê-lo. Segundo este critério os
frameworks podem ser classificados em:
2.2.1.1 Caixa-branca
Frameworks de caixa branca promovem o reuso através de herança, devendo ser criadas
subclasses das classes abstratas do framework para adicionar comportamento específico da
aplicação(JOHNSON e FOOTE, 1988). Desta forma, todo novo uso do framework exige que
novas subclasses sejam criadas (FAYAD e SCHMIDT, 1997).
O comportamento do framework específico da aplicação é definido através da adição ou
sobrescrita de métodos em subclasses das classes do framework. Assim, usar um framework
de caixa-branca implica em criar inúmeras subclasses (JOHNSON e FOOTE, 1988). A
quantidade de subclasses pode tornar o projeto da aplicação confuso e difícil de ser entendido
por alguém que não esteve envolvido em todo o desenvolvimento da aplicação.
2 Don’t call us, we’ll call you, que em português significa Não nos telefone, nós telefonaremos para você.
17
Utilizar framework de caixa branca torna necessário ter um bom conhecimento sobre a
implementação do framework, pois as subclasses devem atender às exigências de suas
superclasses. Por conta disto, estes frameworks são mais difíceis de aprender e usar.
Quando uma aplicação utiliza um framework de caixa-branca, cuja adaptação é baseada
em herança, esta aplicação passa a estar fortemente acoplada ao framework. Assim a
aplicação fica bastante sensível a mudanças que venham a ocorrer na implementação do
framework. Também a troca do framework usado por outro passa a exigir um esforço tão
grande quando ao número de classes e métodos do framework que foram estendidos pela
aplicação.
Os Servlets da plataforma JEE são exemplo de framework de caixa-branca, estando hoje
na versão 2.5. O framework, ou API Servlet é usando para criar páginas web com conteúdo
dinâmico, usando a linguagem Java. Os Servlets são gerenciados por um componente maior,
chamado Container Web, responsável pela criação e destruição dos servlets e também pela
delegação das requisições HTTP recebidas para os servlets existentes. A Figura 1 apresenta as
principais classes e interfaces do framework Servlet.
Figura 1: Principais classes e interfaces do framework Servlet(LEME, 2004)
Para escrever uma aplicação usando puramente servlets é necessário estender a classe
HttpServlet. O comportamento específico da aplicação é inserido nos métodos doGet e
doPost. Para fazer isto se deve conhecer o modo como os servlets funcionam, por exemplo,
que os resultados dos métodos doGet e doPost devem ser escritos no parâmetro
18
HttpResponse. A Figura 2 mostra o tratamento dado a uma requisição do tipo GET chegada
no Container Web.
Figura 2: Diagrama de seqüência de uma requisição GET
Detalhes da implementação do framework de servlet, como o fato de não serem thred-
safe, se desconsiderados na implementação da aplicação, podem gerar problemas de
concorrência. Por estas características de seu uso, o Servlet pode ser considerado um
framework de caixa-branca.
Atualmente é incomum criar uma aplicação web usando apenas Servlet. Normalmente se
utiliza outros frameworks construídos a partir de servlets, como Java Server Pages (JSP) e
Java Server Faces (JSF), os quais são de uso mais simples por não serem de caixa-branca.
2.2.1.2 Caixa-preta
A tecnologia ideal de reuso provê componentes que podem ser facilmente conectados
para criar um novo sistema (JOHNSON, 1997). Os frameworks de caixa-preta tentam
alcançar este objetivo, fornecendo componentes prontos para serem usados, na forma de
classes concretas. Estes componentes já contêm comportamento específico para aplicações do
domínio do framework.
Para usar o framework, deve-se decidir pelos componentes que serão utilizados e
conhecer apenas a interface externa destes (JOHNSON e FOOTE, 1988). A maneira como o
comportamento é implementado não é interesse da aplicação. A preocupação está em escolher
os componentes que tenham o comportamento adequado às necessidades da aplicação.
19
Os frameworks de caixa-preta baseiam-se na composição e delegação, em lugar da
herança. Através da delegação, um objeto pode repassar a realização de algo para outro
objeto, em lugar de ele próprio fazer. A principal diferença entre a herança e a composição é
que na primeira apenas pode-se delegar coisas para a classe mãe, enquanto que na composição
a delegação pode ser feita para objetos de qualquer outra classe.
Por não terem que sofrer extensão, os frameworks de caixa-preta são mais fáceis de usar,
além de aumentarem a produtividade do desenvolvedor por não necessitarem de extensão.
Porém este benefício é também o motivo deste tipo de framework ser menos flexível, pois a
aplicação só pode usar os componentes prontos presentes no “cardápio” do framework.
2.2.1.3 Caixa-cinza
Os frameworks de caixa-cinza aliam a flexibilidade dos de caixa-branca à facilidade de
uso dos de caixa-preta. Ao mesmo tempo em que fornecem classes concretas, para serem
usadas através de composição, também dispõe classes para serem estendidas.
Grande parte dos frameworks feitos em linguagem Java é caixa-cinza. Isto porque
dificilmente um framework conseguirá atender todas as necessidades de uma aplicação, sendo
mais oportuno permitir que o desenvolvedor estenda o framework, mesmo que isto ocorra em
raras ocasiões.
2.2.2 Classificação quanto ao escopo
O escopo define o domínio de problema a qual o framework se destina, por conseqüência,
as aplicações onde este poderá ser utilizado. Quanto ao escopo os frameworks podem ser
classificados em:
2.2.2.1 Frameworks de infra-estrutura de sistema
São utilizados no desenvolvimento de sistemas de infra-estrutura, como sistemas
operacionais, drivers de dispositivos, bem como no desenvolvimento de frameworks para
interfaces gráficas de usuário e frameworks de comunicação(FAYAD e SCHMIDT, 1997).
Não servem para o desenvolvimento de aplicativos e sim para desenvolver ferramentas que
possibilitem isto.
20
2.2.2.2 Frameworks de integração
Em geral se destinam à integração de aplicações distribuídas e componentes. Facilitam a
modularização, reuso e extensão da infra-estrutura da aplicação destinada ao ambiente
distribuído(FAYAD e SCHMIDT, 1997).
2.2.2.3 Frameworks de aplicação
Encapsulam o conhecimento a respeito de um domínio de particular de problema.
Comparado aos tipos anteriores, são mais caros de se desenvolver, porém propiciam um
maior retorno de investimento por serem utilizados no desenvolvimento de sistema destinados
aos clientes.
2.3 Benefícios do uso de frameworks
O uso de um framework pode trazer diversos benefícios a uma aplicação, suportados
pelas suas características de modularidade, reusabilidade, extensibilidade e robustez.
2.3.1 Modularidade
Os frameworks ocultam da aplicação, detalhes de sua implementação. A aplicação utiliza
apenas a interface pública do framework, que geralmente não sofre grandes alterações. Sendo
assim, mudanças na forma como o framework é implementado não afetam as aplicações que o
utilizam, desde que a interface pública do framework não se altere.
Mesmo que a interface pública do framework seja alterada, tais modificações tendem a
ser retro-compatíveis, ou seja, as aplicações existentes construídas sobre a versão anterior do
framework podem usar a nova versão de maneira transparente, sem terem que sofrer
alterações.
A modularidade dos frameworks ajuda na manutenção e entendimento das aplicações que
o utilizam. Além disso, aumenta a flexibilidade do framework, pois quanto mais modular for
o framework, mais fácil será alterar suas funcionalidades(COELHO, 2007).
2.3.2 Reusabilidade
Frameworks promovem o reuso de código fonte e projeto, definindo componentes
genéricos que podem ser usados na construção de novas aplicações. O reuso promovido pelos
21
frameworks aumentam a produtividade no desenvolvimento de aplicações, pois o esforço
feito para implementar e validar as funcionalidades fornecidas pelo framework é economizado
na construção da aplicação.
O reuso também promove o aumento da qualidade das aplicações, pois as funcionalidades
do framework são postas à prova em cada software que o utiliza. Assim, problemas na
implementação do framework tendem a ser encontrados e resolvidos mais rapidamente, visto
que o número de usuários é maior que o de uma única aplicação.
2.3.3 Extensibilidade
A extensibilidade é a capacidade de o framework aumentar as suas funcionalidades, ou
seja, refere-se à capacidade do framework de se adaptar(COELHO, 2007). Os frameworks
provêm maneiras de a aplicação estender suas funcionalidades, através da extensão de suas
classes.
A extensibilidade fornecida por um framework é fundamental para que possam ser
asseguradas as adaptações de comportamentos genéricos e características de um domínio de
aplicações a uma nova específica aplicação desenvolvida com base no framework(AMORIM,
2006).
2.3.4 Robustez
O código e estrutura do framework são freqüentemente testados, corrigidos e melhorados
ao longo do seu uso na construção de aplicações, tornando o framework bastante confiável.
Com o reuso do framework, a aplicação herda esta robustez. Quanto mais aplicações usam o
framework, mais robusto este tende a ficar, e conseqüentemente as aplicações que o utilizam
também.
2.4 Desvantagens dos frameworks
Os frameworks geralmente são componentes com alto nível de abstração. Apesar de
ser esta característica a fonte das vantagens de se usar um framework, é também a principal
causa da complexidade de se uso e desenvolvimento.
Entender como um framework deve ser utilizado e estendido pode não ser algo trivial,
dependendo do tipo de framework. Se for do tipo caixa-branca é necessário conhecer as
22
classes abstratas para saber como as subclasses devem ser implementadas. Para usar um
framework de caixa-preta o desenvolvedor também precisa aprender a interface dos
componentes que o framework dispõe.
Não existe ainda um padrão estabelecido para documentação de
frameworks(JOHNSON, 1997). Normalmente é utilizada linguagem textual, que nem sempre
é interpretada corretamente por alguém que está estudando o framework. O aprendizado fica
muito baseado no uso do framework e nas de tentativas e erros do desenvolvedor.
A inversão de controle muitas vezes atrapalha a depuração da aplicação que usa
framework, principalmente quando não se tem acesso ao código fonte do framework, pois o
depurador não poderá exibir as linhas de código que estão em execução. Descobrir se um erro
identificado está presente no código da aplicação ou do framework se torna difícil nestas
ocasiões.
Usar diferentes frameworks numa mesma aplicação, o que é bastante comum,
geralmente é algo complicado. Os frameworks são desenvolvidos com foco na extensibilidade
e não na integração com outros frameworks. Assim, os mecanismos de integração ficam a
cargo do desenvolvedor da aplicação.
O desenvolvimento de um framework é também uma tarefa dispendiosa. Analisar o
domínio alvo e criar as abstrações de modo a atender adequadamente as aplicações não é
tarefa simples. É preciso conhecer profundamente o domínio ao qual o framework irá se
destinar, analisar uma série de aplicações e ter experiência em projeto e implementação de
software.
O framework tende a melhorar à medida que a quantidade de aplicações suportadas
cresce, porém este crescimento passa a ser um problema para a manutenção do framework. As
alterações no framework devem afetar ao mínimo, ou em nada, as aplicações que o utilizam.
Por isto, cada decisão nas mudanças do projeto e principalmente da interface pública do
framework deve ser muito bem analisada, para que não prejudique as aplicações existentes.
23
3 O FRAMEWORK OCEAN
O OCEAN é um framework, criado para dar suporte à criação de ambientes de
desenvolvimento de sistemas baseados em notação de alto nível, com ênfase em notação
gráfica. Surgiu como um dos resultados do desenvolvimento do SEA, um ambiente que
suporta o desenvolvimento e uso de frameworks, componentes e aplicações. Estes dois
artefatos foram concebidos e implementados por Ricardo Pereira e Silva em sua tese de
doutorado, no ano de 2000, utilizando a linguagem SmallTalk (SILVA, 2000).
A principal motivação para a criação do OCEAN foi a necessidade de produzir um
ambiente flexível para o desenvolvimento e uso de frameworks e componentes(SILVA,
2000), que se moldasse às necessidades constatadas durante seu uso. Tendo a flexibilidade
como requisito fundamental, a decisão foi desenvolver um framework para a construção de
ambientes, em lugar de um ambiente diretamente, ou seja, primeiro desenvolver o OCEAN e
então, usando este como base, desenvolver o SEA.
O SEA é um ambiente de desenvolvimento que suporta a construção de frameworks,
componentes e aplicações como estruturas baseadas no paradigma de orientação a objetos
(Silva, 2000). Possibilita que estes artefatos sejam construídos como arquitetura de
componentes, bem como a partir da extensão da estrutura de frameworks. Foi desenvolvido
como uma extensão do framework OCEAN e se destina à criação e uso de artefatos de
software reutilizáveis.
A análise feita para a criação do OCEAN envolveu uma comparação dos ambientes
existentes com os requisitos necessários para o suporte ao desenvolvimento e uso de
frameworks e componentes. Como conseqüência, o OCEAN suporta o desenvolvimento de
ambientes em geral, não se limitando a ambientes relacionados a frameworks e
componentes(SILVA, 2000).
24
Tanto o ambiente SEA quanto com o OCEAN, passaram por uma migração para a
linguagem Java, feita por João Amorim (Amorim, 2006), Ademir Coelho (Coelho, 2007) e
Thiago Machado (Machado, 2007). O SEA foi utilizado para validar o resultado da
recodificação (Coelho, 2007) do OCEAN. Posteriormente, o SEA também teve acrescentada a
possibilidade de representar especificações usando diagramas da UML 2 (Vargas, 2008).
3.1 Estrutura
Ambientes desenvolvidos sob o framework OCEAN podem manipular diferentes formas
de especificação de projetos. As principais características de um ambiente criado a partir do
framework OCEAN são definidas a partir de uma subclasse concreta de
EnvironmentManager. Nesta subclasse são definidos os tipos de especificação tratados, os
mecanismos de visualização e edição associados a cada modelo e ambiente, os mecanismos
de armazenamento utilizados e as ferramentas utilizáveis para manipular especificações
(Machado, 2007).
Cada tipo de especificação no framework OCEAN (subclasse de Specification) define
quais os modelos (subclasse de ConceptualModel) e conceitos (subclasse de Concept) válidos
para aquela especificação, e cada modelo define quais os conceitos que pode tratar (Coelho,
2007).
Um tipo de conceito é definido como uma estrutura de informações, que podem
corresponder a referências a outros conceitos ou informações exclusivas do conceito tratado.
A classe da orientação de objetos é um exemplo de conceito, que tem como informações os
seus métodos e atributos. Por sua vez, método e atributo também são conceitos.
Os modelos contém um conjunto de conceitos e os relacionamentos entre eles. São os
tipos de relacionamentos e conceitos aceitos que definem a estrutura de um tipo de modelo.
Cada subclasse de ConceptualModel define um tipo de modelo. Por exemplo, para uma
especificação OO, cada diagrama da UML é um tipo de modelo diferente, ou seja, para cada
diagrama há uma subclasse de ConceptualModel que a representa.
Os conceitos de uma especificação são armazenados num repositório de conceitos
(ConceptRepository). Quando um elemento da especificação necessita referenciar um
conceito, busca este no repositório, permitindo que um único conceito seja referenciado por
diferentes modelos da especificação e evitando a duplicação de conceitos. Se um conceito tem
25
suas propriedades alteradas em um modelo da especificação, esta alteração se reflete em todos
os demais modelos e conceitos que o referenciam.
3.2 Relacionamentos entre elementos de especificaçã o
Uma mesma especificação pode conter vários modelos e pode estabelecer
relacionamentos entre estes, na forma de links, associações de sustentação ou associações de
referência.
• Link: é um tipo de conceito (subclasse de Concept), que pode ser associado a
qualquer elemento de especificação, ou seja, qualquer instância de uma subclasse de
SpecificationElement. Os links têm como finalidades possibilitar a criação de caminhos de
navegação e estabelecer ligações semânticas (links semânticos) entre os elementos de uma
mesma especificação, ou de especificações distintas. A definição de todos os pares de
elementos que devem ser relacionados é parte da estrutura de uma especificação (Silva, 2000).
Os links de navegação permitem que os elementos de especificação apontem para outros
elementos, dando à especificação características de hiperdocumento.
• Associação de sustentação: define uma relação de dependência entre dois elementos
de uma especificação, um realizando função de sustentador e outro de sustentado. O elemento
sustentado tem sua existência dependente da existência do elemento sustentador, ou seja, o
elemento sustentado não pode permanecer na especificação caso o seu sustentador seja
removido. Uma vantagem deste tipo de associação é que diminui o acoplamento entre os
diferentes tipos de elemento da especificação.
• Associação de referência: estabelece que parte da definição de um elemento da
especificação, o referenciador, depende da referência a outro elemento, o referenciado. Para
que o referenciador se torne completo, o referenciado deve existir na especificação. Quando o
elemento referenciado é removido da especificação, o referenciador não é excluído, mas fica
incompleto.
As associações de sustentação e referência entre elementos de uma mesma especificação
são registradas através de tabelas (instâncias de TabelaDeTuplas), uma para cada tipo de
associação.
26
A interligação de elementos de especificação, fornecidas pelo framework OCEAN, na
forma de links, sustentações e referências, permite estabelecer relacionamentos e restrições
entre os diagramas de uma especificação.
Os links semânticos são usados para definir a estrutura de refinamento das especificações
OO, por exemplo, para definir que um caso de uso é refinado através de um diagrama de
atividades, ou que um diagrama de transição de estados só pode existir se a classe por ele
modelada estiver presente em um diagrama de classes. Alguns links são criados
automaticamente pelo ambiente, como o existente entre um método e o digrama de corpo de
método que descreve seu algoritmo. Ainda é possível criar manualmente links de navegação
entre os diagramas de uma especificação.
As associações de sustentação são utilizadas para manter a consistência da especificação.
Exemplo disto é a sustentação existente entre classe (instâncias de Classe) e seus métodos
(instâncias de Metodo) e atributos (instâncias de Atributo), sendo os métodos e atributos
sustentados pela classe à qual pertencem. Assim quando uma classe é removida da
especificação, sendo métodos e atributos também são. Por sua vez, se algum método da classe
possui algum diagrama de corpo de método definindo seu algoritmo, este diagrama também é
removido, pois métodos são sustentadores de diagramas de corpo de método.
As restrições impostas por meio de links, sustentações e referências, permitem a
validação da consistência da especificação, evitando erros humanos durante sua criação, por
exemplo, definir uma mensagem em um diagrama de seqüência que não representa um
método de nenhuma das classes presentes na especificação. Desta maneira, pode-se garantir
que uma especificação não fique incompleta ou com resíduos de exclusões, o é um diferencial
em relação a outros ambientes de desenvolvimento(SILVA, 2000).
3.3 Reusabilidade do framework OCEAN
O OCEAN é um framework de caixa cinza, pois dispõe funcionalidades através de classes
concretas e permite que novas funcionalidades sejam acrescentadas através da criação de
novas subclasses (Coelho, 2007). Nos ambientes produzidos a partir do OCEAN o reuso de
funcionalidades do framework podem ser realizados das diferentes maneiras.
Algumas funcionalidades gerais estão completamente implementadas no framework e
podem ser diretamente usadas na construção de diferentes ambientes, servindo como exemplo
27
a funcionalidade de navegação. Outras estão parcialmente implementadas, devendo ser
estendidas pelos ambientes construídos às partir do OCEAN.
Os editores de modelo dos ambientes construídos sob o OCEAN utilizam as
funcionalidades de edição supridas pelo framework para manipular os conceitos de modelos
de uma especificação.
A maneira mais flexível de estender o OCEAN é através de ferramentas, pois a inclusão
de uma nova ferramenta em um ambiente pode ser feita de maneira isolada, sem a
necessidade de alterar a estrutura do ambiente.
As ferramentas podem ser de edição, quando têm a finalidade de alterar uma
especificação; de análise, destinadas a analisar as características de uma especificação e gerar
relatórios com os resultados; ou de transformação, provendo a exportação de elementos de
especificação para fora do ambiente, bem como importar elementos externos para dentro de
uma especificação.
3.4 Funcionalidades supridas pelo OCEAN
Sendo um framework de caixa-cinza, o OCEAN oferece várias funcionalidades prontas
para serem utilizadas em novas aplicações. Boa parte destas funcionalidades provém da
evolução do ambiente SEA. Toda funcionalidade criada para o SEA é incorporada no
OCEAN depois de concluída.
Assim, funcionalidades citadas em trabalhos anteriores para o ambiente SEA são exibidas
aqui como pertencentes ao OCEAN. Tais funcionalidades se encontram prontas para uso na
criação de novos ambientes a partir do OCEAN.
3.4.1 Especificações
Atualmente o framework OCEAN suporta a criação de especificações orientada a
objetos. Este tipo de especificação é usado na definição de frameworks, aplicações,
componente ou componente flexível. Representa uma especificação baseada no paradigma de
orientação a objetos, produzida a partir do uso de notação de alto nível, no caso UML
(Vargas, 2008) ou UML versão 2.
28
Em sua versão original, o OCEAN também suportava outros dois tipos de especificação,
a de interface de componente e de cookbook ativo. Porém estas especificações não foram
migradas para a linguagem Java.
3.4.2 Diagramas UML
O desenvolvimento de frameworks, componentes e aplicações, disponível de maneira
concreta no framework OCEAN, é feito através da construção da especificação de projeto
destes artefatos, usando UML. A notação presente não é puramente UML, mas uma versão
estendida para suportar as necessidades de representação de um framework.
A UML não suporta a representação dos pontos flexíveis de um framework, ou seja,
partes da estrutura que podem ser estendidas ou alteradas. Além disso, não é possível
representar a ligação semântica entre especificações distintas (SILVA, 2000), ou seja, não há
como vincular a especificação de um artefato ao framework que o originou, usando UML. A
ausência de técnicas que atendesse os requisitos de modelagem de frameworks foi um dos
elementos de motivação para a criação do ambiente SEA (Silva, 2000).
Atualmente o framework OCEAN permite a criação de especificações usando UML
versão 1 ou 2. Primeiramente era suportada apenas notação UML, e ainda de maneira parcial.
Porém, em 2008, Thânia Vargas (Vargas, 2008) acrescentou os diagramas de UML 2 e alguns
já presentes na versão 1 da UML, mas que não haviam sido implementados.
Os diagramas de UML, bem como a sua forma de uso, suportados pelo framework
OCEAN são:
• Diagrama de casos de uso, usado para informar as funcionalidades que devem estar
presentes no sistema.
• Diagrama de atividades, usado para especificar as transições entre os casos de uso,
servindo como complemento ao diagrama de uso. Cada caso de uso representa uma atividade
do diagrama. Um dos casos de uso deve ser definido como inicial e a partir deste deve ser
possível chegar a todos os demais casos de uso.
• Diagrama de transição de estados, usado para representar as mudanças de estado de
uma classe. Cada estado do diagrama contém os atributos da classe e sues respectivos
valores. Um método da classe é representado como uma transição do diagrama.
29
• Diagrama de seqüência, usado para moldar execução de um caso de uso ou refinar
outro diagrama de seqüência. É composto por mensagens e elementos que trocam mensagens
(Silva, 2000). As mensagens são enviadas para um objeto, que representa uma instância de
uma das classes da especificação. Uma mensagem pode ser enviada por um objeto, um ator
do diagrama de casos de uso ou pode ser uma mensagem originadora. Uma mensagem
originadora é proveniente de outro diagrama de seqüência da especificação.
• Diagrama de objetos, usado para descrever um conjunto de objetos e seus
relacionamentos em um instante do tempo (Vargas, 2008). É semelhante a digrama de
classes, mas em vez de classes são representadas instâncias de classes ligadas entre si.
• Diagrama de pacotes, usado para modelar a estrutura do sistema, dividindo o modelo
em divisões lógicas interligadas.
• Diagrama de estrutura composta, usado para definir a estrutura interna de elementos
como classe, pacotes e componentes.
• Diagrama de componentes, usado para descrever as associações entre componente e
os artefatos que compõe cada componente.
• Diagrama de utilização ou implantação, usado para determinar a organização de um
conjunto de elementos necessários para a execução de um sistema.
• Diagrama de comunicação, usado para definir uma interação entre um conjunto
objetos. Serve como alternativa ao diagrama de seqüência.
• Diagrama de temporização, usado na modelagem de restrições de tempo do sistema.
• Diagrama de visão geral de interação, usado como alternativa ao diagrama de
atividades.
• Diagrama de estrutura composta, usado para descrever a estrutura interna de
elementos de modelagem estrutural, como classes, pacotes e componentes(VARGAS, 2008).
Além dos diagramas da UML, o SEA suporta diagramas de corpo de método, onde se
descreve o algoritmo de um método. Este diagrama pode referenciar diagramas de seqüência e
transições de estado, para indicar o que o algoritmo está sendo definido.
30
3.4.3 Explicitação da flexibilidade de um framework
A flexibilidade de um framework se apresenta nas classes que podem ou devem ser
redefinidas pela criação de subclasses e nos métodos que devem ser sobrepostos (Silva,
2000). Para poder representar os pontos flexíveis de um framework, o OCEAN define
propriedades de redefinibilidade e essencialidade de uma classe.
A redefinibilidade estabelece se uma classe pode ou não ser estendida em um artefato
construído a partir de um framework. Uma classe redefinível pode ter subclasses em um
artefato que usa o framework. Já a propriedade de essencialidade define que uma classe do
framework deve ser obrigatoriamente estendida em todo artefato construído sob este
framework. Somente classes redefiníveis podem ser essenciais.
As classes também podem ser classificadas como abstratas ou concretas. As classes
abstratas de um framework devem ser estendidas nos artefatos gerados a partir de um
framework, enquanto que a extensão das classes concretas é opcional, já que elas contêm
implementações completas.
Além disso, é possível indicar se um método é classificado como base, template ou
abstrato. Métodos base não precisam ser modificados, apesar de ser possível sobrepô-los;
métodos template fornecem uma estrutura de algoritmo definida, mas permitem que os
métodos que chamam (hooks) sejam estendidos; métodos abstratos devem, obrigatoriamente,
ser definidos nos artefatos que utilizam o framework.
As propriedades de flexibilidade descritas acima são representadas de forma gráfica nos
diagramas do framework OCEAN. A notação UML presente no ambiente foi sobrecarregada
para suportar a exibição destas propriedades em alguns diagramas, como o de classes e o de
seqüencia. No diagrama de classes, por exemplo, uma classe redefinível recebe uma letra R
logo abaixo de seu nome, na figura que a representa.
3.4.4 Navegação
O mecanismo de memorização dos documentos visualizados é implementado na classe
Path(COELHO, 2007). Este mecanismo era especialmente útil na versão SmallTalk do
OCEAN, onde não era possível ter mais que um editor de modelo aberto ao mesmo tempo e o
usuário tinha que usar botões de navegação para alternar entre as janelas. Na versão Java do
31
OCEAN esta funcionalidade se tornou obsoleta, pois várias janelas de edição podem ser
abertas ao mesmo tempo.
3.4.5 Armazenamento
A classe StorageManager define um protocolo de armazenamento e recuperação de
especificações, possibilitando que as especificações do OCEAN sejam armazenadas em
diferentes mecanismos de persistência, como banco de dados ou arquivo. A estrutura de
armazenamento do OCEAN foi projetada para os ambientes possam adicionar diferentes
meios de armazenamento de maneira transparente para as demais classes do
framework(SILVA, 2000).
Um problema que ocorria na versão SmallTalk do framework é que o ambiente só podia
usar uma única forma de armazenamento. Por exemplo, não seria possível carregar uma
especificação de um arquivo e salvá-la em um banco de dados. Só era possível carregar e
salvar especificações armazenadas em um mesmo formato(COELHO, 2007).
Uma das melhorias feitas na migração do OCEAN foi a extensão do mecanismo de
persistência para suportar mais do que um formato de armazenamento ao mesmo tempo.
Também foram criados dois mecanismos de armazenamento, uma para o armazenamento em
arquivo usando a serialização de objetos Java e outra para armazenamento em arquivo
XML(COELHO, 2007).
3.5 Migração para Java
A versão original do framework OCEAN, criada em 2000 por Ricardo Pereira e Silva, foi
desenvolvida na linguagem SmallTalk, utilizando o ambiente VisualWorks versão 2. Além de
ser uma versão antiga, lançada em 1994 (Amorim, 2006), o fato de esta linguagem ser de
pouca utilização nos dias atuais, bem como o uso do framework ser dependente do ambiente
de desenvolvimento, entre outros, dificultavam as extensões e manutenções do OCEAN. Tais
problemas fizeram com que fosse tomada a decisão de migrar o framework para outra
linguagem de programação.
Pensando em facilitar a extensão e manutenção do framework, foi escolhida a
linguagem Java, por ser mais atual e difundida. Além disso, possui um bom suporte em
ambientes de desenvolvimento de código aberto, como o Netbeans e o Eclipse JDT, o que
facilita seu uso no ambiente acadêmico(COELHO, 2007).
32
A migração de SmallTalk para Java não foi simplesmente uma conversão de código
fonte. Várias adaptações no projeto original do OCEAN tiveram de ser feitas, por conta das
diferenças entre as duas linguagens.
Um primeiro problema relatado no trabalho de Ademir Coelho (COELHO, 2007) diz
respeito à diferença existente nas coleções. O índice das coleções em SmallTalk começa em 1,
enquanto que em Java começam em 0. Alterar todos os algoritmos do framework para acessar
as coleções com o padrão da linguagem Java geraria um impacto muito grande no framework
e com isso a possibilidade de introduzir erros. Assim, a solução encontrada foi criar um
decorator para a classe Vector, a classe OceanVector. Esta classe agrega um Vector e possui
os mesmos métodos de Vector, mas que adapta os índices recebidos no padrão SmallTalk
para o padrão Java, antes de repassá-lo à classe Vector.
Outra grande diferença entre Java e SmallTalk é que em Java as variáveis são tipadas,
enquanto que em SmallTalk não. Assim ao converter os métodos de classe para Java foi
necessário decidir qual tipo seria usado em cada argumento(COELHO, 2007).
Alguns métodos em SmallTalk recebiam como parâmetro objetos de classes pertencentes
a hierarquias de classes distintas, ou seja, que não tinham nenhuma superclasse comum além
da classe Object. Usar a classe Object para tipar os argumentos faria com que os métodos
pudessem receber objetos de classes indesejadas como parâmetro, a verificação de tipo teria
que ficar dentro do método e problemas como passagem de parâmetro de tipo incorreto, que
poderiam ser verificados em tempo de compilação passariam a gerar erros em tempo de
execução(COELHO, 2007). O mesmo problema foi verificado para os métodos que recebiam
instâncias de Concept como argumento, sendo que nem toda subclasse de Concept era valida
como entrada.
Muitos métodos do OCEAN recebiam objetos das classes OceanDocument e
SpecificationElementHolder, mas estas classes não possuíam uma superclasse em comum
além da classe Object. Assim, a classe SpecificationElementHolder passou a ser subclasse de
OceanDocument e, para conter os métodos incomuns entre esta duas classes, foi criada a
classe SpecificationDocument(COELHO, 2007). A Figura 3 mostra como ficou a estrutura
básica do framework OCEAN após a migração para Java.
33
Figura 3: Estrutura básica do OCEAN em Java
No trabalho realizado por Thiago Spina(MACHADO, 2007), a classe
EnvironmentManager foi refatorada para aplicação do padrão MVC. Esta classe passou a ter
apenas características de model. As responsabilidades de view e controller foram
transportadas para uma nova classe, EnvironmentManagerView(MACHADO, 2007). A
mudança aumentou a possibilidade de extensão do framework OCEAN. Pode-se ou criar um
novo modelo de aplicação, através da criação de uma subclasse de EnvironmentManager,
reaproveitando a view existente; ou criar apenas uma nova view, subclasse de
EnviromentManagerView, e reutilizar um model existente; ou ainda criar um novo model e
uma nova view(MACHADO, 2007).
Com a refatoração de EnvironmentManager, todas as classes criadas para o novo
ambiente podem ser utilizadas na construção de novos ambientes(MACHADO, 2007). Na
versão original do OCEAN as subclasses de EnvironmentManager eram específicas de um
ambiente, ou seja, a subclasse de um ambiente não poderia ser reutilizada para a construção
de outro. A Figura 4 mostra o resultado da refatoração de EnvironmentManager, presente na
versão Java do OCEAN.
Figura 4: Classes de ambiente do OCEAN em Java
Ainda como parte da migração foi necessário escolher um novo framework para a edição
gráfica dos elementos de uma especificação, substituindo para o framework HotDraw da
versão SmallTalk. O framework escolhido foi o JHotDraw, uma versão do HotDraw para
34
linguagem Java. Esta escolha foi feita com o intuito de que as alterações no OCEAN fossem
às menores possíveis para viabilizar a mudança de um framework para o outro. Como o
JHotDraw advém do HotDraw, muitas das idéias do framework antecessor se mantiveram na
nova versão(AMORIM, 2006).
O framework OCEAN, bem como o ambiente SEA, não foram migrados para Java
totalmente. Alguns tipos de especificação como Cookbook ativo e interface de componentes,
bem como várias ferramentas, existentes na versão SmallTalk, não foram
convertidas(COELHO, 2007). Algumas ferramentas, mesmo tendo seu código convertido,
não foram validadas.
Mesmo não sendo completa, a migração do OCEAN e do SEA permitiu obter um
protótipo de ambiente de desenvolvimento, em linguagem Java, sendo possível especificar
sofwares orientados a objetos com o uso desta ferramenta.(COELHO, 2007)
35
4 REFATORAÇÃO
A refatoração é uma prática comum em metodologias de desenvolvimento ágil de
software, como o Extreme Programming (XP). As técnicas de refatoração têm sido
intensamente utilizadas para melhorar projetos já codificados, tornando-os mais fáceis de
entender, alterar e estender.
Refatoração é um conjunto de alterações do código fonte de um software buscando
melhorar sua estrutura sem adicionar novas funcionalidades. Segundo Fowler(FOWLER,
2004), refatoração é “uma alteração feita na estrutura interna do software para torná-lo mais
fácil de ser entendido e menos custoso de ser modificado sem alterar seu comportamento
observável”. Refatorar é realizar tais alterações no código.
Normalmente, a concepção que se têm do processo de criação de um software é que
primeiramente deve-se fazer um projeto perfeito e então codificá-lo. Porém, é um equivoco
pensar que o projeto continuará sendo bom ao longo de toda vida do software.
Por melhor que seja o projeto, as seqüentes manutenções feitas no código original, para
adição e alteração de funcionalidades, acabam reduzindo a qualidade do código implementado
e distanciando-o do projeto original. Esta deterioração do código é ainda mais evidente
quando o projeto do software não é bom ou simplesmente inexiste. Usando refatoração é
possível fazer alterações no código de maneira que este permaneça bom ou até
melhore(FOWLER, 2004).
No desenvolvimento de frameworks a refatoração é essencial. Frameworks tendem a
evoluir conforme são utilizados, absorvendo novas características do domínio que tratam e
tendo suas funcionalidades readequadas. Portanto, a tendência é que, ao longo de sua vida, o
código do framework seja modificado muitas vezes. Para que o framework mantenha-se
36
legível e fácil de ser alterado, é necessário fazer refatorações à medida que estas mudanças
ocorrem.
4.1 O processo de refatoração
A proposta da refatoração é que as alterações de código sejam feitas em pequenos
passos e de maneira disciplinada, para diminuir as chances de falha e para que mesmo as que
surgirem sejam fáceis de identificar(FOWLER, 2004). Se feito de maneira desordenada a
refatoração pode gerar erros difíceis de identificar e invalidar o código.
A aplicação de refatoração envolve duas atividades diferentes: acrescentar
funcionalidades e refatorar(FOWLER, 2004). O acréscimo de funcionalidades não altera o
código existente, apenas adiciona capacidades. Nesta fase também são criados os testes para
testar novas funcionalidades. Já durante a refatoração apenas se reestrutura o código, sem
adicionar características novas. Também não são criados novos testes durante esta atividade,
no máximo pode haver modificações nos testes, por conseqüência da mudança de alguma
interface de classe.
Desta forma, a mecânica da refatoração pode ser definida em passos como os
seguintes:
1. Criar um conjunto de testes para o trecho de código a ser refatorado. Os testes são
essenciais para evitar falhas originadas nas alterações. Os resultados dos testes devem ser
bastante legíveis, ou seja, serem claros e diretos. Neste passo, os frameworks de testes de
unidade, como o JUnit, são de grande ajuda, pois fornecem uma estrutura base para a criação
dos testes.
2. Identificar os pontos a serem alterados e as refatorações necessárias.
3. Refatorar, isto é, executar as refatorações. É importante lembrar que as alterações
devem ser feitas em pequenos passos. Neste momento também devem ser feitas as alterações
nos testes caso haja necessidade, por exemplo, quando se alterou a interface de alguma classe.
4. Testar o código alterado, para verificar se o seu comportamento continua como era
antes das alterações. Novamente os frameworks de testes unitários servem de auxílio, ao
permitirem a execução automática dos testes criados sobre eles, além de fornecerem relatórios
com os resultados da execução.
37
5. Efetuar as correções necessárias, ou reverter as refatorações feitas, caso o código não
tenha passado em todos os testes. Como cada alteração ser pequena, os erros podem ser
encontrados e corrigidos facilmente.
6. Retornar ao passo dois até que não haja mais refatorações a serem feitas.
Um ponto importante é a definição de quando as refatorações devem ser feitas, dentro
do processo de desenvolvimento do software. Alocar horas para fazer refatoração parece ser
uma solução óbvia, mas não é recomendável. A refatoração não deve ser uma atividade dentro
de um planejamento e sim uma parte, ou conseqüência, de uma atividade onde refatorar é útil
(FOWLER, 2004). Esta separação de horas só faz sentido quando se tem um débito de
projeto, ou seja, uma refatoração que foi previamente identificada como necessária, mas que
teve de ser adiada por falta de tempo, ficando como uma atividade do projeto a ser feita mais
adiante.
Há uma diretriz criada por Don Roberts que define o momento para a refatoração da
seguinte maneira:
Na primeira vez em que você faz algo, você apenas faz. Na segunda vez em que faz algo parecido, você estremece diante da duplicação, mas faz de qualquer forma. Na terceira vez em que faz algo parecido, você refatora.(FOWLER, 2004)
Sendo assim, não existe um tempo certo dentro do desenvolvimento do software em
que a refatoração deve ser aplicada, mas algumas situações em que refatorar é mais propício,
como:
• Durante a adição de funcionalidade, quando o projeto não facilita esta adição ou
para auxiliar no entendimento do código que se deve alterar.
• Durante a correção de falha, para tornar o código mais claro e compreensível. Pode-
se entender a causa de um defeito como sendo o fato de o código não estar claro o suficiente
para que quem o desenvolveu pudesse perceber as falhas que gerou.
• Durante a revisão de código, para incluir sugestões dos revisores.
4.2 Maus cheiros
A identificação dos locais do código onde existe a necessidade de refatoração é algo
importante. Esta tarefa exige que o desenvolvedor conheça problemas tipicamente presentes
em um código ruim e tenha a experiência para identificá-los. Estes problemas comuns de
38
projetos foram batizados por Kent Back como maus cheiros3(FOWLER, 2004), sendo alguns
de seus exemplos:
4.2.1 Código duplicado
Este pode ser considerado o problema mais grave, em que a refatoração certamente é
necessária(FOWLER, 2004). Quando um dos locais é alterado, certamente a alteração terá
que ser feita na mesma maneira nos outros locais onde o código é repetido. Se ocorre um
esquecimento e algum dos locais com código copiado não é mudado, surge um defeito no
software. Para evitar este tipo de problema, o que deve ser feito é refatorar de maneira
unificar o código replicado.
4.2.2 Método longo
Quanto maior é um procedimento, mais difícil é entendê-lo. Métodos pequenos e com
boa nomeação são mais fáceis de entender, manter e reusar. Assim, os métodos grandes
devem ser decompostos em métodos menores. Os comentários dentro de métodos são uma
boa identificação de um método que deve ser decomposto, pois um bloco de código com
comentário explicando o que ele faz muitas vezes pode ser substitído por um método, com
nome baseado no comentário.
4.2.3 Classe grande
Classes com muitas variáveis de instância ou muitos métodos públicos, geralmente fazem
coisas em excesso e devem ser quebradas em classes menores.
4.2.4 Lista de parâmetros longa
Uma lista de parâmetros muito longa é difícil de entender. Não é necessário passar para
um método todos os elementos que ele precisa, mas o que ele precisa para chegar no que
necessita. Quando é inevitável reduzir a quantidade de parâmetros, estes podem ser agrupados
em um objeto parâmetro.
3 O termo em inglês é bad smells.
39
4.2.5 Alteração divergente
O código deve ser estruturado para receber mudanças facilmente. As alterações no código
devem ser pontuais. Quando uma classe é alterada de diferentes maneiras, por diferentes
razões, é melhor dividir a classe em duas ou mais, onde cada uma deve estar associada à um
único tipo de mudança.
4.2.6 Cirurgia com rifle
Quando mudanças envolvem alterações pequenas em diversos locais diferentes é fácil
deixar de fazer alguma alteração importante. Talvez os locais afetados possam ser unificados
em uma classe.
4.3 Catálogos de refatorações
A primeira obra a reunir uma série de técnicas de refatoração e reuni-las em um catálogo
com explicações e exemplos práticos foi o livro de Martin Fowler, Refactoring(FOWLER,
2004), que é tido até então como uma “bíblia” sobre o assunto. O objetivo do catálogo é
mostrar como executar refatoração de maneira controlada e eficiente, de modo que não
introduza erros no código, melhorando de maneira metódica a estrutura.
Em seu livro, Fowler dá a descrição de cada refatoração formatada nas seguintes partes:
• Nome da refatoração, importante para a construção do vocabulário de
refatorações.
• Resumo da situação em que deve ser aplicada a refatoração e do que esta faz.
• Motivação para a aplicação da refatoração e as circunstâncias em que a
refatoração não deve ser feita.
• Mecânica da refatoração, descrevendo pequenos passos para a execução da
refatoração.
• Exemplos do uso da refatoração para ilustrar como esta técnica funciona. Os
exemplos são bastante simples, com fim didático apenas. Os exemplos são
escritos em Java.
O catálogo contém 71 refatorações, desde as mais simples, como Substituir Números
Mágicos por Constantes Simbólicas, mais pontuais e envolvendo poucos passos, até
refatorações mais complexas, envolvendo vários passos, como Substituir Herança por
40
Delegação. As refatorações presentes no catálogo de Fowler são chamadas de refatorações de
baixo nível.
Em 2005, Joshua Kerievsky lançou um novo catálogo de refatoração, no livro
Refactoring to Patterns (KERIEVSKY, 2005). Kerievsky complementou o catálogo criado
por Fowler com refatorações direcionadas a aplicação de padrões de projetos.
Com o uso das refatorações de baixo nível, as refatorações para padrões buscam unir a
melhoria de projeto de código existente, proporcionada pelo uso de refatoração, com padrões
de projeto, soluções para problemas recorrentes de projeto.
O catálogo de Kerievsky apresenta 27 refatorações, num formato parecido com o usado
por Fowler. Cada refatoração apresenta um nome, resumo, motivação, mecânica, exemplo e
variações. No catálogo de Fowler não há uma seção exclusiva para variações, estando
presentes logo após os exemplos de uma refatoração.
4.4 Ferramentas de auxílio à refatoração
4.4.1 Verificadores estáticos
Parte das atividades que garantem a qualidade de um software são classificadas em
dois grupos: verificação e validação. A verificação refere-se ao conjunto de atividades que
garante que o software implemente corretamente uma função específica, enquanto que a
validação remete à outras atividades que garantem que o software realiza o que o usuário
espera(PRESSMAN, 1995).
A análise estática é uma técnica de verificação de software na qual se busca detectar
problemas com base em representações do software, tais como documentos de requisitos,
diagramas de projeto e código fonte. Os analisadores ou verificadores estáticos são
ferramentas que executam análise estática sobre o código fonte ou código objeto, como o
bytecode da linguagem Java. Após a análise, os resultados destas ferramentas passam por uma
avaliação humana.
Os verificadores estáticos buscam por problemas no código, como variáveis não
utilizadas, variáveis que nunca recebem um valor ou métodos que não são chamados em
nenhum local do sistema. Normalmente estes problemas são erros de programação, que
possivelmente só seriam percebidos na execução da aplicação. Alguns dos problemas
41
indicados pelo analisador podem não ser reais e por isto é importante que se avalie os
resultados da análise antes de alterar o código.
Em relação à refatoração, as ferramentas de verificação são úteis no sentido de apontar
locais onde pode ser necessário fazer refatorações. Além disso, algumas ainda sugerem
soluções para os problemas, dando subsídios para a atividade de refatoração.
Dentre os verificadores disponíveis para a linguagem Java está o FindBugs (FindBugs
Homepage), que busca possíveis erros de programação com base em uma lista de padrões de
erro. O programa varre o bytecode em busca de locais onde estes padrões se apresentam. Os
erros encontrados são classificados de acordo com o modo como afetam o projeto, em Má
Prática, Erro, Vulnerabilidade à Código Malicioso, Erro em Concorrência, Desempenho,
Segurança e Espertalhão. Ainda existem subcategorias, ditas tipos de defeito, que dão uma
visão geral do defeito ou indicam no que este pode acarretar.
O PMD (PMD Homepage) é outro detector de defeitos potenciais e funciona de maneira
semelhante ao Findbugs. Busca por erros de programação, código morto, código não
otimizado, expressões com complexidade excessiva e duplicações.
Ainda existem analisadores que se preocupam em encontrar inconsistências no estilo de
programação, com base em regras de estilo. Regras de estilo como "identar implementação do
método em relação à sua declaração" ou "usar nomes de constantes com letras maiúsculas"
são muito úteis para aumentar a legibilidade do código, além de deixá-lo mais elegante.
O Checkstyle (Checkstyle Homepage) é um outro verificador disponível para Java, mas
com foco na padronização da codificação. Esta ferramenta indica locais do código fonte que
não aderem ao estilo de programação adotado. Tais estilos são altamente configuráveis e
normalmente se adota um único por projeto ou até para toda uma organização.
O uso de verificação estática é bastante comum em projetos com integração contínua. A
integração contínua é uma técnica de XP na qual o código fonte desenvolvido pela equipe
deve ser freqüentemente recombinado, ou seja integrado, e uma versão funcional ou semi-
funcional do projeto é construída, por uma ferramenta de construção automática. Durante a
construção, a ferramenta pode executar os verificadores sobre o código e gerar relatórios com
os resultados. Estes resultados são muitas vezes usados como critério para definir se uma
construção tem qualidade suficiente para ser lançada para cliente final ou se ainda deve passar
por melhorias.
42
4.4.2 Testes de unidade
Testes de unidade são usados para certificar que os métodos ou classes implementados
produzem os resultados esperados. Os testes são responsáveis pela verificação dinâmica do
software, ou seja, o software é analisado durante sua execução.
Um dos princípios que deve ser seguido ao se escrever testes, é que estes devem verificar
seus próprios resultados e notificar a falha claramente. Esta é a grande vantagem dos testes de
unidade sobre a depuração. Uma vez que um teste falhe, a causa é clara, a porção de código
que ele valida está com problemas.
A existência de testes é considerada uma das pré-condições para a refatoração. Quando se
deseja refatorar, é preciso criar testes para o código modificado caso não existam. Este testes
são usados para indicar se a refatoração alterou ou não o comportamento do código. Se algum
teste existente falha, então a refatoração deve ser desfeita e revista.
O JUnit é um framework de testes de unidade bastante difundido na comunidade Java.
Com ele é possível escrever testes de unidade e executá-los de maneira bastante simples,
principalmente em IDEs que possuem integração com este framework.
4.4.3 Ambientes de desenvolvimento com suporte à re fatorações
automatizadas
Os ambientes de desenvolvimento integrado (IDEs) atuais, em sua grande maioria, dão
suporte à refatorações automatizadas, normalmente com base no catálogo criado por Fowler.
A automatização torna as refatorações mais baratas, em termos de tempo e esforço. A
carga de trabalho repetitivo se torna muito menor e há menos coisas para se verificar
manualmente. Estas vantagens servem como incentivo para o desenvolvedor refatorar e,
conseqüentemente, melhorar o projeto.
O custo do projeto de software também diminui junto com o custo da refatoração. Com
refatorações automáticas, algumas decisões de projeto podem ser adiadas, pois alterá-lo é
menos custoso. Pode-se focar mais no problema corrente e liberar mais rapidamente um
projeto inicial, sem ter que adivinhar as maneiras pelas quais o sistema irá mudar no futuro. O
projeto passa a crescer e amadurecer juntamente com os requisitos e não prematuramente. Os
equívocos de projeto são menores e há menos retrabalho.
43
A possibilidade de falhas humanas durante a refatoração também cai bastante, já que fica
à cargo da ferramenta verificar as pré-condições para a realização da refatoração, bem como
validar a consistência do código após concluída. Erros banais são evitados, como esquecer de
alterar o nome de um método em algum lugar do código em que ele é chamado ao realizar a
refatoração Renomear Método.
A refatoração auxiliada por ferramentas também influencia os procedimentos de teste.
Como boa parte das refatorações são executadas automaticamente, menos testes precisam ser
executados durante a realização das refatorações. Isto agiliza o processo de refatoração,
aumentando a produtividade.
4.4.3.1 Refatoração no Eclipse JDT
Dentre os IDEs de código aberto com suporte a linguagem Java, o Eclipse JDT sempre
teve o suporte à refatoração como uma característica forte. A ferramenta fornece suporte à 18
refatorações de baixo nível, além de outras específicas da linguagem Java, como as
relacionadas a tipos genéricos.
As refatorações providas pelo Eclipse são bastante confiáveis e dificilmente acarretam em
falhas. Antes de executar a refatoração, o Eclipse faz uma série de verificações para
determinar se a refatoração tornará o código inválido ou inconsistente. Em alguns casos,
quando identifica algum problema com a refatoração, o Eclipse exibe um alerta notificando o
desenvolvedor e permite interromper a operação. Em outros, quando o problema identificado
é mais crítico, a refatoração é simplesmente negada. Isto dá muita segurança ao
desenvolvedor
Ao executar uma refatoração no Eclipse é possível visualizar os locais que serão afetados
e comparar o estado anterior à refatoração com o estado posterior, para cada classe afetada. Se
o resultado apresentado é diferente do que se esperava, a refatoração pode ser cancelada e
nada é alterado.
As modificações feitas por meio de refatoração são registradas em um histórico. Este
histórico pode ser usado para reverter o projeto para um estado anterior bem como pode ser
exportado em um script de refatoração. Ao importar o script, o IDE executa as refatorações
salvas neste. Assim as refatorações podem ser aplicadas e trocadas entre os desenvolvedores
como é feito hoje com os patchs de ferramentas de controle de versão.
44
Apesar de um suporte avançado à refatorações de baixo nível, grande parte das
refatorações de baixo nível não são implementadas pelo Eclipse JDT. Quando se fala em
refatoração para padrões, estas não possuem suporte algum.
4.5 Vantagens da refatoração
O uso de refatoração evita a deterioração do projeto do software, ou seja, o desencontro
entre o que está projetado e o que se tem implementado, porque as melhorias na estrutura do
código são feitas juntamente com as manutenções, mantendo sempre a facilidade de se
visualizar o projeto a partir do código.
A manutenção do código refatorado é facilitada, tanto pela eliminação de trechos
duplicados, que diminuem o tamanho do código a ser mantido, quanto pelo aumento a
legibilidade do código. Quanto mais rapidamente alguém o entende o código, mais rápido
poderá alterá-lo e ainda cometendo menos enganos.
A refatoração é também um meio de se aprender sobre o código. Usando refatoração
pode-se alterar um código, partindo de uma suposição a respeito do que ele faz, e então testá-
lo. Se continuar funcionando, muito provavelmente a suposição está correta. Isto também
ajuda a encontrar falhas existentes no código, através do conhecimento adquirido a seu
respeito durante as refatorações.
A produtividade dos trabalhos sobre o código refatorado é aumentada, pois o
distanciamento entre código e o projeto é evitado. Além disso, o aumento da legibilidade e a
redução das falhas do código são de grande importância para o aumento da produtividade.
4.6 Problemas com a refatoração
O uso de refatoração traz vários benefícios à evolução do projeto. Porém o seu uso, além
de necessitar de grande disciplina e cuidado, pode acarretar em problemas decorrentes da
natureza do projeto e da complexidade na aplicação destas técnicas. Nem sempre é um bom
negócio refatorar. Tem-se que avaliar muito bem o contexto.
Nas refatorações em que a interface da classe é alterada, quando não se tem controle
sobre todo o código que utiliza a classe modificada, por exemplo no código fonte de uma
biblioteca utilizada por diferentes sistemas, pode-se gerar incompatibilidade entre os usuários
da interface antiga da classe e a nova interface(FOWLER, 2004). Utilizando o exemplo da
45
classe de uma biblioteca se esta tivesse o nome de um método público alterado, caso não
possa alterar também os sistemas que usam biblioteca para referenciarem o método pelo
nome, a refatoração de alteração de nome do método torna-se inviável.
Uma maneira de viabilizar esta refatoração seria manter na classe o método com o nome
antigo, delegando sua chamada para o método com o nome novo. A classe passaria a conter
mais de um método executando exatamente o mesmo código mas este seria o custo a se pagar
para manter a compatibilidade. Uma boa prática seria marcar o método antigo como obsoleto,
referenciando qual método deve passar a ser usado, para que aos poucos os usuários da classe
passem a utilizar o método novo e o antigo possa ser excluído.
Um caso problemático de refatoração de interface de classe, é a adição do lançamento de
uma exceção checada em um método na linguagem Java. Este tipo de exceção deve ser
tratada nos locais em que o método onde ela é lançada é chamado, ou capturando-a em um
bloco try/catch, ou relançando-a. De qualquer forma a adição de exceção envolve alterações
em todos os locais onde o método alterado é utilizado, o que não é desejável.
Uma solução é criar um outro método que lance a nova exceção e chamá-lo no método
antigo e neste converter a exceção checada em uma não checada. Exceções não checadas não
têm a necessidade de serem tratadas pelos métodos. Outra maneira seria lançar diretamente
uma exceção não checada, porém isto faria perder a obrigatoriedade do tratamento da
exceção.
Em ambos as soluções é importante notificar que a exceção pode passar a ser checada,
para que os desenvolvedores que utilizam a classe possam preparar seus códigos para a futura
modificação.
Uma boa prática é definir uma classe de exceção para todo um pacote e utilizá-las nas
super classes, assegurando que as interfaces públicas sempre utilizem esta exceção. Assim
pode-se definir novas exceções nas subclasses que herdem da classe de exceção do pacote, o
que não afeta classes que lançam a exceção do pacote. Esta tática é utilizada no pacote
java.sql da API do Java 2. Toda exceção deste pacote herda ou é diretamente uma instância de
java.sql.SQLException.
Em aplicações altamente acopladas ao esquema do banco de dados alterações no esquema
do banco se tornam muito difíceis, pois acarretam em mudanças no modelo de objetos. Além
disso as modificações no esquema implicam em migração de dados, que geralmente é uma
46
tarefa arriscada e trabalhosa. Perda ou inconsistência de dados é algo ruim para qualquer
projeto.
Com bancos de dados não orientados a objetos, uma solução é criar uma camada de
software entre os dois modelos, para isolar as alterações no modelo do banco das alterações
no modelo de objetos. As atualizações em um dos modelos afeta apenas a camada
intermediária. Normalmente é usado o padrão de projeto DAO para a construção desta
camada.
Algumas banco de dados OO fornecem migração automática de uma versão de um objeto
para outra. Isto reduz o esforço, porém há perda de tempo enquanto a migração ocorre.
Quando esta migração não é automática a alteração na estrutura de dados da classe deve ser
mais cuidadosa, pois a migração manual demanda muito esforço.
47
5 REFATORAÇÃO DO FRAMEWORK OCEAN
O JFC Swing é o framework padrão da linguagem Java para a construção de interfaces
gráficas com o usuário (GUI) e foi utilizado na construção das classes de visualização do
OCEAN ao longo de sua migração para a linguagem Java. Ferramentas e editores, partes do
OCEAN com necessidade de comunicação com o usuário, passaram a ter o JFC Swing como
dependência.
O JHotDraw é um framework destinado a desenhos técnicos e estruturados, ou seja, é
voltado ao desenvolvimento de editores gráficos bidimensionais com semântica associada aos
elementos gráficos. Foi utilizado na versão Java do OCEAN para a construção dos editores de
diagramas. O JHotDraw tem sua estrutura definida sobre o framework JFC Swing, o que
reforçou ainda mais a dependência do OCEAN em relação a este último.
A abordagem MVC é composta por três tipos de objetos. O Modelo é o objeto da
aplicação, a Visão é a apresentação na tela e o Controlador é o que define a maneira como a
interface do usuário reage às ações do mesmo. A MVC separa estes objetos para aumentar a
flexibilidade e a reutilização (GAMMA, HELM, et al., 2000). Manter o projeto baseado na
MVC, com independência entre as classes de modelo em relação as responsáveis pelo
controle e visualização, foi algo muito considerado durante a migração para a linguagem
Java.
Porém, sendo o objetivo da migração para Java a obtenção de um protótipo do
ambiente SEA, que certamente teria que sofrer melhorias para se tornar um produto final,
além das limitações de prazo para atingir tal objetivo, a intenção de manter as classes de
modelo isoladas acabou perdendo prioridade e o uso de classes do JFC Swing se alastrou ao
longo do núcleo do framework.
48
O objetivo da migração foi alcançado, porém a revisão das classes de modelo do
OCEAN para a remoção dos acoplamentos indevidos com a GUI permaneceu como uma
pendência a ser resolvida em trabalhos futuros. Neste contexto surgiu a refatoração como
solução para melhorar a qualidade do projeto e código do OCEAN, mantendo suas
funcionalidades.
A execução das refatorações foi centrada nas classes do núcleo do framework,
principalmente na hierarquia de OceanDocument, mostrada na Figura 1. Classes de
ferramentas foram retiradas do escopo, visto que as ferramentas do OCEAN precisam ser
revisadas e validadas.
Foi necessário identificar as estruturas dentro do OCEAN onde o acoplamento à
interface gráfica era indevido. Depois de levantar a possíveis soluções e decidir qual seria
adotada eram, então, aplicadas as refatorações para diminuição ou remoção do acoplamento.
A realização das refatorações foi feita com o auxílio do Eclipse JDT, que oferece uma
série de refatorações automatizadas. Sempre que possível, foi escolhida uma seqüência de
refatorações na qual todas fossem suportadas pela ferramenta, a fim de evitar erros
decorrentes da realização de refatorações manualmente.
5.1 JOptionPane
O uso do JOptionPane4 em classes de modelo do OCEAN era um problema vagamente
conhecido. Era sabido que em algumas classes de modelo do OCEAN o JOptionPane era
usado para exibir mensagens e em outras classes para solicitar valores ao usuário. Porém não
se tinha idéia de qual eram estas classes nem da quantidade de classes que continham este
acoplamento.
Assim, foi feita uma busca pelas classes do OCEAN referenciavam a classe
JOptionPane. Esta busca foi feita com o auxílio da ferramenta procura do Eclipse JDT, por
esta exibir em uma árvore cada classe e método onde havia uma ocorrência, o que permitia ter
uma boa visão do problema bem como uma navegação rápida entre as ocorrências.
Primeiramente foram procuradas as classes que usavam o JOptionPane para exibir
mensagens, ou seja, classes onde era chamado o método showMessageDialog. Como
4 A classe JOptionPane é um componente do framework JFC Swing, facilita a exibição de uma caixa de diálogo padrão, para
solicitar ao usuário algum valor ou mostrar uma mensagem. É comum usar esta classe para notificar erros ou exibir alertas ao usuário.
49
resultado desta primeira busca foi gerada a Tabela 1, que encontra-se no Anexo 1, contendo as
linhas onde era chamado o showMessageDialog e a mensagem que era exibida, agrupados por
classe. Nesta primeira busca foram encontradas 176 ocorrências em 51 classes diferentes.
Num segundo momento foi feita uma busca pelas classes onde o JOptionPane era
utilizado para solicitar valores ao usuário, através de chamadas aos métodos
showConfirmDialog ou showInputDialog. O resultado da busca deu origem à Tabela 2,
presente no Anexo 2, inicialmente com registros no mesmo formato que os da Tabela 1. Ao
todo, foram encontradas 63 ocorrências em 27 classes diferentes, como resultado desta busca.
Tendo em mãos o mapeamento da quantidade de pontos de acoplamento, e os locais
onde se encontravam, partiu-se para a análise das ocorrências encontradas.
5.1.1 JOptionPane para exibição de mensagens
Em várias classes era usada a função showMessageDialog do JOptionPane para exibir
mensagens. Como a quantidade de ocorrências encontradas era muito grande foi decidido
reduzir o escopo da análise e das refatoração, eliminando-se as classes de ferramentas do
OCEAN. Outro motivo para esta redução do escopo é que as ferramentas do OCEAN ainda
estavam pendentes de validação e refatorá-las neste estado seria em vão. Após a redução de
escopo, as ocorrências restantes foram analisadas uma a uma.
5.1.1.1 Análise das ocorrências encontradas
Algumas das mensagens exibidas via JOptionPane notificavam o usuário a respeito de
um erro inesperado ocorrido durante a execução de um método, como por exemplo na
chamada de métodos que instanciavam classes usando reflection, ou em chamadas à métodos
sem corpo ainda não implementados. Este tipo de erro está normalmente associado à um
defeito no sistema, ou seja, um falha de programação, que não pode ser recuperada ao longo
da execução.
Na ocorrência de erros inesperados exibir uma janela com uma mensagem ao usuário e
continuar a execução do software não é uma boa escolha, pois dá ao usuário a impressão de
que a falha foi contornada, enquanto que esta continua a existir, até que seja feita uma
manutenção no código fonte.
50
Em grande parte das chamadas de showMessageDialog encontradas, o JOptionPane era
usado para notificar erros na edição de modelos ou conceitos, oriundos da verificação de
consistência de especificação feita pelo OCEAN. Quando a alteração do usuário levaria a
especificação a um estado inconsistente da especificação, era exibido um JOptionPane
alertando o usuário sobre a inconsistência e a alteração não era aplicada.
Diferente dos casos citados anteriormente, notificar o usuário do problema ocorrido é
o mais importante, pois este deve saber que está executando uma edição ilegal na
especificação. Também a ocorrência deste tipo de erro não leva a aplicação à um estado de
erro irrecuperável. A execução pode continuar normalmente, pois não cabe ao software e sim
ao usuário corrigir sua ação. Assim, a exibição do JOptionPane deveria continuar sendo feita,
mas a partir das classes de GUI, em geral nos editores de diagramas do OCEAN.
5.1.1.2 Proposta de solução
As exceções são a forma usual em Java para indicar a um método cliente que uma
condição anormal ocorreu na chamada à outro método (VENNERS, 1998). Um método, ao se
encontrar em uma condição anormal que não pode tratar, deve lançar uma exceção,
permitindo que o problema seja tratado em outro local.
Com o uso de exceções é possível separar o tratamento de erros do código que é
executado em condições normais (VENNERS, 1998). O código normal5, executado com
maior freqüência, pode ser cercado por um bloco try/catch e o código de tratamento de erros
pode ser colocado dentro da cláusula catch. Desta forma, o código normal fica menos
fragmentado.
Quando um método lança exceções checadas, o compilador força que esta exceção seja
tratada nos métodos clientes do mesmo, capturando a exceção ou relançado-a. O fato de o
compilador Java garantir o tratamento de exceções checadas auxilia no aumento da robustez
dos softwares em Java (VENNERS, 1998). Em Java, são exceções checadas a classe
Exception e suas subclasses6.
O lançamentos de uma exceção não checada permite que o método cliente decida por
tratar ou ignorar a exceção, assim como ocorre com as exceções checadas. Entretanto, o
5 Código que é executado em condições normais. 6 Exceto RuntimeException e suas subclasses.
51
compilador não força o tratamento de exceções não checadas. Assim, um método cliente pode
até desconhecer que um exceção deste tipo possa ser lançada pelo método chamado. Em
geral, exceções que indicam o uso inapropriado de uma classe devem ser não checadas
(VENNERS, 1998). Em Java, classe RuntimeException e suas subclasses constituem a
hierarquia das exceções não checadas.
Por esta características das exceções na linguagem Java, foi decidido adotá-las como
solução para substituir a uso do JOptionPane na exibição de mensagens a partir das classes de
modelo do OCEAN. A estratégia adotada foi lançar uma exceção com a mensagem antes
exibida pelo JOptionPane. Assim, fica a cargo das classes de interface gráfica a captura da
exceção e a exibição da mensagem através de um JOptionPane.
Nas ocorrências presentes na Tabela 1 onde a mensagem exibida via JOptionPane era
um erro inesperado, ou irrecuperável, sem necessidade de notificação do usuário, foi decidido
lançar exceções não checadas.
Nos casos em que a mensagem notificava um do domínio do OCEAN, como uma
edição insistente de uma especificação, quando o JOptionPane deveria continuar sendo
exibido ao usuário, foram adotadas as exceções checadas para forçar o tratamento nas classes
de GUI. Após escolhidas as soluções a serem adotadas, a Tabela 1foi completada com a
coluna a solução a ser aplicada em cada ocorrência do showMessageDialog.
Lançar Exception apenas com uma mensagem indicando o tipo de condição anormal
ocorrida não é algo recomendado (VENNERS, 1998). A classe da exceção é que deve indicar
o tipo de problema ocorrido. Assim, foi criada uma hierarquia de exceções checadas,
composta pelas classes OceanException e InconsistentModelException. A Figura 5 mostra a
hierarquia de exceções criada.
Figura 5: Hierarquia de classes de exceção do OCEAN
52
A classe OceanException foi criada para ser a raiz da hierarquia de exceções do
OCEAN, ou seja, toda classe de exceção do framework deve ser subclasse de
OceanException.
A definição desta hierarquia de exceções é importante para que as aplicações
construídas a partir do OCEAN possam ter a escolha de tratar as exceções disparadas a partir
do framework como sendo de um único tipo, evitando acoplamento às exceções mais
especializadas do framework.
A classe InconsistentModelException foi criada para notificar os erros resultantes das
validações de consistência feitas nas classes de modelo (subclasses de ConceptualModel).
5.1.1.3 Aplicação das refatorações
A substituição do JOptionPane pelo lançamento das exceções não checadas, não
implicou em alterações nos métodos clientes dos métodos refatorados, o que tornou estas
refatorações mais simples. Bastou alterar os algoritmos para lançar a exceção não checada
com a mensagem que antes era exibida via JOptionPane e remover a chamada ao método
showMessageDialog.
As refatorações para inclusão das exceções checadas foram mais trabalhosas que a
realizadas para as não checadas, pois foi necessária a alteração dos métodos clientes dos
refatorados.
Basicamente, os passos envolvidos na substituição do JOptionPane pelo lançamento de
exceções checadas, para cada método refatorado, foram:
1. Extrair todo o algoritmo do método refatorado para um novo, de nome semelhante,
usando a refatoração Extrair Método. Neste passo o método original era marcado como
depreciado (deprecated) e era inserido um comentário javadoc no método referenciando o
método novo.
2. No novo método, trocar a exibição do JOptionPane pelo lançamento de uma exceção com
uma mensagem igual. Capturar a exceção dentro método original, exibindo um
JOptionPane para mostrar a mensagem da exceção.
3. Aplicar Internalizar Método sobre o método refatorado em todas as classes que o
chamam. Como conseqüência deste passo, a exibição do JOptionPane passa da classe de
53
modelo para a de interface gráfica. Neste passo a marcação de depreciação também era
removida.
4. Renomear o método novo para o mesmo nome que o método internalizado.
A Figura 6, Figura 7, Figura 8 e Figura 10 mostram como foi feito o uso desta
seqüência de passos sobre o método createComponent da classe ConceptualModel.
Figura 6: Estado inicial
Figura 7: Após a refatoração Extrair Método (Passo 1)
54
Figura 8: Após substituição do JOptionPane por lançamento de exceção (Passo 2)
Figura 9: Após Internalizer Método (Passo 3)
Figura 10: Após Renomear Método (Passo 4)
55
5.1.2 Uso do JOptionPane para solicitar parâmetros ao usuário
Em alguns locais do OCEAN o JOptionPane foi usado para solicitar parâmetros ao
usuário ou confirmar a execução de alguma ação. Estes casos foram registrados na Tabela 2,
presente no Anexo 2.
Um primeiro passo da análise destes casos foi o levantamento de quais os tipos de
valores eram solicitados ao usuário em cada ocorrência de showConfirmDialog e
showInputDialog encontrada. Este levantamento também foi registrado na Tabela 2, na última
coluna.
Depois de mapeados os tipos de valores solicitados, cada uma das ocorrências foi
analisada separadamente para levantamento da refatorações necessárias.
Nestes casos, o método onde era feita a chamado ao JOptionPane foi quebrado em
dois, um primeiro com a chamada ao JOptionPane para solicitar o valor ao usuário e um
segundo que recebe o valor obtido do usuário como parâmetro e executa o algoritmo do
método original. Para isto era usada a refatoração Extrair Método.
Extraídos os dois métodos, entre estes o que continha a chamada ao JOptionPane era
internalizado nas classes de GUI, com a aplicação da refatoração Internalizar Método.
5.2 Recuperação da estrutura de editores
Na primeira versão do framework OCEAN, ainda em linguagem SmallTalk, a
estrutura de visualização e edição dos mecanismos de especificação eram definidas na classe
SpecificationElementInterface. A classe ConceptInterface continha a estrutura genérica dos
mecanismos de edição e visualização de conceitos e a classe ConceptualModelInterface,
correspondia à estrutura genérica dos mecanismos de edição e visualização de modelos. A
Figura 11 mostra esta estrutura de classes, que foi perdida durante a recodificação para Java.
Figura 11: Hierarquia das classes de editores da versão original do OCEAN
56
ReferenceManager é uma das classes do núcleo do OCEAN e tem a responsabilidade
de mapear cada tipo conceito e modelo ao seu respectivo mecanismo de edição e visualização.
Uma das conseqüências da remoção da hierarquia de editores é que a classe
ReferenceManager passou a ficar acoplada às classes concretas de editores de diagramas e
conceitos criadas para o SEA, ou seja, às subclasses de AuxWindowAppModel. A Figura 12
mostra como ficou a hierarquia de classes de editores após a migração do OCEAN para a
linguagem Java.
Figura 12: Hierarquia de editores do OCEAN após migração para Java
A classe AuxWindowAppModel e suas subclasses têm JPanel como classe mãe,
sendos formetemente acopladas ao JFC Swing. Assim manter a dependência entre
ReferenceManager e tais classes é também manter mais um ponto de acoplamento entre o
OCEAN e o JFC Swing.
A hierarquia de editores presente na versão original do OCEAN foi retomada, porém
com o uso de interfaces Java em lugar do uso de classes abstratas. A Figura 13 mostra como
ficou a estrutura de editores após as refatorações.
57
Figura 13: Estrutura de editores após refatoração
As interfaces SpecificationElementEditor, ConceptualModelEditor e ConceptEditor
correspondem às classes SpecificationElementInterface, ConceptualModelInterface e
ConceptInterface, respectivamente.
A classe AuxWindowAppModel passou a implementar SpecificationElementEditor.
Por sua vez a classe JedicaoConceitos e suas subclasses passaram a implementar
ConceptEditor bem como a classe EditorAuxWindow passou a implementar
ConceptualModelEditor. Como a nova estrutura de editores é baseada em interfaces, as
classes de editores não precisaram ter sua hierarquia alterada. Classes que herdavam de JPanel
assim se mantiveram.
Além do uso de interfaces, outro avanço da nova estrutura de editores foi a o uso de
tipos genéricos do Java. O uso deste recurso da linguagem propicia um aumento na segurança
de tipos em tempo de compilação evitando erros de conversão de tipos (casting) em tempo de
execução.
A classe ReferenceManager foi refatorada para fazer uso da nova estrutura de editores
sendo completamente desacoplada da hierarquia de AuxWindowAppModel. Também com o
uso dos tipos genéricos não é mais permitido mapear um tipo de conceito para um editor de
outro tipo de conceito, ou seja, para um conceito Metodo só podem ser mapeadas classes de
editores que implementem ConceptualModelEditor<Metodo>.
58
Outro ponto a se destacar é a quanto a classe ReferenceManager reduziu, passando a
ter 68 linhas, bem menos que a versão anterior, que tinha 372 linhas. Mesmo com a redução
de tamanho as funcionalidades de ReferenceManager permaneceram as mesmas.
5.3 Outros problemas resolvidos
5.3.1 Substituição da classe OceanVector
A classe OceanVector foi criada por Ademir durante a migração do OCEAN para a
linguagem Java, a fim de contornar o problema com índices de coleções, que em Java
começam em 0 (zero) enquanto que em SmallTalk começam em 1 (um). Como seria muito
trabalhoso e propenso à falhas alterar os algoritmos do OCEAN que usam índices de coleções
para que usassem as coleções da API do Java, foi decidido criar uma nova classe de coleção,
OceanVector, com índice iniciado em 1.
Apesar de ter resolvido o problema da migração, o uso da classe OceanVector
dificultava o entendimento dos algoritmos por alguém já habituado com as coleções nativas
do Java. Este foi mais um motivo para a execução da refatoração. Além disso, pode-se dizer
que a classe OceanVector é o mau cheiro chamado Intermediário (FOWLER, 2004), pois
praticamente todos os seus métodos delegam para a classe Vector.
A refatoração recomendada para este caso é a Remover Intermediário, porém foi
utilizada uma seqüencia diferente de passos para substituição do Intermediário OceanVector
pela classe Vector, por conta da adaptação de índices feita em OceanVector e para que fossem
evitadas as refatorações manuais em favor do uso das refatorações automáticas fornecidas
pelo Eclipse JDT.
1. Usando a refatoração Renomear Método para adicionar o sufixo “Adaptado”aos métodos
que faziam delegação ao atributo vector da classe OceanVector.
Estado Inicial Renomear Método
public void add(final int index, final T element) {
vector.add(this.adapta(index), element);
public void addAdaptado(final int index, final T element) {
vector.add(this.adapta(index), element);
59
} }
2. Depois as delegações ao vector foram isoladas em métodos de mesmo nome que o método
delegado, usando Externalizar Método.
Após Alterar Algoritmo Após Externalizar Método
public void addAdaptado(final int index, final T element) {
int auxIndex = this.adapta(index);
vector.add(auxIndex, element);
}
public void addAdaptado(final int index, final T element) {
int auxIndex = this.adapta(index);
this.add(auxIndex, element);
}
public void add(final int index, final T element) {
vector.add(index, element);
}
3. Foi aplicada a refatoração Internalizar Método sobre métodos adapta(int) e desadapta(int)
da classe OceanVector.
Após Internalizar Método Após Alterar Algoritmo
public void addAdaptado(final int index, final T element) {
int auxIndex = index - 1
this.add(auxIndex, element);
}
public void addAdaptado(final int index, final T element) {
this.add(index - 1, element);
}
4. Aplicando a refatoração Substituir Delegação por Herança, a classe OceanVector passou
a estender a classe Vector. Assim os métodos que delegavam a Vector foram removidos.
Estado Anterior Após Substituir Delegação por Herança
public void addAdaptado(final int index, final T element) {
this.add(index - 1, element);
}
public void add(final int index, final T element) {
vector.add(index, element);
}
public void addAdaptado(final int index, final T element) {
this.add(index - 1, element);
}
public void add(final int index, final T element) {
vector.add(index, element);
}
60
5. Então, os métodos com sufixo “Adaptado” foram internalizados (Internalizar Método) nas
classes que os chamavam.
Estado Anterior Após Internalizar Método
...
OceanVector vector = ...;
Object foo = ...;
for (int i = 1; i < vector.size(); i++) {
vector.add(i, foo);
}
...
OceanVector vector = ...;
Object foo = ...;
for (int i = 1; i < vector.size(); i++) {
vector.add(i - 1, foo);
}
6. Por fim, todas as referências e construtores à classe OceanVector foram substituídos por
Vector com a refatoração Condensar Hierarquia e a classe OceanVector pôde ser
removida do OCEAN.
Apesar de terem sido mostrados os efeitos da refatoração para o método add(int), os
mesmos passos foram feitos para os demais da classe OceanVector, como get(int) e
remove(int).
Como conseqüência desta refatoração, os algoritmos existentes no OCEAN passaram a
usar Vector e por conseqüência índice iniciado em 0, tornando-se mais claros. Também
possibilita que durante a revisão dos algoritmos existentes seja possível usar o laço foreach
para iterar sobre as coleções. O foreach é um recurso da linguagem Java válido apenas para
coleções com índice inicial 0.
5.3.2 Eliminação de código morto
Antes de aplicar qualquer refatoração em um método, por exemplo que continha a
chamada à um JOptionPane, verificava-se se este método era utilizado ou redefinido por
alguma outra classe. Se o método não era usado nem estendido, este método era excluído da
classe. Assim, porções de código que seriam refatoradas inutilmente foram ignoradas.
Esta abordagem também fez com que muitos métodos inúteis fossem eliminados,
reduzindo a quantidade de código do OCEAN a ser mantido.
5.3.3 Reescrita de algoritmos
O uso de uma ferramenta de conversão automática facilitou a migração do OCEAN
para Java, porém teve como efeito colateral a baixa legibilidade do código resultante.
61
Declarações de variáveis fora do escopo onde são usadas, laços de iteração sobre
enumerations e uso intenso de variáveis temporárias são características comuns a muitos
métodos das classes do framework.
Melhorar os algoritmos para torná-los mais claros e melhor estruturados foi algo
bastante necessário durante as refatorações feitas no OCEAN. Algumas refatorações não eram
possíveis sobre o algoritmo implementado, sendo necessário primeiramente alterar o
algoritmo para então refatorar.
Além disso, a refatoração dos algoritmos trouxe à tona duplicidades de código que
estavam ocultas nos algoritmos confusos. Os códigos identificados como duplicatas foram
removidos.
Assim, os métodos do das classes do OCEAN que sofreram refatoração ficaram mais
legíveis e a quantidade do código duplicado também diminuiu nestas classes.
5.3.4 Maven para controle do ciclo de vida
O Maven é uma ferramenta de gerenciamento de projetos Java . Com o uso desta
ferramenta é possível configurar tarefas a serem executadas automaticamente durante a fases
de compilação, teste, empacotamento e instalação do projeto. Coleta de métricas, execução de
testes automáticos, criação do arquivo jar são uns poucos exemplos de tarefas que podem ser
executadas pelo Maven ao longo das fases do projeto.
O Maven também suporta o controle de dependências do projeto. Em um projeto que
usa o Maven não é necessário ter os arquivos de bibliotecas dentro da estrutura do projeto.
Basta declarar a dependência no arquivo de configuração do projeto, o POM, que o Maven se
encarrega de fazer o download da biblioteca e instalá-la em um repositório local, que pode ser
compartilhado entre vários projetos.
No caso do OCEAN, o Maven foi usado para controlar as dependências e também
para dar uma estrutura ao projeto, em termos de organização de pastas e pacotes. Como a
versão do JHotDraw usada no OCEAN não está presente no repositório central do Maven, foi
criado um script que faz a instalação destas bibliotecas no repositório local.
62
5.3.5 SLF4J
O SLF4J é um Facade sobre vários frameworks de logging da linguagem Java, como
JUL7, Log4j e Logback, permitindo que o desenvolvedor escolha sobre qual framework
utilizar no momento da implantação do software. Toda implementação do sistema é feita
sobres classes do SLF4J, independente do framework a ser usado depois.
Um framework ou biblioteca não deveria impor um framework de log ao software que
o utiliza, pois dificulta o uso em aplicação existentes, com estrutura de logs já montada ou em
novas aplicações em que o uso de um framework de log está pré-definido nos requisitos.
Tendo em vista facilitar o uso do OCEAN, foi substituída a sua dependência do log4j
pelo SLF4J. O log4j continua sendo usado como framework padrão, mas passou a ser uma
dependência opcional, podendo ser trocado por outro, desde que seja suportado pelo SLF4J.
7 API padrão da plataforma Java (java.util.logging).
63
6 CONCLUSÃO
Com o uso de técnicas de refatoração foi possível a melhoria do projeto do framework
OCEAN, passando a ter uma melhor divisão de responsabilidades entre suas classes de
modelo e interface gráfica e uma redução no acoplamento entre o núcleo do OCEAN e o
framework JFC Swing.
A adoção de exceções melhorou o modo como são feitas as notificações e tratamento de
erros no OCEAN, tornando possível separar o código de tratamento de erros do código
comum. Além disso, o uso de exceções checadas permitiu ter o auxílio do compilador Java
para obrigar o tratamento de erros, contribuindo para o aumento da robustez do framework.
Também o uso da exceções não checadas passa a tornar mais evidente o falhas no framework
decorrentes de erros de programação.
O aumento da clareza de código proporcionado pelo uso de refatoração ficou evidente nas
classes e métodos que sofreram modificação neste trabalho. Os algoritmos de vários métodos
refatorados foram reescritos para permitir a aplicação da refatoração, ficando melhor
estruturados que o resultante da conversão automática de SmallTalk para Java.
A remoção de código duplicado feita durante as refatorações aumentou a legibilidade do
código do OCEAN, além de ter reduzido as chances de introdução de falhas decorrentes da
alteração de códigos copiados. Outra contribuição da remoção de duplicidades, junto à
eliminação de código morto, foi redução da quantidade de código a ser mantida.
Uma deficiência na execução das refatorações se foi a superficialidade com que foram
realizados os testes. Apenas com o uso do ambiente SEA não se pode garantir efetivamente
que as refatorações feitas não introduziram falhas, já que a cobertura oferecida por este tipo
de teste é um tanto vaga. Além disso, o esforço despendido na realização manual dos testes
64
não pode ser reaproveitado em trabalhos futuros, algo que se teria caso implementados o
testes de unidade.
A ausência de documentação unificada, bem como grande quantidade de classes do
framework são fatores que dificultam o entendimento do OCEAN. O próprio domínio a que o
framework se destina é um tanto complexo e exige bastante conhecimento a respeito do
desenvolvimento de frameworks para ser entendido.
6.1 Trabalhos futuros
Durante este trabalho foi feito um levantamento de vários pontos do OCEAN onde o
acoplamento com a GUI deveria ser removido (vide Anexo 1 e Anexo 2), porém nem todos
foram removidos. As ferramentas do OCEAN, que foram excluídas do escopo, podem ter os
acoplamentos apontados removidos à medida que são validadas.
A criação dos testes de unidade é imprescindível para que as manutenções sobre o
OCEAN sejam feitas de forma mais confiável, de maneira a não introduzirem defeitos no
código do framework. A atividade de criação de testes de unidade deve tornar-se um
requisito obrigatório para toda nova funcionalidade inserida no framework. Além de
aumentarem a robustez do framework, os testes podem suprir parte da deficiência de
documentação do OCEAN, revelando a intenção das classes e métodos que avaliam.
A falta de documentação, á citada em trabalhos anteriores, continua a ser um empecilho
para a evolução do OCEAN, devendo ser o quanto antes solucionada. A documentação
existente está descentralizada, sendo difícil obter uma visão geral a respeito do framework
sem a leitura de vários trabalhos realizados sobre o OCEAN. Também, a nível de
implementação a documentação é praticamente nula, sendo pouquíssimos os métodos e
classes possuem comentários javadoc.
A preocupação em relação aos trabalhos futuros sobre o OCEAN não está na evolução
funcional proporcionada por cada trabalho, mas na maneira como devem ser desenvolvidos e
inseridos no framework. A adequação às convenções da linguagem Java (Java Code
Conventions, 1997), apresentação de testes de unidade e documentação de código fonte são
características que deveriam estar presentes em todos os trabalhos futuros. Quando necessária
a adaptação do OCEAN para inclusão de novas funcionalidade, estas modificações poderiam
ser feitas com a base no processo de refatoração descrito neste trabalho.
65
6.2 Considerações finais
A contribuição trazida por este trabalho à continuidade do OCEAN vai além do
atendimento dos objetivos específicos, se estendendo aos benefícios conseqüentes do uso de
técnicas de refatoração, resultando no código do framework melhor estruturado, mais legível
e mais fácil de ser mantido.
A percepção dos benefícios do uso de refatoração é tão importante quanto resultado
final obtido no código fonte do OCEAN, devendo servir de incentivo para a aplicação da
técnica nos futuros trabalhos construídos sobre o framework. Somente assim, com o uso de
refatoração como parte das atividades de manutenção, o projeto e código do OCEAN entrarão
em um processo de melhoria contínua e trabalhos como este, como foco na realização de
refatorações, passarão a ser desnecessários.
66
7 REFERÊNCIAS BIBLIOGRÁFICAS
AMORIM, J. Integração dos frameworks JHotDraw e OCEAN para a produção de
objetos visuais a partir do framework OCEAN. Universidade Federal de Santa Catarina.
Florianópolis. 2006.
CHECKSTYLE Homepage. Checkstyle. Disponivel em:
<http://checkstyle.sourceforge.net>. Acesso em: 05 dez. 2010.
COELHO, A. Reengenharia do framework OCEAN. Universidade Federal de Santa
Catarina. Florianópolis. 2007.
FAYAD, M.; SCHMIDT, D. C. Object-Oriented Application Frameworks. Special Issue
on Object-Oriented Application Frameworks, 40, 1997.
FINDBUGS Homepage. FindBugs - Find Bugs in Java Programs. Disponivel em:
<http://findbugs.sourceforge.net>. Acesso em: 10 nov. 2009.
FOWLER, M. Refatoração - Aperfeiçoando o Projeto de Código Existente. Tradução
de Acauan Fernandes. Porto Alegre: Boookman, 2004.
GAMMA, E. et al. Padrões de projeto: soluções reutilizáveis de software orientado a
objetos. Tradução de Luiz A. Meirelles Salgado. Porto Alegre: Bookman, 2000.
Java Code Conventions. Sun Microsystems, Inc. [S.l.]. 1997.
JOHNSON, R. E. Components, Frameworks, Patterns, fev. 1997.
JOHNSON, R. E.; FOOTE, B. Disigning Reusable Classes. Journal of Object-Oriented
Programming, 1, 1988. 22-35.
KERIEVSKY, J. Refatoração para Padrões. Tradução de Eduardo Kessler Piveta. Porto
Alegre: Bookman, 2005.
67
LEME, F. Servlets - Parte1: Conceitos e Técnicas. Java Magazine, p. 32-42, 2004.
MACHADO, T. A. A. S. R. Reengenharia da interface do ambiente SEA.
Universidade Federal de Santa Catarina. Florianópolis. 2007.
PMD Homepage. PMD - Don't shoot the messenger. Disponivel em:
<http://pmd.sourceforge.net>. Acesso em: 05 dez. 2010.
PRESSMAN, R. S. Engenharia de Software. Tradução de José Carlos Barbosa dos
Santos. São Paulo: Person Makron Books, 1995. ISBN 85-346-0237-9.
ROBERTS, D.; JOHNSON, R. Evolving Frameworks - A Pattern Language for
Developing Object-Oriented Frameworks.
ROCHA, J. A. M. D. Modelo de Trabalho de Conclusão de Curso (TCC). Disponivel em:
<http://www.meiradarocha.jor.br/uploads/1021/196/modelo_de_projeto_de_TCC-2006-06-
12a.sxw>. Acesso em: 12 jul. 2009.
SILVA, R. P. Suporte ao desenvolvimento e uso de frameworks e componentes.
Universidade Federal do Rio Grande do Sul. Porto Alegre, p. 108-177. 2000.
VARGAS, T. C. D. S. Suporte à Edição de UML 2 no Ambiente SEA. Universidade
Federal de Santa Catarina. Florianópolis. 2008.
VENNERS, B. Designing with exceptions - Guidelines and tips on when and how to use
exceptions. JavaWorld.com, 1998. Disponivel em: <http://www.javaworld.com/jw-07-
1998/jw-07-techniques.html>. Acesso em: 08 dez. 2010.
VENNERS, B. Exceptions in Java - The full story of exceptions in the Java language and
virtual machine. JavaWorld.com, 1998. Disponivel em:
<http://www.javaworld.com/javaworld/jw-07-1998/jw-07-exceptions.html>. Acesso em: 08
dez. 2010.
68
8 ANEXOS
8.1 Anexo 1 - Tabela com ocorrências do JOptionPan e para exibição de mensagens
Tabela 1: Ocorrências do JOptionPane para exibição de mensagens
Linha Mensagem Solução proposta FileStoreManager
145 "Formato não suportado, escolha outro arquivo." Não alterar (fora do escopo) OceanFileManager
47 "The file is a directory" Não alterar (fora do escopo) 60 "You do not have the necessary permissions" Não alterar (fora do escopo) 88 "The file is a directory" Não alterar (fora do escopo)
102 "You do not have the necessary permissions" Não alterar (fora do escopo) 129 "The file is a directory" Não alterar (fora do escopo) 135 "You do not have the necessary permissions" Não alterar (fora do escopo)
ToolManager 89 "Error loading tool " + descriptor.toolName() + ".\n" + "Exception: " + tle.getMessage() Exception
Agregacao 801 "A versão atual não admite associações envolvendo uma única classe" Exception 904 "Impossível colar agregação: ausência de classe(s) envolvida(s) no diagrama." Método não é chamado em lugar algum.
Considerar exclusão ou ignorar. AssociacaoBinaria
971 "A versão atual não admite associações envolvendo uma única classe" Exception 1080 "Impossível colar associação binária: ausência de classe(s) envolvida(s) no diagrama." Exception 1377 I18NProperties.getString("not.allow.this.relationship") = "Este tipo de relacionamento não é Código inútil. Remover.
69
permitido." Atributo
69 "Incompatibilidade: atributos com tipos diferentes" Exception 75 "Incompatibilidade: atributos com tipos diferentes" Exception
232 "É necessário selecionar a classe em que o atributo será colado." Exception 306 "Conflito com atributo de superclasse (nomes repetidos)" Exception 330 "Conflito com atributo de subclasse (nomes repetidos)" Exception
Classe 108 "Incompatibilidade: superclasses diferentes" Exception 116 "Incompatibilidade: superclasses diferentes" Exception 348 "Nao é possível alterar a condição \"externo\" da classe sob edição" Exception 373 "Impossibilidade de determinar subclasses de: \"" + this.name() + "\"." Exception 379 "Impossibilidade de determinar subclasses de: \""+ this.name() + "\"." Exception 400 "Impossibilidade de determinar subclasses de: \"" + this.name() + "\"." Exception 406 "Impossibilidade de determinar subclasses de: \"" + this.name() + "\": especificação indefinida." Exception
Heranca 216 "Inconsitência: uma classe não pode ser subclasse dela mesma" Exception 262 "Impossível colar herança: ausência de classe(s) envolvidas no diagrama." Método não é chamado em lugar algum.
Considerar exclusão ou ignorar. 478 "Não é permitido looping de herança." Exception
Mensagem 193 "Tentativa frustrada de troca de origem de mensagem." Exception 198 "O método originalmente invocado torna-se inacessível. Para que seja efetuado este transporte é
necessário remover o método invocado (editar mensagem)" Exception
273 "É necessário selecionar o objeto (ou componente) em que a mensagem será colada." Método não é chamado em lugar algum. Considerar exclusão ou ignorar.
MethodParameter 124 "É necessário selecionar o método em que o parâmetro será colado." Método não é chamado em lugar algum.
Considerar exclusão ou ignorar. MethodTemporaryVariable
131 "É necessário selecionar o método em que a variável será colada." Método não é chamado em lugar algum. Considerar exclusão ou ignorar.
Metodo 262 "É necessário selecionar a classe em que o método será colado." Método não é chamado em lugar algum.
Considerar exclusão ou ignorar. Transition
70
129 "A versão atual não admite moving que produza transições com origem e destino coincidentes" Exception ActivityDiagramEditor
110 "Não existe nenhum use case que possa ser incluído no activity diagram. (novos use cases só podem ser ciados no use case diagram)"
Exception
ScenarioDrawing 653 "Procedimento de edição inconsistente: não é permitido looping de mensagens" Exception
ScenarioEditor 794 "O cenário sob edição já possui uma mensagem inicial." Não alterar
StateFigure 146 e.getMessage() Exception 151 "Não é permitido alterar o documento" Exception
Cenario 171 "O metodo de inversão de blocos de mensagens exige continuidade." Exception
DCM 103 "É necessário que exista pelo menos uma Classe criada na especificação." Exception 123 "Não pode ser criado um diagrama de corpo de método para a classe "+ auxClass.name() + " que é
externa." Exception
145 "É necessário que exista pelo menos um Método na Classe selecionada." Exception 191 "Já existe um diagrama de corpo de método para o método " + auxMethod.name() Exception 383 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 456 "Seleção de statements mal feita, na chamada de removeLacksFrom: de DCM." Exception
DTE 221 "É necessário que exista pelo menos uma Classe criada na especificação." Exception 242 "Não pode ser criado um diagrama de transição de estados para a classe " + auxClass.name() + " que é
externa." Exception
264 "Já existe um diagrama de transição de estados para a classe " + auxClass.name() Exception PatternSpecificationAnalyser
55 "Encontrado erro na especificação que impossibilita que ela seja salva como padrão.\nFechar a especificação corrente, sem salvar."
Não alterar (fora do escopo)
64 "Encontrado erro na especificação que impossibilita que ela seja salva como padrão.\nFechar a especificação corrente, sem salvar."
Não alterar (fora do escopo)
PatternTestTool 46 "Não é possível proceder a inclusão do padrão selecionado na especificação corrente.\nConsultar
relatório da análise (c:\\visual\\sea\\checking\\testpatt.chk)." Não alterar (fora do escopo)
132 "Não é possível proceder a inclusão do padrão selecionado na especificação corrente.\nConsultar relatório da análise (c:\\visual\\sea\\checking\\testpatt.chk)."
Não alterar (fora do escopo)
71
139 "É possível proceder a inclusão do padrão selecionado na especificação corrente." Não alterar (fora do escopo) SEAPreceptorAnalyser
381 "Encontrado erro na especificação analisada, com respeito às restrições impostas pelo framework." Não alterar (fora do escopo) 386 "Fim do procedimento de análise. Especificação fiel às restrições impostas pelo framework." Não alterar (fora do escopo) 453 "Especificação corrente não é um framework e nem foi desenvolvida sob um framework." Não alterar (fora do escopo) 468 "Especificação corrente não é um framework e nem foi desenvolvida sob um framework." Não alterar (fora do escopo) 476 "Não identificado um framework superior" Não alterar (fora do escopo) 501 "Não foi selecionado um framework." Não alterar (fora do escopo) 509 "Não identificado um framework superior" Não alterar (fora do escopo) 544 "Especificação corrente não é um framework e nem foi desenvolvida sob um framework." Não alterar (fora do escopo) 553 "Não identificado um framework superior" Não alterar (fora do escopo) 579 "Não foi selecionado um framework." Não alterar (fora do escopo) 587 "Não identificado um framework superior" Não alterar (fora do escopo)
1293 "Encontrado erro na especificação analisada, com respeito às restrições impostas pelo framework." Não alterar (fora do escopo) 1298 "Fim do procedimento de análise. Especificação fiel às restrições impostas pelo framework." Não alterar (fora do escopo)
SEAPreceptorBuilderTool 65 "É recomendável salvar a especificação agora." Não alterar (fora do escopo)
143 "Não há alterações que possam ser feitas por SEA-Preceptor sobre a classe" + handledClass.name() + " ou sobre modelos e conceitos a ela associados"
Não alterar (fora do escopo)
202 "Ainda não é possível concluir a especificação corrente. Ver relatório da análise." Não alterar (fora do escopo) 241 "Nome de classe existente. Escolher outro nome." Não alterar (fora do escopo) 292 "Nome de documento existente. Escolher outro nome." Não alterar (fora do escopo) 337 "Erro ao tentar salvar a especificação." Não alterar (fora do escopo) 346 "Já existe uma especificação sendo construída." Não alterar (fora do escopo)
SEAPreceptorHyperdocument 74 Não alterar (fora do escopo) Não alterar (fora do escopo) 98 Não alterar (fora do escopo) Não alterar (fora do escopo)
113 Não alterar (fora do escopo) Não alterar (fora do escopo) StateAdapterTool
461 "Selecionados métodos incompatíveis:" + mensagem A variável mensagem pode receber os seguintes valores: "\n- métodos com tipos de retorno incompatíveis" ou "\n- métodos com tipos de retorno incompatíveis"
Não alterar (fora do escopo)
AccessMethodGeneratorTool 117 "A classe " + currentClass.name() possui atributo(s) não tipado(s).\nDefinir tipagem de todos os atributos
antes de ativar esta ferramenta." Não alterar (fora do escopo)
284 "Não é permitido alterar a especificação" Não alterar (fora do escopo)
72
346 "Não é permitido alterar a especificação" Não alterar (fora do escopo) AggregationRepairerTool
102 "Correção já executada. \"Close\" produz retorno ao procedimento de verificação de consistência." Não alterar (fora do escopo) ClassMovingAnalyser
50 "Não é possível proceder a transferêcia. Consultar relatório da análise (" + fileName + ".chk)." Não alterar (fora do escopo) 87 "Não é possível proceder a transferêcia. Consultar relatório da análise (" + fileName + ".chk)." Não alterar (fora do escopo)
ClassMovingToHigherFrameworkTool 431 "Não é possível proceder a transferência. \nSuperclasse da classe selecionada deve pertencer à
especificação pai, que deve ser um framework." Não alterar (fora do escopo)
622 "Não é possível proceder a transferência.\nSuperclasse da classe selecionada deve pertencer à especificação pai, que deve ser um framework."
Não alterar (fora do escopo)
634 "O procedimento de tranferência é possível, porém a análise produziu advertências, registradas no relatório da análise."
Não alterar (fora do escopo)
641 "O procedimento de tranferência é possível, sem restrições registradas no relatório da análise." Não alterar (fora do escopo) DCMExternalStatementGeneratorTool
204 "O modelo sob edição possui statements \"external\"." Não alterar (fora do escopo) 209 "O modelo sob edição não possui statements \"external\"." Não alterar (fora do escopo) 215 "Para a ferramenta atuar o documento corrente deve ser um diagrama de corpo de método." Não alterar (fora do escopo) 380 "Início do procedimento de geração de DTEExternalStatements." Não alterar (fora do escopo) 441 "Para a ferramenta atuar o documento corrente deve ser um diagrama de corpo de método." Não alterar (fora do escopo) 467 "Início do procedimento de geração de ScenarioExternalStatements." Não alterar (fora do escopo)
GroupAccessMethodGeneratorTool 244 "Ocorreu a seleção de atributo(s) não tipado(s). \nDefinir tipagem de todos os atributos selecionados
antes de ativar esta ferramenta." Não alterar (fora do escopo)
427 "Não é permitido alterar a especificação" Não alterar (fora do escopo) 514 "Não é permitido alterar a especificação" Não alterar (fora do escopo)
MBDConsistenceRepairerTool 1118 "Correção já executada. \"Close\" produz retorno ao procedimento de verificação de consistência." Não alterar (fora do escopo) 1191 "A ferramenta de correção não conseguiu determinar os statements a serem alterados" Não alterar (fora do escopo) 1233 "A ferramenta de correção não conseguiu determinar as mensagens a serem removidas" Não alterar (fora do escopo) 1256 "A ferramenta de correção não conseguiu definir os statements a incluir" Não alterar (fora do escopo) 1298 "A ferramenta de correção não conseguiu determinar os statements a serem removidos" Não alterar (fora do escopo) 1320 "A ferramenta de correção não conseguiu definir os statements a incluir" Não alterar (fora do escopo)
MessageRefinementRepairerTool 109 "Correção já executada. \"Close\" produz retorno ao procedimento de verificação de consistência." Não alterar (fora do escopo)
ModelCopyTool
73
32 "Procedimento de cópia de modelo (abstrato) não sobreposto na subclasse." Não alterar (fora do escopo) SEASpecificationAnalyser
85 "Encontrado erro de consistência na especificação." Não alterar (fora do escopo) 91 "Fim do procedimento de análise. Especificação validada." Não alterar (fora do escopo)
SmalltalkCodeGenerator 870 "Fim do procedimento de tradução." Não alterar (fora do escopo) 875 "Especificação corrente não validada ainda. Proceder checagem de consistência antes da geração de
código" Não alterar (fora do escopo)
882 "Nome de arquivo inválido." Não alterar (fora do escopo) Sea
138 "Nao é permitido alterar o documento" Exception 188 "document frozen" Exception 193 "just consistent documents can be frozen" Exception 355 "Opção ainda não implementada." UnsupportedOperationException: "Ainda não
implementado." 573 "Nome de padrão existente. Escolher outro nome." Exception 599 "Não é permitido alterar o documento" Exception 683 "impossible to unfreeze: document belongs to a frozen specification" Exception 689 "document unfrozen" Exception 694 "current document is not frozen" Exception
Concept 82 "Problamas ao criar o objeto (Concept) de referencia." Exception 92 "Ha uma (nova) subclasse de conceito sem a redefinicao do metodo \"conceptName\". " Exception
130 "Problamas ao criar o objeto (Concept) de referencia." Exception 383 "Não é possível remover um componente que não esteja diretamente agregado ao componente sob
edição." Exception
ConceptRepository 95 "Tentativa de alteração resultou em duplicidade com outro componente" Exception
765 "tentativa de alteração inconsistente" Exception 783 "tentativa de alteração inconsistente" Exception 900 "Incompatibilidade verificada em conceito(s) dependente(s) do conceito sob alteração." Exception 918 "Incompatibilidade verificada em conceito(s) dependente(s) do conceito sob alteração." Exception
ConceptualModel 74 "Problamas ao criar o objeto (ConceptualModel) de referencia." Exception
121 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 262 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception
74
306 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 349 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 393 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 438 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 591 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 646 "Impossibilidade de colar componente do tipo \"\" , aComponent.getClass().specificationElementName()
, \"\" no modelo sob edição." Exception
658 "Impossibilidade de proceder colagem no modelo sob edição." Exception 707 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception 950 "Não é possível incluir o mesmo componente mais de uma vez em um modelo." Exception
EnvironmentManager 262 "Opção não implementada." UnsupportedOperationException: "Ainda não
implementado." 535 "Selecionar somente um item a ser removido da especificação." Exception 874 "Impossível ir para link: seleção múltipla de elementos" Exception 955 "Documento apontado não encontrado. Atualizar o link ativado." Exception 961 "Documento apontado não encontrado. Atualizar o link ativado." Exception 985 "Nenhum documento selecionado" Exception
1258 "Inconsistência: opção por vinculação a documento(s) sem sua definição" Exception 1270 "Opção ainda não implementada." UnsupportedOperationException: "Ainda não
implementado." 1380 "O conteúdo do clipboard não pode ser inserido no documento sob edição." Exception 1455 "O conteúdo do clipboard não pode ser inserido no documento sob edição." Exception 1515 "O conteúdo do clipboard não pode ser inserido no documento sob edição." Exception 1602 "ERRO: EnvironmentManager/removeSelection(): \nOcorreu a tentativa de remoção de uma lista onde o
documento corrente não é ConceptualModel" Exception
1628 "Selecionar somente um item a ser removido da especificação." Exception 1637 "Erro: Elemento selecionado não compatível para remover." Exception 1651 "ERRO: EnvironmentManager/removeSelection(): \nOcorreu a tentativa de remoção de uma lista onde o
documento corrente não é ConceptualModel" Exception
1750 "Não é permitido alterar o documento" Exception OceanDocument
139 "Nada a remover." Exception Specification
271 "Especificação mal elaborada: mais de uma classe para o mesmo conceito" Exception 557 "Já existe um documento com o nome \"" + docName + "\" " Exception
75
575 "Não é permitido alterar o documento" Exception 641 "Já existe um documento com o nome \"" + docName + "\"" Exception 659 "Não é permitido alterar o documento" Exception 725 "Já existe um documento com o nome \"" + docName + "\"" Exception 743 "Não é permitido alterar o documento" Exception 796 "Não é possível alterar o documento" Exception
SpecificationElement 121 "Problamas ao criar o objeto (SpecificationElement)" + " de referencia." Exception 277 "ERRO: SpecificationElement/elementFromMainList(Object):\nTipo do elemento não não esperado." Exception
SpecificationElementHolder 182 "Uma especificação pode conter apenas um(a) " + name() Exception 301 "Nada a remover." Exception
jhotdraw.SpecificationDrawing 28 "Método \"createFigureFor:\" não implementado em " + this.getClass().getName() UnsupportedOperationException: "Ainda não
implementado." ModelAnalyser
86 "Modelo sem erros." Não alterar (fora do escopo) 92 "Documento corrente não é do tipo de modelo que a ferramenta analisa." Não alterar (fora do escopo)
SpecificationAnalyser 84 "Fim do procedimento de análise. Especificação validada." Não alterar (fora do escopo)
object_diagram.Dependency 1250 "Não existe dependências com apenas uma classe." Exception
8.2 Anexo 2 – Tabela com ocorrências do JOptionPane para solicitação de valores
Tabela 2: Ocorrências do JOptionPane para solicitação de valores
Linha Mensagem Tipo de Valor Esperado FileStoreManager
155 "Deseja substituir o arquivo?" Booleano (Botões Sim/Não) OceanFileManager
51 "All right to overwrite the existing file?" Booleano (Botões Sim/Não) 92 "All right to overwrite the existing file?" Booleano (Botões Sim/Não)
Atributo 150 "O transporte deste componente " + this.conceptName() + " para " + Booleano (Botões Sim/Não)
76
aTargetComponent.conceptName() + " " + aTargetComponent.name() + " provocará a perda e referência ao componente movido, em outras pertes da especificação sob edição. Situações de perda de referência:" + auxString + "Deseja mover o componente mesmo assim ?"
Mensagem 178 "Deseja substituir o metodo invocado por um outro equivalente (mesmo nome e mesma
quantidade de parâmetros) ?" Booleano (Botões Sim/Não) Metodo
135 "O transporte deste componente " + this.conceptName() + " para " + aTargetComponent.conceptName() + " " + aTargetComponent.name() + " provocará a perda de referência ao componente movido, em outras pertes da especificação sob edição.\nSituações de perda de referência:" + auxString + "\nDeseja mover o componente mesmo assim ?" Booleano (Botões Sim/Não)
Type 49 "Novo tipo está associado a uma classe ?" Booleano (Botões Sim/Não)
ActivityDiagramEditor 83 "Selecionar use case não incluído no activity diagram." String (O usuário deve selecionar entre uma lista de nomes de casos de
uso) classDiagram.MObjLineFigure
54 "Defina a cardinalidade da classe origem." String (Um dos seguintes valores: "1", "0..1", "0..*", "*", "1..*") 62 "Defina a cardinalidade da classe destino." String (Um dos seguintes valores: "1", "0..1", "0..*", "*", "1..*") 87 "Defina o nome da associação." String (Um nome qualquer)
ScenarioCombinedFragmentWithDivisionFigure 504 I18NProperties.getString("condition.value") = "Digite a condição:" ? 577 I18NProperties.getString("condition.value") = "Digite a condição:" ?
ScenarioCombinedFragmentWithoutDivisionFigure 85 I18NProperties.getString("condition.value") = "Digite a condição:" ?
ScenarioMessageConnectionFigure 260 "Defina o nome do método destino." String (Um nome qualquer)
DCM 110 "Novo DCM está associado a um método de que classe ?" String (O usuário deve selecionar entre uma lista de nomes de classes) 166 "Novo DCM está associado a que método?" String (O usuário deve selecionar entre uma lista de nomes de
métodos) DTE
221 "Novo DTE está associado a que classe ?" String (O usuário deve selecionar entre uma lista de nomes de classes) PatternSpecificationAnalyser
77
374
"A análise verificou a existência de " + messageString + ", o que não deve estar presente em uma especificação de \nDeseja remover" + messageString + " para possibilitar a o prosseguimento do processo?" Booleano (Botões Sim/Não/Cancelar)
PatternTestTool
46 "Não é possível proceder a inclusão do padrão selecionado na especificação corrente.\nConsultar relatório da análise (c:\\visual\\sea\\checking\\testpatt.chk)."
132 "Não é possível proceder a inclusão do padrão selecionado na especificação corrente.\nConsultar relatório da análise (c:\\visual\\sea\\checking\\testpatt.chk)."
139 "É possível proceder a inclusão do padrão selecionado na especificação corrente." SEAPreceptorAnalyser
236 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (A localização de um arquivo) 482 "Avaliar especificação em função de que framework ?" String (O nome de uma especificação)
526
"A especificação corrente é um framework, porém foi desenvolvida sob outro(s) framework(s).\nDeseja testar a compatibilidade do framework corrente com as restrições de um framework superior?" Booleano (Botões Sim/Não)
560 "Avaliar especificação em função de que framework ?" String (O nome de uma especificação) 610 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (Um nome qualquer)
SEAPreceptorBuilderTool 62 "A especificação " + this.newSpecification().name() + " já satisfaz as restrições
estabelecidas pelo framework " + this.framework().name() + ". Deseja desvinculá-la do hiperdocumento agora?" Booleano (Botões Sim/Não)
89 "O procedimento a seguir poderá criar métodos e modelos associados à classe " + handledClass.name() + ". Deseja fazer isto agora?" Booleano (Botões Sim/Não)
97 "Deseja criar um statechart associado à classe " + handledClass.name() + "?" Booleano (Botões Sim/Não) 460 "Já existe subclasse de " + aClassName + " na especificação tratada. É possível criar
uma nova subclasse ou tratar uma subclasse existente. Deseja criar nova subclasse de " + aClassName + "?" Booleano (Botões Sim/Não)
484 "Tratar qual subclasse de " + aClassName + "?" String (O usuário deve selecionar entre uma lista de nomes de classes) 1246 "Deseja criar um cenário que refine o método " + overridingMethod.name() +
overridingMethod.nameComplement() + "?" Booleano (Botões Sim/Não) StateTestTool
127 "A classe " + targetClientClass.name() + " associada à classe SEAClientClass do padrão State não possui um método template, sem corpo definido, a que possa ser associado o método request, cujo comportamento muda em função do estado. Se o procedimento de implantação do padrão State prosseguir, será criado um método denominado request na classe " + targetClientClass.name() + ". Deseja prosseguir nestas condições?" Booleano (Botões Sim/Não/Cancelar)
182 "A classe " + targetStateClass.name() + " associada à classe SEAState do padrão State Booleano (Botões Sim/Não/Cancelar)
78
não possui um método abstrato a que possa ser associado o método stateMethod, cujo comportamento é definido nas subclasses. Se o procedimento de implantação do padrão State prosseguir, será criado um método denominado stateMethod na classe " + targetStateClass.name() + ". Deseja prosseguir nestas condições?"
AggregationRepairerTool 118 Uma das seguintes:
- "Iniciar procedimento?" - "Iniciar procedimento de substituição?" - "Iniciar procedimento de remoção?" Booleano (Botões Sim/Não)
ClassMovingAnalyser 72 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (A localização de um arquivo)
115 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (A localização de um arquivo) 140 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (A localização de um arquivo)
ClassMovingToHigherFrameworkTool 445 "A análise produziu advertências, registradas no relatório da análise.\n Deseja continuar
o procedimento de tranferência mesmo assim?" Booleano (Botões Sim/Não) 524 "Transferir classe para que framework ?" String (O usuário deve selecionar entre uma lista de nomes
deespecificações) MBDConsistenceRepairerTool
855 "Enviar mensagem (que invoca o método " + statementAtKey.calledMethod().name() + ") para que objeto do cenário?" Booleano (Botões Sim/Não)
1124 "Iniciar procedimento?" Booleano (Botões Sim/Não) MessageRefinementRepairerTool
115 "Iniciar procedimento de remoção?" Booleano (Botões Sim/Não) SEASpecificationAnalyser
137 "Encontrado erro no modelo " + aModel.specificationElementName() + ": " + aModel.name() + ". Deseja prosseguir?" Booleano (Botões Sim/Não/Cancelar)
SmalltalkCodeGenerator 797 "Qual o nome do arquivo que conterá o código gerado?" String (A localização de um arquivo)
Sea 123 "Esta ação eliminará a especificação corrente. Deseja prosseguir?" Booleano (Botões Sim/Não) 352 "Deseja ser orientado pelo hiperdocumento do framework?" Booleano (Botões Sim/Não)
EnvironmentManager 1267 "Deseja ser orientado pelo hiperdocumento do framework?" Booleano (Botões Sim/Não)
SpecificationAnalyser 49 "Qual o nome do arquivo em que será armazenado o resultado da análise?" String (A localização de um arquivo)
79
76 "Encontrado erro de consitência da especificação (de compatibilidade entre modelos)." Nenhum
132 "Encontrado erro no modelo" + aModel.specificationElementName() + ": " + aModel.name() + ". Deseja prosseguir?" Booleano (Botões Sim/Não)
80
8.3 Anexo 3 - Artigo
Refatoração do framework OCEAN para desacoplamento de especificidades de interface
Andrey Morais Brüggemann1
Orientador: Ademir Coelho
Co-orientador: Ricardo Pereira e Silva, Dr.
Departamento de Informática e Estatística
Universidade Federal de Santa Catarina (UFSC) Florianópolis – SC - Brasil
2010
Abstract. As a project changes, the quality of your code and design tend to decrease, causing problems such as duplication and lack of clarity. The OCEAN framework supports the creation of software development environments that handle project specifications. Since its inception, this framework has undergone several changes, highlighting its porting from SmallTalk to Java. This paper describes the refactoring of the OCEAN framework to promote the decoupling between the GUI and its model classes.
Resumo. À medida que um software sofre alterações, a qualidade de seu código e projeto tende a diminuir, apresentando problemas como duplicidade e falta de clareza. O framework OCEAN suporta a criação de ambientes de desenvolvimento de software que manipulam especificações de projeto. Desde a sua criação, este framework passou por diversas modificações, destacando a sua recodificação de SmallTalk para Java. Este documento descreve a refatoração do framework OCEAN, a fim de reduzir o acoplamento entre sua interface gráfica e suas classes de modelo.
1. Introdução
A engenharia de software aplica disciplinas da engenharia no desenvolvimento de software, através de métodos, ferramentas e procedimentos que tornam o processo gerenciável. A reusabilidade é uma das características de qualidade. Um software de alta qualidade deve ser projetado e codificado de forma que possa ser utilizado na construção de outros softwares.
Um framework é um conjunto de classes que agregam soluções de projeto para um domínio de problemas. Ele estende o reuso das linguagens orientadas à objetos definindo um esqueleto para a construção de uma aplicação ou parte de uma.
O OCEAN é um framework criado para dar suporte à criação de ambientes de desenvolvimento de sistemas baseados em notação de alto nível, com ênfase em notação gráfica. Este framework passou por diversas manutenções, em grande parte para
81
1. Introdução
A engenharia de software aplica disciplinas da engenharia no desenvolvimento de software, através de métodos, ferramentas e procedimentos que tornam o processo gerenciável. A reusabilidade é uma das características de qualidade. Um software de alta qualidade deve ser projetado e codificado de forma que possa ser utilizado na construção de outros softwares.
Um framework é um conjunto de classes que agregam soluções de projeto para um domínio de problemas. Ele estende o reuso das linguagens orientadas à objetos definindo um esqueleto para a construção de uma aplicação ou parte de uma.
O OCEAN é um framework criado para dar suporte à criação de ambientes de desenvolvimento de sistemas baseados em notação de alto nível, com ênfase em notação gráfica. Este framework passou por diversas manutenções, em grande parte para acrescentar funcionalidades. Em 2007, passou por uma migração da linguagem SmallTalk, com a qual foi originalmente implementado, para Java.
Ao longo de tantas alterações, muitos problemas se acumularam no código fonte. A escassez de documentação aliada à falta de controle sobre a maneira como as manutenções foram feitas, são fatores que tornaram propício o surgimento de falhas de projeto e de implementação.
Entre as falhas de projeto que dificultam o crescimento e continuidade do framework está o acoplamento existente entre as classes de modelo e classes de interface gráfica de usuário. O trabalho consistiu na identificação dos pontos do framework onde se apresentava este tipo de acoplamento e na redução de tal acoplamento através da realização de refatorações no código do OCEAN.
2. Frameworks
O reuso de artefatos de software existentes é uma maneira de se reduzir o custo de desenvolvimento de software. Pode-se reusar produtos de diferentes fases do desenvolvimento, desde requisitos e casos de uso, até o projeto e o código.
Os frameworks utilizam as características da orientação a objetos, como polimorfismo e herança, para promover o reuso de projeto e de código. São compostos por uma série de classes, abstratas e concretas, que constituem um projeto abstrato para um domínio de aplicação.
Os frameworks impõem uma estrutura às suas aplicações, pois especificam a maneira como suas classes interagem, o que propicia a reutilização do projeto do framework.
É responsabilidade do framework chamar suas extensões. As subclasses criadas pelo desenvolvedor são chamadas pelo framework. Esta característica dos frameworks é nomeada inversão de controle, ou Princípio de Hollywood
82
2.1. Classificação
De acordo com o seu uso, os frameworks são classificados em caixa-branca, caixa-preta e caixa-cinza. Os de caixa-branca são usados através da criação de subclasses das sua classes abstratas para adicionar comportamento específico da aplicação (Johnson, et al., 1988). Os frameworks de caixa-preta fornecem componentes prontos para serem usados através de composição, na forma de classes concretas. Os frameworks de caixa-cinza aliam a flexibilidade dos de caixa-branca à facilidade de uso dos de caixa-preta, fornecendo ao mesmo tempo classes para serem estendidas e classes concretas, para serem usadas através de composição.
Quanto ao domínio de problema a qual o framework se destina, este pode ser de infra-estrutura de sistema, de integração ou de aplicação. Os de infra-estrutura são utilizados no desenvolvimento de software básico, como sistemas operacionais e driversde dispositivos. Os frameworks de integração facilitam a modularização, reuso e extensão da infra-estrutura da aplicação destinada ao ambiente distribuído. Frameworks de aplicação encapsulam o conhecimento a respeito de um domínio de particular de problema, sendo utilizados no desenvolvimento de sistema destinados aos clientes (Fayad, et al., 1997).
2.2. Benefícios do uso de frameworks
O uso de um framework pode trazer diversos benefícios a uma aplicação, suportados pelas suas características de modularidade, reusabilidade, extensibilidade e robustez.
A modularidade consiste na capacidade que os frameworks têm de isolar da aplicação os detalhes de sua implementação. A aplicação utiliza apenas a interface pública do framework, que geralmente não sofre grandes alterações.
Os frameworks estendem as características de reusabilidade provida pelas linguagens OO, fornecendo o reuso de código fonte e projeto através de componentes genéricos que podem ser usados na construção de novas aplicações com maior qualidade e menos esforço.
A extensibilidade é a capacidade de o framework aumentar as suas funcionalidades, ou seja, refere-se à capacidade do framework de se adaptar. Esta característica assegura as adaptações de comportamentos genéricos e características de um domínio de aplicações a uma nova específica aplicação desenvolvida com base no framework.
Quanto mais aplicações usam o framework, mais robusto este tende a ficar, e conseqüentemente as aplicações que o utilizam também. Isto porque o código e estrutura do framework são freqüentemente testados, corrigidos e melhorados ao longo do seu uso na construção de aplicações, tornando o framework bastante confiável.
2.3. Desvantagens dos frameworks
Os frameworks geralmente são componentes com alto nível de abstração. Apesar de ser esta característica a fonte das vantagens de se usar um framework, é também a principal causa da complexidade de seu aprendizado, uso e desenvolvimento.
83
Entender como usar um framework pode não ser algo trivial. Para usar um framework de caixa branca, é preciso conhecer as classes abstratas para saber como as subclasses devem ser implementadas. Mesmo o uso dos de caixa-preta envolve aprender a interface dos componentes que o framework dispõe.
A ausência de um padrão estabelecido para documentação de frameworksdificulta seu aprendizado (Johnson, 1997). Na documentação é utilizada linguagem textual, que nem sempre é interpretada corretamente.
A inversão de controle muitas vezes atrapalha a depuração da aplicação que usa framework e torna difícil descobrir se um erro identificado está presente no código da aplicação ou do framework.
Os frameworks são desenvolvidos com foco na extensibilidade e não na integração com outros frameworks, o que dificulta o uso de diferentes frameworks numa mesma aplicação.
O desenvolvimento de frameworks é uma tarefa complexa, que envolve analisar o domínio alvo e criar as abstrações de modo a atender adequadamente as aplicações. Após desenvolvido, manter um framework exige um grande cuidado nas mudanças do projeto e principalmente da interface pública do framework, para que as aplicações que o utilizam não sejam prejudicadas.
3. O Framework OCEAN
O OCEAN é um framework, criado para dar suporte à criação de ambientes de desenvolvimento de sistemas baseados em notação de alto nível, com ênfase em notação gráfica. Surgiu como um dos resultados do desenvolvimento do SEA, um ambiente que suporta o desenvolvimento e uso de frameworks, componentes e aplicações. Entretanto, o OCEAN suporta o desenvolvimento de ambientes em geral, não se limitando a ambientes relacionados a frameworks e componentes (Silva, 2000).
Tanto o ambiente SEA quanto com o OCEAN, passaram por uma migração para a linguagem Java, feita por João Amorim (Amorim, 2006), Ademir Coelho (Coelho, 2007) e Thiago Machado (Machado, 2007). O SEA foi utilizado para validar o resultado da recodificação (Coelho, 2007) do OCEAN. Posteriormente, o SEA também teve acrescentada a possibilidade de representar especificações usando diagramas da UML 2 (Vargas, 2008).
A migração de SmallTalk para Java não foi simplesmente uma conversão de código fonte. Várias adaptações no projeto original do OCEAN tiveram de ser feitas, por conta das diferenças entre as duas linguagens. Também o framework HotDraw foi substituído pelo JHotDraw (Amorim, 2006) na construção dos editores de diagramas, além de ter sido construída uma nova estrutura de interface gráfica com o uso do framework JFC Swing (Machado, 2007).
3.1. Estrutura
As principais características de um ambiente criado a partir do OCEAN são definas em uma subclasse concreta de EnvironmentManager. Nesta subclasse são definidos os tipos de especificação tratados, os mecanismos de visualização e edição associados a cada
84
modelo e ambiente, os mecanismos de armazenamento utilizados e as ferramentasutilizáveis para manipular especificações (Machado, 2007).
Figura 1: Classes de Ambiente do OCEAN
Ambientes desenvolvidos sob o framework OCEAN podem manipular diferentes formas de especificação de projetos. Cada tipo de especificação no framework OCEAN (subclasse de Specification) define quais os tipos de modelo(subclasse de ConceptualModel) e tipos de conceito (subclasse de Concept) válidos para aquela especificação, e cada modelo define quais os conceitos que pode tratar e os relacionamentos possíveis entre estes conceitos.
Figura 2: Estrutura básica de documentos do OCEAN
Uma mesma especificação pode conter vários modelos e pode estabelecer relacionamentos entre estes, na forma de links, associações de sustentação ou associações de referência. Esta interligação de elementos permite estabelecer relacionamentos e restrições entre os diagramas de uma especificação, bem como a validação da consistência de uma especificação.
3.2. Funcionalidades
Sendo um framework de caixa-cinza, o OCEAN oferece várias funcionalidades prontas para serem utilizadas em novas aplicações.
Entre as funcionalidades está suporte à especificações orientadas a objetos, produzidas a partir de diagramas em notação UML ou UML 2 (Vargas, 2008). Os diagramas UML do OCEAN são sobrecarregados para suportar a representação dos pontos flexíveis de um framework.
O OCEAN ainda fornece um mecanismo de persistência que suporta mais do que um formato de armazenamento ao mesmo tempo, possibilitando que as especificações sejam armazenadas em diferentes mecanismos de persistência, como banco de dados ou arquivo.
85
4. Refatoração
Refatoração é um conjunto de alterações do código fonte de um software buscando melhorar sua estrutura sem adicionar novas funcionalidades. Usando refatoração é possível fazer alterações no código de maneira que este permaneça bom ou até melhore(Fowler, 2004), evitando a deterioração do código fonte durrante a realização de manutenções.
Estas modificações foram catalogadas por Fowler em seu livro (Fowler, 2004),onde é mostrado como executar refatoração de maneira controlada e eficiente, de modo que não introduza erros no código, melhorando de maneira metódica a estrutura.
4.1. Processo de refatoração
A proposta da refatoração é que as alterações de código sejam feitas em pequenos passos e de maneira disciplinada, para diminuir as chances de falha e para que mesmo as que surgirem sejam fáceis de identificar (Fowler, 2004).
Os passos envolvidos no processo de refatoração são:
1. Criar um conjunto de testes para o trecho de código a ser refatorado.
2. Identificar os pontos a serem alterados e as refatorações necessárias.
3. Refatorar, isto é, executar as refatorações. Neste momento também devem ser feitas as alterações nos testes caso haja necessidade.
4. Testar o código alterado, para verificar se o seu comportamento continua como era antes das alterações.
5. Efetuar as correções necessárias, ou reverter as refatorações feitas, caso o código não tenha passado em todos os testes.
6. Retornar ao passo dois até que não haja mais refatorações a serem feitas.
Definir de quando as refatorações devem ser feitas é um ponto importante. A refatoração não deve ser uma atividade dentro de um planejamento e sim uma parte, ou conseqüência, de uma atividade onde refatorar é útil (Fowler, 2004). Momentos em que é propícia a aplicação de refatoração seriam durante a adição de funcionalidade, correção de falhas ou ao longo da revisão de código.
4.2. Maus cheiros
Os maus cheiros são problemas tipicamente presentes em um código ruim e indicam os pontos do código onde existe a necessidade de refatoração (Fowler, 2004). Código duplicado, Método longo e Classe grande são exemplos de maus cheiros.
4.3. Ferramentas de auxílio à refatoração
A execução de refatoração pode ser auxiliada pelo uso de ferramentas. Verificadores estáticos auxiliam na descoberta das porções de código onde deve-se aplicar refatoração. Por sua vez os, testes de unidade são a ferramenta usada para validar a refatoração, indicando se a aplicação da refatoração fez surgirem falhas na porção de código refatorado.
86
Os ambientes de desenvolvimento com suporte a refatorações automatizadas, como o Eclipse JDT, também ajudam no sentido se diminuir a quantidade de tarefas repetitivas além de reduzir a chance de introdução de falhas ao longo da aplicação de uma refatoração.
4.4. Vantagens do uso de refatoração
O uso de refatoração evita a deterioração do projeto do software, ou seja, o desencontro entre o que está projetado e o que se tem implementado. A manutenção do código refatorado é facilitada, pela eliminação de trechos duplicados e pelo aumento da clarezado código.
A refatoração é também um meio de se aprender sobre o código. Ao longo do desenvolvimento dos testes de unidade são adquiridos conhecimentos a respeito do que o código faz. Isto também ajuda a encontrar falhas existentes no código, através do conhecimento adquirido a seu respeito durante as refatorações.
5. Refatoração do Framework OCEAN
Ao longo da migração para a linguagem Java, foram inseridos nas classes de modelo do OCEAN acoplamentos com as classes de interface gráfica, pertencentes ao framework JFC Swing.
A existência destes acoplamentos ia contra a abordagem MVC, com a qual sempre buscou-se manter alinhado o projeto do OCEAN, além de dificultarem a manutenção do framework. Neste contexto surgiu a refatoração como solução para melhorar a qualidade do projeto e código do OCEAN, mantendo suas funcionalidades.
A execução das refatorações foi centrada nas classes do núcleo do framework, principalmente na hierarquia de OceanDocument, mostrada na Erro! Fonte de referência não encontrada.. Entretanto, outras classes do framework também foram refatoradas.
A realização das refatorações foi feita com o auxílio do Eclipse JDT, que oferece uma série de refatorações automatizadas.
5.1. Remoção do acoplamento com JOptionPane
Uma grande quantidade das classes de modelo do OCEAN usavam o componente JOptionPane ou para exibir mensagens ou solicitar parâmetros ao usuário.
Para os casos onde o JOptionPane era usado para exibir mensagens, a solução adotada foi o uso de exceções. A estratégia adotada foi lançar uma exceção a partir da classe de modelo com a mensagem antes exibida pelo JOptionPane, deixando a cargo das classes de interface gráfica a captura da exceção e a exibição da mensagem via JOptionPane.
Algumas das mensagens exibidas via JOptionPane notificavam o usuário a respeito de um erro inesperado ocorrido durante a execução de um método. Nestes casos foram lançadas exceções não checadas. A refatoração para inclusão das exceções não checadas consistiu em alterar os algoritmos para lançar a exceção não checada com a mensagem que antes era exibida via JOptionPane e remover a chamada ao método showMessageDialog.
87
Nos casos em que a mensagem notificava um do domínio do OCEAN, como uma edição insistente de uma especificação, quando o JOptionPane deveria continuar sendo exibido ao usuário, foram adotadas as exceções checadas. As refatorações para inclusão das exceções checadas foram mais, pois foi necessária a alteração dos métodos clientes dos refatorados.
Basicamente, os passos envolvidos na substituição do JOptionPane pelo lançamento de exceções checadas, para cada método refatorado, foram:
1. Extrair todo o algoritmo do método refatorado para um novo, de nome
semelhante, usando a refatoração Extrair Método.
2. No novo método trocar a exibição do JOptionPane pelo lançamento de uma
exceção com uma mensagem igual. Capturar a exceção dentro método original,
exibindo um JOptionPane para mostrar a mensagem da exceção.
3. Aplicar Internalizar Método sobre o método refatorado em todas as classes que
o chamam.
4. Renomear o método novo para o mesmo nome que o método internalizado.
Nos casos em o JOptionPane era usado para solicitar parâmetros, o método onde era feita a chamado ao JOptionPane foi quebrado em dois, um primeiro com a chamada ao JOptionPane para solicitar o valor ao usuário e um segundo que recebe o valor obtido do usuário como parâmetro e executa o algoritmo do método original. Para isto era usada a refatoração Extrair Método.
5.2. Recuperação da estrutura de editores
ReferenceManager é uma das classes do núcleo do OCEAN e tem a responsabilidade de mapear cada tipo conceito e modelo ao seu respectivo mecanismo de edição e visualização. Na versão original do OCEAN esta classe era dependente de classes abstratas de editores.
Porém durante a redificação do OCEAN em Java, ReferenceManager passou a ficar acoplada às classes concretas de editores de diagramas, que são subclasses de JPanel, tornando ReferenceManager acoplada ao JFC Swing. Este acoplamento foi removido com o uso de refatorações. A figuras 3 e 4 mostram a estrutura de editores d OCEAN antes e após as refatorações, respectivamente.
Figura 1: Estrutura de editores original do OCEAN n a versão Java
88
Figura 1: Estrutura de editores após as refatoraçõe s
5.3. Outros problemas resolvidos
Além da execução de refatorações para remoção de acoplamentos com a interface gráfica, a substituição da classe OceanVector por Vector foi outra mudança feita no OCEAN com o uso de refatorações.
Além disso, ao longo da execução das refatorações, foram removidas várias porções de código duplicado, algoritmos foram reescritos para ficar mais claros e permitir o uso de refatoração, bem como foram eliminados métodos mortos, não usados nem estendidos em local algum.
Também foi iniciado o uso do da ferramenta Maven para controle do ciclo de vida e das dependências do OCEAN e a foi feita a substituição do framework log4j pelo SLF4J.
6. Considerações finais
Foi alcançada uma melhoria do projeto do framework OCEAN, passando a ter uma melhor divisão de responsabilidades entre suas classes de modelo e interface gráfica e uma redução no acoplamento entre o núcleo do OCEAN e o framework JFC Swing.
A adoção de exceções tornou possível separar o código de tratamento de erros do código comum. Também o uso da exceções não checadas, passa a tornar mais evidente o falhas no framework decorrentes de erros de programação.
Como efeitos colaterais do uso de refatoração obteve-se o aumento da clareza do código, com a reescrita de vários algoritmos bem como a remoção de duplicações de código, que diminuiu a quantidade de código do OCEAN a ser mantida.
Os benefícios conseqüentes do uso de técnicas de refatoração, resultaram numno código do framework OCEAN melhor estruturado, mais legível e mais fácil de ser mantido.
89
Referências Bibliográficas
Amorim, J. (2006). Integração dos frameworks JHotDraw e OCEAN para a produção de objetos visuais a partir do framework OCEAN. Tese de Graduação, Universidade Federal de Santa Catarina, Departameto de Informática e Estatística, Florianópolis.
Coelho, A. (2007). Reengenharia do framework OCEAN. Universidade Federal de Santa Catarina, Florianópolis.
Fayad, M., & Schmidt, D. C. (1997). Object-Oriented Application Frameworks. Special Issue on Object-Oriented Application Frameworks , 40.
Fowler, M. (2004). Refatoração - Aperfeiçoando o Projeto de Código Existente. (A. Fernandes, Trans.) Porto Alegre: Boookman.
Johnson, R. E. (1997, 2). Components, Frameworks, Patterns.
Johnson, R. E., & Foote, B. (1988). Disigning Reusable Classes. Journal of Object-Oriented Programming , 1, pp. 22-35.
Machado, T. A. (2007). Reengenharia da interface do ambiente SEA. Universidade Federal de Santa Catarina, Departamento de Informática e Estatística, Florianópolis.
Pressman, R. S. (1995). Engenharia de Software. (J. C. dos Santos, Trans.) São Paulo: Person Makron Books.
Silva, R. P. (2000). Suporte ao desenvolvimento e uso de frameworks e componentes.Tese de Doutorado, Universidade Federal do Rio Grande do Sul, Instituto de Informática, Porto Alegre.
Vargas, T. C. (2008). Suporte à Edição de UML 2 no Ambiente SEA. Tese de Mestrado, Universidade Federal de Santa Catarina, Departamento de Informática e Estatística, Florianópolis.