Desenvolvimento de Aplicações J2EE com UML e Rational Rose
À medida que as empresas procuram desenvolver software mais rapidamente, com
maior previsibilidade e com maior qualidade, a plataforma Java 2 Enterprise Edition
(J2EE) emerge como um standard para o desenvolvimento de aplicações empresariais.
Além de fornecer um paradigma completo para o desenvolvimento de aplicações
empresariais, o J2EE também ajuda a unir várias tecnologias herdadas do passado.
Os aspectos chave para o sucesso com o J2EE são os mesmos que para qualquer outra
plataforma de software complexa: comunicação eficiente dos requisitos, decisões correctas em
termos de análise e desenho, identificação das melhores opções de implementação. As
organizações que seguem as melhores práticas da modelação visual aceites pela indústria são
capazes de desenvolver software de forma mais rápida e de construir sistemas com maior
qualidade.
O que é a Unified Modeling Language (UML)?
A UML é um standard do Object Management Group (OMG) desde finais de 1997 e uma
linguagem gráfica para a modelação e desenvolvimento de sistemas de software. Fornece
suporte de modelação e visualização para todas as fases do desenvolvimento de software,
desde a análise dos requisitos até à especificação, passando ainda pela construção e pela
implementação.
A ideia central que está por detrás da utilização da UML para a modelação visual consiste na
identificação dos detalhes significativos sobre um sistema – por exemplo, se os requisitos para
o projecto são compreendidos de forma clara, se é desenvolvida a arquitectura da solução, ou
se uma dada implementação é identificada e construída de forma clara. Isto requer uma
notação rica para a modelação visual de sistemas de software.
A UML fornece essa notação para os blocos básicos em construção e disponibiliza formas de
expressar relações complexas entre esses blocos. Tais relações são expressas sob a forma de
diagramas UML.
Compreender os requisitos
Os projectos fracassam frequentemente porque os requisitos não foram bem compreendidos ou
comunicados. Na realidade, isto não é assim tão surpreendente, sobretudo se considerarmos
que qualquer linguagem – escrita ou oral – é ambígua e imprecisa por natureza. Desta forma,
podemos aplicar a modelação de casos de utilização (use cases) UML para desenvolver um
modelo preciso daquilo que é requerido ao sistema e, seguidamente, utilizar os casos de
utilização como base orientadora para outros aspectos do desenvolvimento do sistema
empresarial.
Na prática, um caso de utilização age como o fio que liga as pérolas de um colar. Os casos de
utilização estabelecem a ponte entre o utilizador final e os requisitos de um sistema. Podem,
portanto, ser utilizados para estabelecer o acompanhamento (traceability) entre os requisitos
funcionais e a própria implementação do sistema. Os casos de utilização servem ainda como
pontos de ligação para o documento de casos de utilização onde estão os detalhes dos
requisitos.
A Figura 1 mostra um diagrama parcial de casos de utilização para uma loja de CDs online,
resultante da transformação dos requisitos escritos e verbais para a funcionalidade esperada
em casos de utilização. Neste caso, é imediatamente óbvio que o comprador (representado
pela figura de um indivíduo, designado por actor na UML) pode utilizar o sistema de quatro
formas (representadas através de elipses, designadas como Casos de Utilização na UML).
Figura 1. Um diagrama simples de casos de utilização.
Por sua vez, cada caso de utilização é elaborado por meio de um ou mais cenários,
normalmente através de diagramas de sequência. Evidentemente, nesta fase inicial da recolha
e análise dos requisitos, os diagramas de sequência são relativamente simples e poderão estar
incompletos. Um exemplo deste tipo de diagramas de sequência é apresentado na Figura 2.
Figura 2. Um diagrama de sequência a ilustrar o caso de utilização checkout.
Desenhar uma solução
O passo seguinte – Análise do Caso de Utilização – fornece uma definição inicial e de alto nível
sobre a forma como é que os elementos internos interagem para satisfazer os requisitos
funcionais do sistema e como estão relacionados estaticamente entre si. Esta actividade pode
envolver muito trabalho de teste e erro até serem criadas soluções satisfatórias.
As “analysis classes” (classes de análise) – para as quais os comportamentos são
frequentemente descritos de forma abstracta utilizando linguagem natural – constituem uma
ferramenta útil para ser utilizada durante este tipo de análise. As classes de análise não estão
normalmente implementadas no software, embora possam estar. Em vez disso, são refinadas
mais tarde (durante o processo de desenho global) em classes de desenho e subsistemas
definidos de forma precisa.
Isto começa com a elaboração dos diagramas de sequência, de forma a revelarem os
mecanismos internos do sistema. Em vez de mostrar a interacção entre os actores e um
sistema monolítico, o sistema é dividido em objectos de nível de análise (analysis level objects).
As responsabilidades do sistema são divididas pelos objectos de nível de análise para se
alcançar um diagrama de sequência mais pormenorizado. São utilizados três tipos de objectos
de análise.
Objectos Boundary. Os objectos boundary representam todas as interacções entre os
mecanismos internos do sistema e aquilo que os rodeia. Estão aqui incluídas a interacção com
os utilizadores através de uma interface gráfica, as interacções com outros actores
(nomeadamente aqueles que representam outros sistemas), as comunicações com
dispositivos, etc. Os objectos boundary servem para isolar e proteger o resto do sistema de
preocupações externas. De uma forma geral, cada interacção entre um caso de utilização e um
actor é representada num objecto boundary.
Objectos Entity. Os objectos entity representam informação com significância para o sistema.
São normalmente persistentes e têm uma duração alargada. O seu propósito principal consiste
em representar e gerir informação dentro do sistema. Os conceitos chave dentro de um sistema
manifestam-se como objectos entidade no modelo.
Objectos Control. Os objectos control são utilizados para modelar comportamento dentro do
sistema. Estes objectos não implementam necessariamente o comportamento. Em vez disso,
podem funcionar com outros objectos para realizarem o comportamento do caso de utilização.
A ideia é separar o comportamento da informação subjacente associada ao modelo, fazendo
com que seja mais fácil lidar posteriormente com alterações em ambas as partes.
A UML disponibiliza a noção de estereótipo, representada sob a forma de texto entre aspas
duplas, para distinguir entre diferentes tipos de classes. No Rational Rose podem-se criar
facilmente classes de análise através da alteração do campo de estereótipo de classe para
<<boundary>>, <<entity>>e <<control>>, respectivamente. Isto pode ser depois utilizado como
base para a criação de diagramas de nível de análise.
A Figura 3 mostra uma versão actualizada do diagrama de sequência para o caso de utilização
checkout – desta vez com o sistema decomposto em objectos de análise. A figura utiliza a
representação icónica para os objectos fronteira, controlo e entidade (círculo com um T, círculo
com uma seta e círculo com uma linha tangencial, respectivamente).
Figura 3. Diagrama de sequência refinado com objectos de análise.
As classes participam frequentemente de vários casos de utilização e é importante
compreender as suas relações estáticas para assegurar consistência ao longo do sistema. O
diagrama de classes UML é útil para identificar as relações estáticas entre diferentes elementos
estruturais. O primeiro passo consiste em identificar e colocar num diagrama de classes todas
as classes que participam num caso de utilização.
Já se distribuiu o comportamento do caso de utilização aos objectos, pelo que é um exercício
relativamente simples criar operações de análise para as responsabilidades atribuídas a cada
uma. Convém sublinhar que se trata de operações de análise, o que significa que estas
operações precisarão provavelmente de evoluir à medida que continuamos com o nosso
trabalho de análise e desenho.
O Rational Rose permite-nos definir facilmente novas operações na classe de análise a partir
de diagramas de sequência. Para isso, basta seleccionar a mensagem existente e escolher
<new operation> no menu de contexto (como mostra a Figura 3). Se já tivermos definido
operações numa classe, podemos simplesmente seleccionar a operação existente a partir da
lista. Isto é típico da abordagem utilizada no Rational Rose para melhorar a produtividade dos
utilizadores e assegurar a consistência – e consequentemente a qualidade – ao longo de todo o
modelo. Outras capacidades igualmente úteis incluem a possibilidade de interrogar o modelo
onde as classes e as mensagens estejam por resolver (por exemplo, não representação para
as classes reais ou operações no modelo).
Outro aspecto de análise de cada classe individual consiste em identificar atributos para a
classe. Os atributos representam informação que pode ser pedida à classe por outras, ou que
pode ser pedida pela própria classe cumprir as suas responsabilidades. Nesta fase da análise,
é apropriado identificar atributos como tipos genéricos – por exemplo, número, sequência
(string), etc.
A identificação das relações entre as classes completa o diagrama de classes para o caso de
utilização. As relações em que estamos especialmente interessados nesta fase são as de
associação, dependência e herança. Depois da análise de todos os casos de utilização e da
criação dos diagramas de classes para cada caso de utilização, é altura de combinar as várias
classes de análise para chegar a um modelo de análise unificado. Esta é uma actividade
importante, na medida em que se pretende chegar a um conjunto mínimo de classes e evitar
redundâncias desnecessárias no modelo de análise final.
A tarefa chave nesta fase anda em torno da identificação de classes que possam estar
duplicadas ao longo dos casos de utilização ou camufladas por ligeiras variações. Por exemplo,
as classes de controlo que tiverem um comportamento similar ou representarem o mesmo
conceito ao longo de casos de utilização deverão ser fundidas. As classes de entidade que
tiverem os mesmos atributos também deverão ser fundidas e o seu comportamento combinado
numa única classe.
A Figura 4 mostra um diagrama de classes de nível de análise preliminar para os casos de
utilização identificados na Figura 1. Como estamos interessados principalmente nas relações
entre as classes, utilizámos as capacidades de filtragem do Rational Rose para filtrar os
detalhes das classes individuais através da não verificação do Format>Show todos os atributos
e do Format>Show todas as operações.
Figura 4. Diagrama de classes de nível de análise preliminar.
Implementação do software
Apesar do modelo de análise nos poder ajudar a desenvolver uma base sólida para resolver um
problema, continua a estar muito longe de uma implementação. Durante o desenho, temos que
ter em conta restrições e requisitos adicionais impostos à nossa aplicação pela tecnologia
subjacente. Como tal, precisamos de tentar desenhar a solução para a implementação óptima.
Por exemplo, se estivermos a construir uma aplicação online que requer uma aplicação cliente,
a tecnologia a utilizar poderá ser diferente das escolhas que seriam feitas para uma aplicação
baseada na Web com uma funcionalidade idêntica. Ainda para efeitos de exemplo, vamos partir
do pressuposto que estamos a construir uma aplicação baseada na Web. A implementação de
uma aplicação deste tipo exige uma abordagem bem pensada.
O modelo de análise ajuda neste caso, na medida em que fornece o ponto de partida para
determinar a forma como as diferentes tecnologias J2EE se adequam à solução. As classes
<<control>> adequam-se bem às Servlets Java ou aos Enterprise JavaBean (EJB) Session
Beans. Esta abordagem adequa-se bem ao modelo de implementação J2EE (por níveis, ou
tiered) e à “Model 2” Reference Architecture da Sun. O Rational Rose fornece uma interface
simplificada para o desenvolvimento de servlets e de EJB Session Beans. A Figura 5 mostra a
caixa de diálogo para a criação de uma servlet.
Figura 5. Caixa de diálogo para a definição de uma servlet.
O Rational Rose também fornece uma interface conveniente para a criação de EJBs, apesar de
um EJB envolver múltiplas interfaces e classes. A caixa de diálogo para a criação de EJBs é
apresentada na Figura 6. Neste caso específico, a caixa de diálogo mostra as especificações
necessárias para criar uma Session Bean sem estado (stateless).
Figura 6. Criação de uma EJB Session Bean.
A Session EJB resultante é apresentada na Figura 7. Esta baseia-se na modelação UML para o
perfil EJB que está a ser desenvolvido no JSR-26 sob os auspícios do Sun Java Community
Process. Mostra relações entre os vários elementos que constituem um EJB, nomeadamente
as interfaces home e remote e a classe de implementação EJB. Uma vez que o EJB não
implementa realmente as interfaces home e remote (estas são implementadas por objectos
gerados automaticamente pelo utilitário de implementação), a relação não é um
reconhecimento, mas antes <<EJBRealizeHome>> e <<EJBRealizeRemote>>,
respectivamente. A dependência entre as interfaces home e remote mostra que a interface
home instancia a interface remote.
Figura 7. Uma Session Bean sem estado.
As classes <<boundary>> adequam-se mais ou menos às JSP, às páginas HTML e aos
formulários. Se estivermos a desenvolver uma aplicação tradicional baseada em cliente,
também se adequa mais ou menos a uma caixa de diálogo de aplicação cliente. Utilizamos as
JSP como as construtoras de tudo aquilo que é apresentado às entidades que interagem com o
sistema. Uma vez que uma JSP tem realmente dois aspectos – nomeadamente apresentação
cliente e comportamento do lado do servidor, é modelada como consistindo numa Client Page e
numa Server Page, com um estereótipo especial <<build>> na relação. A Figura 8 mostra um
exemplo.
Figura 8. JSP como uma página servidor e cliente.
A criação de uma JSP é ainda mais simples do que a de um EJB e é efectuada através do
menu Web Modeler>New>Server Page do menu de contexto do browser, como mostra a Figura
9.
Figura 9. Criação de uma JavaServer Page no Rational Rose.
As classes <<entity>> – como Catalog, Order e Customer – são boas candidatas para Entity
Beans. Estes últimos são criados utilizando a caixa de diálogo apresentada na Figura 6,
destinada à criação de Session Beans. Uma técnica comum utilizada nas aplicações J2EE
consiste na utilização de JavaBeans para passar informação entre as servlets e as JSP. Isto é
realizado facilmente no Rational Rose através da criação de atributos numa classe Java e da
especificação dos atributos para propriedades (utilizando a caixa de diálogo de especificação
de atributos apresentada na Figura 10. Convém sublinhar que isto também pode ser efectuado
numa base global, através de uma especificação de utilizador.
Figura 10. Especificação de um atributo como proprietário.
A criação de JSPs, servlets, JavaBeans e EJBs é útil sobretudo no contexto de um modelo de
implementação global. O Rational Rose permite-nos modelar facilmente as relações e realizar
os detalhes básicos, não só das JSPs, servlets, EJBs e JavaBeans, mas também das páginas
HTML e dos Formulários envolvidos na implementação. Esses detalhes podem depois ser
remetidos para quem desenvolve a apresentação a fim de se conseguir um maior refinamento,
mantendo a compatibilidade com a lógica da aplicação.
A Figura 11 mostra um diagrama de classe parcial que apresenta a implementação com as
diferentes tecnologias envolvidas na loja de CDs online. O diagrama foi pensado para mostrar
classes e a forma como se adequam à apresentação, lógica de negócio e níveis de dados.
Desta forma, as páginas clientes estão à esquerda, a servlet controladora está no meio e os
Entity Beans estão à direita.
Figura 11. Modelo de implementação parcial para a loja de CDs online.
Este diagrama mostra apenas algumas das classes necessárias para os casos de utilização
“checkout” e “ver detalhes de CD”. Para ler o diagrama seguindo um cenário simples de
checkout, vamos partir do princípio que acabámos a nossa navegação e seleccionámos alguns
CDs que queremos comprar. Seleccionamos então a opção “checkout” na página principal
(topo à esquerda). Esta acção invoca o controlador MainServlet, como é mostrado através da
associação estereotipada <<link>>.
A MainServlet obtém os detalhes da encomenda do Order EJB, constrói um Order JavaBean,
especifica-o como um atributo para a sessão e encaminha o pedido (como identificado através
do estereótipo <<forward>>) para a Checkout JSP. Esta última utiliza o Order JavaBean – como
se vê pelo estereótipo <<Use Bean>> na associação entre a JSP e a Order JavaBean – para
criar a página Checkout_Client e a apresentar ao utilizador/comprador.
Obviamente, descorámos alguns detalhes. Por exemplo, num projecto real, utilizaríamos
provavelmente um carrinho de compras para efectuar o acompanhamento dos itens. Por outro
lado, as responsabilidades de controlo poderiam ser mais distribuídas, em vez de residirem
numa única MainServlet monolítica. O aspecto principal a reter neste caso tem a ver com o
facto da UML ser uma poderosa ferramenta para desenhar e desenvolver aplicações J2EE
complexas.
Trabalhar com a implementação
O Rational Rose dá uma ajuda em tudo isto, permitindo a criação de JSPs, JavaBeans, HTML,
servlets e código EJB directamente a partir deste diagrama. Por exemplo, uma associação
<<include>> entre duas JSPs (não apresentada no diagrama), resulta automaticamente em:
<%@include file=“header.jsp”%> na JSP apropriada. De forma análoga, o estereótipo <<Use
Bean>> resulta em: <jsp:useBean id=“cd” class=“com.rational.cdshop.util.CD” scope=“session”>
na JSP que utilize o JavaBean CD.
Do lado do EJB, além de gerar código para todos os três tipos de EJBs identificados no EJB 2.0
(bem como EJBs compatíveis com EJB 1.1), o Rational Rose disponibiliza várias
funcionalidades para simplificar o desenvolvimento de EJBs. Por exemplo, um dos aspectos
entediantes do desenvolvimento de EJBs é a necessidade de codificar os métodos na interface
e na classe de implementação.
O Rational Rose fornece assim uma opção de menu que trata desses detalhes, bastando para
tal o clique num botão. Também fornece uma opção de menu “check and repair” para verificar
se o EJB que definimos é de facto legal (por exemplo, se os métodos remotos na interface
remota correspondem aos seus correspondentes na classe de implementação EJB). Se não
corresponderem, a ferramenta oferece-se para resolver os problemas por nós.
Outra poderosa capacidade relacionada com os EJB proposta pelo Rational Rose é a Rational
Quality Architect (RQA), para o desenho dos testes dos EJBs. Por exemplo, podemos utilizar a
RQA para o teste unitário dos EJBs. Também podemos utilizar os diagramas de sequência que
definimos no Rose para o teste de múltiplos EJBs. De igual modo, podemos utilizar a RQA para
gerar chamadas de atenção (stubs) para aquelas alturas em que temos uma dependência num
componente de software que ainda não está pronto.
Para assegurar que podemos trabalhar com a implementação de acordo com as nossas
condições, sem nos preocuparmos com alterações ao modelo UML e vice-versa, o Rational
Rose fornece um editor de código (incluído) com opções de sincronização configuráveis pelo
utilizador. Por exemplo, podemos optar por manter a sincronização activa permanentemente.
Neste caso, o modelo UML no Rose será actualizado automaticamente sempre que
actualizarmos o nosso código fonte e guardarmos essa alteração. Algumas vezes, poderemos
querer apenas experimentar para ver como é que as coisas funcionam, sem causar qualquer
impacto no nosso modelo. Nestes casos, podemos desactivar a sincronização de forma global
ou por classe.
Não existe contestação ao facto de que quando se trata de implementação e de código,
precisamos de trabalhar com um IDE robusto, como o Forte da Sun para Java ou o Borland
JBuilder. O Rational Rose fornece uma estreita integração e autosincronização com os
principais IDEs, pelo que será possível continuar com o IDE que preferirmos e tirar partido ao
mesmo tempo do Rational Rose para a modelação UML e para o desenvolvimento de
aplicações J2EE.
Mais sobre UML e J2EE
Neste artigo abordámos apenas de forma superficial a utilização da UML para a modelação e
desenvolvimento de aplicações J2EE. Por exemplo, podemos utilizar os diagramas de
actividade UML para modelar a gestão das sessões pelas várias entidades envolvidas na
sessão. Outro desafio consiste na comunicação da sequência adequada das chamadas de
operação esperadas por uma sessão EJB.
Um diagrama de sequência pode identificar um único cenário, pelo que precisamos de vários
diagramas de sequência para expressar toda a gama de cenários suportados pelo componente.
Há quem tente utilizar um diagrama de sequência com controlo e declarações. No entanto, isto
só conduz a diagramas de sequência complexos e difíceis.
Por outro lado, os diagramas de estado UML (statechart diagrams) fornecem uma poderosa
capacidade para a modelação e comunicação deste aspecto. Podemos depois validar um
diagrama de sequência relativamente ao diagrama de estado, verificando se o componente
suporta a forma como estamos a tentar utilizá-lo.
Existe uma linha muito ténue entre o desenvolvimento de software que desempenha o seu
trabalho e o desenvolvimento de software que não desempenha o seu trabalho. Podemos
melhorar significativamente as nossas hipóteses de desenvolver software escalável, fácil de
manter e durável se utilizarmos a UML para compreender os requisitos e efectuar análises e
desenho de forma adequada, bem como desenvolver uma solução baseada em princípios com
provas dadas e na implementação das melhores práticas da indústria.
Baseado no artigo “Developing J2EE Applications with the UML and Rational Rose”, de Khawar
Ahmed, membro da Rational Rose eBusiness Products Team (Rational/IBM).
Tel: (+351) 239 497 230 / 2 • Fax: (+351) 239 497 231
E-mail: [email protected] • Internet: www.engenharia-software.com
Download

Desenvolvimento de Aplicações J2EE com UML