Compreensão de Programas através da Localização de Casos de Uso · enquanto as linguagens de...

16
Compreensão de Programas através da Localização de Casos de Uso Marcelo Marinho, Nicolas Anquetil Universidade Católica de Brasília (UCB) SGAN 916 – Av. W5 – CEP: 70790-160 – Brasília – DF– Brasil [email protected], [email protected] Abstract. It is the maintainer’s task to translate business needs into running code. As a result a large part (40% to 60% according to some studies) of the time spent modifying systems is actually devoted to understand them and how to implement the needed changes. Concept location is the branch of reverse engineering that aims at providing tools to help identifying where a given system functionality is implemented in the source code. In past works, terms of “feature”, “scenario, “test case” or “use case” are used interchangeably and independently from their usual meaning in software engineering. This problem maybe corrected by a propose of a feature location framework based on (Jacobson) use cases. A prototype environment has been created and applied to two applications to illustrate the improvement opportunities. Resumo. É trabalho do mantenedor traduzir necessidades de negócio em um código executável. Consequentemente grande parte do tempo de modificação dos sistemas é dedicado a compreender o próprio sistema e como as modificações devem ser implementadas. Localização de conceitos é uma linha de engenharia reversa que provê ferramentas para identificar onde uma determinada funcionalidade do sistema está implementada. Em trabalhos anteriores, termos como “funcionalidade”, “cenários”, “casos de teste” ou “casos de uso” foram usados de forma geral, quase como sinônimos. Este problema pode ser corrigido por uma abordagem baseada em casos de uso. Um protótipo desta abordagem foi construído e aplicado em casos reais. 1. Introdução Para melhorar e adaptar os softwares existentes e desempenhar as atividades de manutenção efetivamente, os mantenedores responsáveis precisam compreender o software em questão; sua estrutura, comportamento e inserção no ambiente operacional. O tempo necessário para compreender um sistema, e como devem ser realizadas as mudanças desejadas, pode chegar a 90% do tempo total gasto [Lucia et al 1996]. Bennett e Rajlich (2000) destacam que estudar métodos e ferramentas de apoio à compreensão de programas é uma das sete grandes áreas de pesquisa em manutenção de software. A localização de conceitos é uma das formas adotadas para ajudar na compreensão de programas no contexto da manutenção de software [Rajlich e Wilde 2002]. A localização de conceitos corresponde a identificar as partes do código fonte do software

Transcript of Compreensão de Programas através da Localização de Casos de Uso · enquanto as linguagens de...

Compreensão de Programas através da Localização de Casos de Uso

Marcelo Marinho, Nicolas Anquetil

Universidade Católica de Brasília (UCB) SGAN 916 – Av. W5 – CEP: 70790-160 – Brasília – DF– Brasil

[email protected], [email protected]

Abstract. It is the maintainer’s task to translate business needs into running code. As a result a large part (40% to 60% according to some studies) of the time spent modifying systems is actually devoted to understand them and how to implement the needed changes. Concept location is the branch of reverse engineering that aims at providing tools to help identifying where a given system functionality is implemented in the source code. In past works, terms of “feature”, “scenario, “test case” or “use case” are used interchangeably and independently from their usual meaning in software engineering. This problem maybe corrected by a propose of a feature location framework based on (Jacobson) use cases. A prototype environment has been created and applied to two applications to illustrate the improvement opportunities.

Resumo. É trabalho do mantenedor traduzir necessidades de negócio em um código executável. Consequentemente grande parte do tempo de modificação dos sistemas é dedicado a compreender o próprio sistema e como as modificações devem ser implementadas. Localização de conceitos é uma linha de engenharia reversa que provê ferramentas para identificar onde uma determinada funcionalidade do sistema está implementada. Em trabalhos anteriores, termos como “funcionalidade”, “cenários”, “casos de teste” ou “casos de uso” foram usados de forma geral, quase como sinônimos. Este problema pode ser corrigido por uma abordagem baseada em casos de uso. Um protótipo desta abordagem foi construído e aplicado em casos reais.

1. Introdução Para melhorar e adaptar os softwares existentes e desempenhar as atividades de manutenção efetivamente, os mantenedores responsáveis precisam compreender o software em questão; sua estrutura, comportamento e inserção no ambiente operacional. O tempo necessário para compreender um sistema, e como devem ser realizadas as mudanças desejadas, pode chegar a 90% do tempo total gasto [Lucia et al 1996]. Bennett e Rajlich (2000) destacam que estudar métodos e ferramentas de apoio à compreensão de programas é uma das sete grandes áreas de pesquisa em manutenção de software.

A localização de conceitos é uma das formas adotadas para ajudar na compreensão de programas no contexto da manutenção de software [Rajlich e Wilde 2002]. A localização de conceitos corresponde a identificar as partes do código fonte do software

em questão que implementam conceitos de alto nível de abstração – de dimensão humana. Por exemplo, para modificar o “rastreamento de entregas” em um sistema de vendas pela internet, é preciso saber que unidades – classes, funções, blocos de código – implementam o rastreamento, para depois descobrir como fazer a mudança, avaliar o impacto e assim por diante.

De um modo geral, nas diferentes abordagens de localização de conceitos que foram propostas ao longo da última década, as formas de se identificar e representar os conceitos de dimensão humana foram tratadas superficialmente. Uma evidência disso é o uso de diversos termos diferentes para se referir aos conceitos que estavam sendo localizados, tais como funcionalidades, cenários, casos de uso, cenários de uso e etc.

Neste trabalho, os casos de uso – conforme descritos por Jacobson (1992) – são vistos com a forma preferencial de se representar os conceitos de alto nível de abstração, entre outras coisas, devido à adoção crescente na indústria de software. A partir desta idéia, foi desenvolvida uma abordagem para a localização de conceitos totalmente adaptada ao tratamento de casos de uso.

Na seção 2, serão relacionadas as limitações de trabalhos anteriores que motivaram a pesquisa. A estrutura dos casos de uso e os benefícios de sua utilização na localização de conceitos serão abordados na seção 3. A seção 4 traz uma visão geral da abordagem proposta. Na seção 5, os 2 experimentos realizados para validar a idéia serão descritos. A seção 6 trata dos trabalhos relacionados. A seção 7 apresenta as conclusões.

2. Compreendendo Programas através da Localização de Conceitos

Os problemas que afetam a manutenção de software podem ser relacionados a uma questão fundamental: a compreensão do software. Estimativas a respeito da composição dos custos de manutenção apontam que o tempo gasto pelos mantenedores para entender como um sistema está implementado e de que forma eles devem proceder para realizar uma determinada mudança está entre 40% e 90% do tempo total [Lucia et al 1996]. Para Rajlich e Wilde (2002) a “compreensão de programas é uma parte essencial da evolução e manutenção de software”, pois “programas que não podem ser compreendidos, não podem ser mudados”.

Na prática, o processo de manutenção de software é normalmente iniciado por requisições dos usuários, que identificam necessidades de mudança no software. Essas requisições são normalmente expressas em linguagem natural, com base em termos de alto nível de abstração, quando comparados com o que é possível expressar com uma linguagem de programação [Biggerstaff 1993]. Por isso, para realizar as tarefas da manutenção, é necessário que os mantenedores compreendam o software em um sentido amplo, isto é, são importantes conhecimentos tanto em níveis mais altos de abstração – para compreender o texto de uma requisição escrita pelo usuário – como em níveis mais baixos, próximos ao da linguagem de programação – para descobrir como realizar as mudanças necessárias. Mais que isso, é necessário conseguir relacionar estes dois níveis de conhecimento [Rajlich e Wilde 2002].

Biggerstaff (1993) foi pioneiro na formalização da localização de conceitos. Ele introduziu a noção de que os termos do domínio da aplicação, expressos em linguagem natural, são conceitos humanos, e por tanto, imprecisos e sujeitos à ambigüidade;

enquanto as linguagens de programação são baseadas em expressões determinísticas e não-ambíguas. A principal conseqüência desta diferença de naturezas é que é muito difícil descobrir relações entre estes os conceitos e o código fonte de programas através de abordagens algorítmicas. Ele chamou esta questão de “concept assignment problem”.

Ao longo da última década diversas propostas de solução para este problema já surgiram [Wilde e Scully 1995] [Gold 2000] [Eisenbarth et al 2003] [Salah et al 2006] desde que Lakhotia (1993) citou o comando grep do sistema operacional UNIX como sendo a sua ferramenta para realizar este tipo de tarefa.

As técnicas de localização de conceitos podem se valer tanto de análises estáticas como de análises dinâmicas, ou mesmo de ambas ao mesmo tempo. Uma abordagem estática comum é a de realizar uma busca por padrões de texto que de alguma forma lembram conceitos procurados; por exemplo, “vnd” ou “vend” para “vendas”. A solução pode ser baseada em ferramentas simples como o comando grep do UNIX [Wilde et al, 2002] ou em mais sofisticadas, como agentes inteligentes [Biggerstaff, 1993]. A linha de soluções baseada em análise dinâmica procura obter rastros de execução dos programas para associar as partes do código aos conceitos disparados por casos de testes especialmente concebidos [Wilde e Scully, 1995].

A principal motivação de desenvolver uma nova abordagem para atacar o problema é que a maior parte dos autores deixa em aberto a origem dos conceitos que serão localizados no código fonte. Os trabalhos de análise estática não se fixam em definições do que são os conceitos, não se preocupando em explicar como chegar a eles, sua forma ou seu conteúdo. Atribuir importância a cada conceito, organizar os relacionamentos entre eles e as demais atividades relacionadas dependem totalmente do conhecimento prévio e da capacidade do mantenedor, tanto no domínio do problema como no domínio da implementação da solução. Quando se baseiam em análise dinâmica, devido à própria natureza da solução, os trabalhos normalmente optam por especializar a localização de conceitos no tratamento de funcionalidades do sistema. Desta forma, os conceitos não são tão indefinidos e podem ter forma e fonte mais determinadas, – os requisitos do sistema – mas, por outro lado, os conceitos abordados são muito triviais e de baixo nível de abstração.

Uma abordagem ideal deveria ter uma perspectiva ampla que estivesse mais próxima ao domínio do problema, da terminologia usada pelos usuários ao formularem requisições de mudança, mas ao mesmo tempo não deveria perder a visão das atividades mais pontuais, como nos casos citados. Além disso, seria muito bom se esta abordagem estivesse enquadrada no contexto das técnicas, artefatos e ferramentas modernas do ciclo de vida do software. Na próxima seção, será apresentada a Localização de Casos de Uso – uma subclasse da localização de conceitos – pode atender a estes requisitos.

3. Casos de Uso e a Localização de Conceitos Caso de uso é uma técnica de especificação de requisitos funcionais adotada em métodos modernos de desenvolvimento de software [RUP 2007]. Para explicar adequadamente a proposta deste trabalho é necessário ressaltar as características dos casos de uso que são importantes para a aplicação da técnica. A consideração destes aspectos é exatamente o que torna a abordagem apresentada neste artigo diferente das apresentadas em trabalhos anteriores.

• Diferentemente da noção atômica de conceitos ou funcionalidades, o caso de uso é descrito em fluxos de eventos. Cada fluxo de eventos descreve uma seqüência de ações entre o sistema e o ator(es).

• Os fluxos de eventos incluem formas diferentes de se obter o mesmo resultado. E mesmo o tratamento de erros ou insucessos na obtenção de resultados são descritos em fluxos separados do mesmo caso de uso.

Os cenários são instâncias de um caso de uso. Eles são seqüências distintas de eventos, dentre as muitas possíveis descritas em um caso de uso.

A figura 1 apresenta um exemplo de especificação de caso de uso. Existe sempre um fluxo principal que leva à obtenção do resultado desejado pelo ator da forma mais simples possível. Outros fluxos especificam os tratamentos de erros ou formas alternativas de obtenção do resultado.

Figura 1. Exemplo de Fluxo de Eventos de Caso de Uso

Caso de Uso: Escolher Pacote Esse caso de use se refere à navegação no site onde o cliente pode estudar o catálogo de opções de pacotes turísticos e escolher alguns para compra 1. Fluxo Básico

1.1. Cliente acessa a tela principal do sistema pela URL 1.2. Cliente seleciona uma categoria de aventura. 1.3. Cliente seleciona um pacote de aventura, para visualização. 1.4. Cliente seleciona o pacote, para compra. 1.5. Cliente define e submete as opções do pacote. 1.6. Cliente escolhe as opções de transporte e submete para o sistema. 1.7. Cliente escolhe seu vôo de ida e de volta e submete para o sistema.

2. Dispensa Transporte 2.1. No passo 1.6, o cliente pode escolher dispensar a reserva do transporte.

3. Altera Opções de Pacote no Carrinho de Compras 3.1. Após o passo 1.7, o cliente pode alterar os dados escolhidos, retornando aos passos do fluxo básico.

No conjunto dos trabalhos de localização de conceitos, alguns que se basearam em casos de uso [Bojic e Velasevic 2000] [Lucca et al 2000] [El-Ramly et al 2002] [Zhang et al 2006] [Salah et al 2006]. Contudo, de um modo geral, os fluxos de eventos não foram considerados. Com isso, os casos de uso se tornam, para efeito dos resultados obtidos, tão atômicos como as funcionalidades de outros trabalhos. Além disso, o nível de abstração dos casos de uso é muito próximo ao de funcionalidades como “imprimir” ou “mover objetos na tela”. Em aplicações mais complexas os casos de uso tendem a ser mais abstratos – “escolher pacote de aventura”, por exemplo – e possuir muitas variantes, ou seja, muito fluxos alternativos. Uma abordagem de localização de conceitos baseada em casos de uso deve levar em conta também a estrutura dos fluxos de eventos, a fim de obter todos os benefícios e que o formato da especificação pode oferecer.

3.1. Benefícios dos Casos de Uso na Localização de Conceitos Localizar a implementação de casos de uso no código fonte, pode ser considerado interessante por diversos motivos, como por exemplo:

• Eles estão mais próximos da perspectiva humana do que artefatos mais técnicos – como modelos de projeto – e por isso podem ser mais úteis à compreensão do mantenedor [Zhang et al, 2006];

• Conhecimento do domínio do problema é fundamental para definir cenários e identificar funcionalidades importantes, cujas implementações devem ser

localizadas [Einsebarth et al 2003]. Casos de uso são essencialmente representações de conceitos de negócio, pois representam “algo de valor observável para o usuário”.

• A técnica de especificar funcionalidades com casos de uso está se tornando cada vez mais comum entre as organizações que desenvolvem software e, portanto, é provável que o mantenedor já esteja familiarizado com a técnica [Zhang et al 2006].

Além disso, dos benefícios relacionados acima, uma abordagem de localização de casos de uso que se baseie também nos fluxos de eventos pode apresentar as seguintes vantagens:

• A estrutura dos casos de uso é razoavelmente bem definida. Ainda que possa haver alguma variação da forma de um autor para outro [Cockburn 2000] a estrutura de fluxos de eventos deve ser sempre preservada, o que permite padronizar o trabalho de como definir e representar os conceitos.

• Dentro de um caso de uso existem diferentes níveis de abstração que podem ser considerados: o próprio caso de uso, os fluxos de eventos e cada uma das ações dos fluxos. Com isso, a análise pode variar de uma visão mais arquitetural como a apresentada por Bojic e Velasevic [2000] a um rastro detalhado de como uma determinada ação do caso de uso é implementada.

• Casos de uso organizam as variações para uma mesma funcionalidade. Com isso, é possível saber como o código reage a condições diferentes, ainda que o resultado final obtido pelo usuário seja muito parecido.

• É fácil identificar cenários e criar casos de testes a partir de casos de uso. Existem métodos consolidados para se criar casos de teste a partir de casos de uso [RUP 2007].

4. Proposta de Localização da Implementação de Casos de Uso

O objetivo deste trabalho é propor uma técnica para a compreensão de programas através da localização da implementação de casos de usos. A proposta apresentada possui semelhanças com os outros trabalhos de localização de casos de uso, em especial os de Bojic e Velasevic (2000) e Salah et al (2006), pois também obtém seus produtos através da análise dinâmica. Os trabalhos referenciados se dedicaram a criar visões e documentos focados na estrutura interna dos sistemas estudados, sem aproveitar a estrutura dos próprios casos de uso para segmentar mais as visões e criar novos níveis de abstração que podem contribuir para a compreensão do mantenedor. A contribuição desta nova abordagem está na forma diferente de tratar os conceitos humanos, representados por casos de usos.

Entre as características da proposta que contribuem para diferenciá-la das demais, podemos citar:

• Leva em consideração a estrutura de fluxos e atividades do caso de uso;

• Aproveita, sempre que possível, técnicas e ferramentas conhecidas e já adotadas na indústria de software;

• Favorece a representação de conceitos de nível mais alto de abstração através dos casos de uso, sem perder a visão mais detalhada, no nível das ações.

Além disso, a abordagem não se baseia em conceitos existentes exclusivamente em linguagens orientadas a objetos o que, potencialmente, permite sua utilização em um conjunto maior de soluções.

4.1. Visão Geral da Proposta O principal pré-requisito para a aplicação da técnica de localização de casos de uso é a existência dos casos de uso. A criação, ou mesmo revisão de casos de uso existentes, pode ser feita com base em diversas referências [COCKBURN 2000] [RUP 2007] que descrevem não apenas a produção dos casos de uso, mas outras atividades importantes como avaliação, priorização, classificação, hierarquização e modelagem visual.

As etapas para a aplicação da técnica são as similares às encontradas em outras abordagens baseadas no trabalho de Wilde e Scully (1995):

I. Criação de casos de testes – derivados dos casos de usos, através da adaptação de um roteiro do RUP (2007);

II. Instrumentação do código fonte do sistema;

III. Execução dos casos de teste e coleta de rastros – criando um tipo específico de rastro, segmentado por ações;

IV. Análise dos rastros e geração de relatórios – para obter informações que vão auxiliar o processo de compreensão.

De forma muito similar à solução de Salah et al (2006) A aplicação da técnica deve ser suportada por um ambiente de software com os seguintes componentes:

• Instrumentador de Código – altera o código fonte da aplicação inserindo as chamadas para as funções que gerarão o rastro de execução do sistema.

• Interface do Executor – uma interface de usuário que permita ao executor dos casos de testes registrar cada ação que for executada.

• Base de Rastros – um meio de armazenamento dos rastros gerados, que no caso de sistemas reais podem atingir volumes inviáveis de serem tratados manualmente.

• Gerenciador de Rastreamento – deve ser capaz de correlacionar a informação das ações executadas nos casos de teste, gerada na Interface do Executor com os rastros do sistema instrumentado, preparado pelo Instrumentador.

• Analisador de Rastros – conjunto de relatórios e outras consultas que apresentam informações que podem ser obtidas dos rastros coletados.

A Figura 2 apresenta uma visão geral da proposta, unindo os passos do método com os componentes do ambiente de suporte. Cada etapa está indicada pelos numerais romanos usados anteriormente. Nos próximos tópicos será feita uma descrição detalhada de cada etapa e como cada uma delas deve utilizar o ambiente de suporte.

Figura 2. Visão Geral da Proposta

4.2. Criação dos Casos de Teste O primeiro passo para a realização da análise dinâmica é definir os casos de testes que serão executados para gerar os rastros. Nesta abordagem, a criação dos casos de teste se baseia na técnica descrita no RUP (2007) que deriva os casos de testes a partir dos casos de uso. Alguns autores citam a dificuldade de definir casos de testes relevantes e que tenham correlação clara com os conceitos a serem estudados [Deprez e Lakhotia 2000] [Eisenbarth et al 2003]. Neste ponto os casos de uso apresentam uma vantagem considerável: seguindo métodos como o descrito no RUP (2007), é possível criar, com passos bem definidos, casos de teste a partir da estrutura em fluxos e ações dos casos de uso.

Além de ser bastante prática e de já estar um uso em muitas organizações, a criação de caso de testes a partir de casos de uso, elimina um problema encontrado em trabalhos de localização de funcionalidades. Nas abordagens de Bojic e Velasevic (2000) e Eisenbarth et al (2003), por exemplo, cada caso de teste pode ser relacionar a mais de uma funcionalidade ou caso de uso. Isso faz com que seja necessário selecionar um conjunto de casos de teste ainda mais complexo, para que seja possível diferenciar os casos de uso ao se analisar os rastros gerados. Em oposição a isso, quando os casos de testes são produtos derivados dos casos de uso cada caso de teste se refere então a um, e apenas a um, caso de uso. Certamente existirão pontos em comum entre casos de testes de casos de usos diferentes, mas essas semelhanças poderão ser detectadas na análise dos rastros. Por exemplo, pode ser possível identificar ações ou fluxos semelhantes entre casos de usos em que essa semelhança não era clara. Sendo assim, detectar a

Análises IV Analisadores

Caso de Uso

Caso de Teste

Base de Rastros

código fonte Instrumentador

código fonte (instrumentado)

sistema (instrumentado)

operador script automatizado

Interface do Executor

I II

III

Gerenciador de Rastreamento

similaridade e a correspondência entre casos de teste e casos de uso deixa de ser uma atividade totalmente dependente do discernimento de uma pessoa responsável e passa a ser suportada por métodos claros e informações obtidas automaticamente.

O reaproveitamento de esforços é um outro ponto importante que surge com a proposta desta abordagem. É possível que, em um contexto favorável, parte do trabalho já tenha sido realizada por equipes especializadas. Isto é, pode ser que os casos de uso já tenham sido criados ou revisados por uma equipe de analistas de requisitos e que casos de testes derivados destes casos de uso já tenham sido definidos por uma equipe de analistas de testes.

O método de criação de casos de testes descrito pelo RUP (2007) é composto de três passos: gerar os cenários, identificar casos de testes e definir os dados a serem aplicados.

Os cenários gerados são as instâncias de um caso de uso, conforme descritos anteriormente. Cada cenário é uma seqüência específica de ações, dentre as diversas possíveis em um caso de uso e pode ser descrito como um conjunto de fluxos de eventos.

O segundo passo consiste em definir os casos de testes podem ser obtidos de cada cenário e em que condições eles devem satisfazer. Cada cenário deve gerar pelo menos um caso de teste, mas pode haver mais, pois uma mesma condição pode ser atendida por dados diferentes. Por exemplo, um “valor inválido” pode ser inválido por estar acima ou por estar abaixo do intervalo considerado válido. A Tabela 1 apresenta casos de testes que podem ser obtidos a partir dos cenários hipotéticos do caso de uso “Escolher Pacote”.

Tabela 1 – Casos de Teste do Caso de Uso “Escolher Pacote”

Caso de Teste

Cenário Condições Resultado Esperado

CT1 1: Escolhe um pacote Qualquer Carrinho = 1 pacote

CT 2 4: Escolhe um pacote com e outro sem transporte

Passo 7 – Escolhe outro pacote de outra categoria

Carrinho = 2 pacotes

CT 3 7: Navega e não escolhe nada Passo 2 – muda de categorias

Passo 3 – escolhe vários pacotes

Carrinho = vazio

CT 4 6: Escolhe um pacote e depois remove Fluxo A3 – muda a quantidade do pacote escolhido para 0 (zero)

Carrinho = vazio

A seguir, no terceiro passo, as condições gerais dos dados são substituídas por valores reais ou por classes mais restritas. Por exemplo, o “valor do saque” passa de “> 0” para um número absoluto, como “100”.

Neste ponto termina a técnica do RUP (2007) para a criação de casos de teste. Contudo, para assegurar a obtenção dos rastros no nível de ações de caso de uso, a abordagem exige mais uma tarefa a ser realizada. No quarto passo desta atividade o caso de teste deve ser detalhado em uma seqüência de ações, onde a cada ação do caso de uso deve corresponder uma ação do caso de teste.

4.3. Instrumentação do Software Esta é uma atividade típica na realização de análises dinâmicas. O programa estudado deve estar preparado para gerar os rastros, que são as informações internas do programa enquanto estão sendo executados os casos de testes.

O componente principal da instrumentação é o Instrumentador que depende da linguagem de programação utilizada na implementação. Na prática, a instrumentação corresponde a inserir linhas de código adicionais no código fonte do programa estudado. Estas linhas de código são comandos que geram os rastros, por exemplo, escrevendo em um arquivo texto que a execução passou por um desvio condicional. Os comandos que geram os rastros não devem alterar o fluxo de execução nem alterar o estado de nenhuma variável para não interferir no resultado da execução. Apesar de ser uma atividade que pode ser realizada manualmente em sistemas pequenos, realizar esta tarefa sem a ajuda de algum tipo de automação é inviável em sistemas muito grandes. Desta forma a instrumentação consiste em executar um programa que realizará a inserção das chamadas no código fonte. A atividade se completa com a compilação e geração de uma versão instrumentada do executável do programa.

Em termos de funcionamento geral do protótipo de ambiente criado, o Instrumentador foi criado para instrumentar programas em Java™. Quando acionado, ele cria uma cópia de todos os arquivos “.java” onde cada método recebe uma linha de código em seu início. Esta linha de código realiza o registro de que o método foi executado; em outras palavras, rastreia o método.

No caso da abordagem proposta neste trabalho os comandos geradores dos rastros têm uma característica especial. Ao invés de gerarem diretamente o rastro, em um arquivo texto, por exemplo, os comandos são chamadas remotas para funções do Gerenciador de Rastreamento. Em resumo, o rastro do programa não é gerado pelo próprio programa executado, como acontece normalmente, mas sim por um outro programa que recebe os dados de rastreamento em tempo-real.

4.4. Execução dos Casos de Teste A principal diferença entre a execução normal de uma aplicação e execução de um caso de teste para a localização de casos de uso é que o executor dos testes deve utilizar a Interface do Executor para informar cada ação do teste executado. O objetivo desta atividade é executar os casos de testes e armazenar os rastros obtidos, segmentados em ações, na Base de Rastros.

Para viabilizar isso, um componente fundamental é o Gerenciador de Rastreamento que vai receber tanto as chamadas do programa instrumentado (como citado no tópico anterior), como da Interface do Executor. O programa instrumentado informa para o Gerenciador de Rastreamento as partes do programa que estão sendo executadas, enquanto isso, o mantenedor que executa o caso de teste informa, através da Interface do Executor, em que ação prevista no caso de teste ele está. O Gerenciador de Rastreamento une estas informações originadas em tempo-real em um rastro segmentado – semelhante ao obtido por Salah et al (2006).

Quando o caso de teste termina, o Gerenciador de Rastreamento armazena tudo na Base de Rastros. Ainda que na prática se trate de um modelo relacional, de forma ilustrativa, pode-se imaginar o rastro marcado como sendo algo parecido com a Figura 3.

Figura 3. Ilustração de Um Rastro Marcado de Caso de Uso Caso de Teste 1 (derivado do Caso de Uso 1)

1ª Ação do Caso de Teste (relacionada a ação do caso de uso) ClasseX.Metodo1 ClasseX.Metodo2

ClasseY.Metodo6 ClasseZ.Metodo3

2ª Ação do Caso de Teste (relacionada a ação do caso de uso) ClasseA.Metodo3 ClasseX.Metodo3 ClasseY.Metodo6 ClasseB.Metodo1 ClasseB.Metodo2

3ª Ação do Caso de Teste (relacionada a ação do caso de uso) ... 4ª Ação do Caso de Teste (relacionada a ação do caso de uso) ...

Este rastro marcado no nível de ações de caso de teste confere a esta abordagem uma característica única entre as soluções de localização conceitos, pois o mesmo rastro permitirá fazer análises em diferentes níveis de abstração.

4.5. Análise dos Rastros

Quando os casos de teste são executados, as unidades computacionais acionadas são armazenadas na Base de Rastros. O resultado são rastros segmentados por ações de caso de uso. Através de consultas à Base de Rastros é possível obter diversos produtos que vão suportar a compreensão da implementação dos casos de uso no sistema.

A análise mais simples e mais detalhada é própria apresentação dos rastros coletados. Esta análise é chamada de “Execução Post-Mortem”, pois para cada ação de caso de uso as unidades computacionais registradas nos rastros são apresentadas, incluindo invocações repetidas e a hierarquia de chamadas, como se o mantenedor estivesse seguindo uma execução real do sistema.

Aplicando-se filtros sobre os rastros é possível apresentar as informações de forma mais consolidada, eliminando repetições e dispensando a hierarquia de chamadas, por exemplo. Pode-se também optar por selecionar apenas unidades computacionais que sejam parte de um determinado módulo do sistema e assim por diante.

Outras análises podem se basear no cruzamento entre rastros de casos de usos diferentes para descobrir diferenças e semelhanças significativas nas suas implementações. A comparação entre os rastros de casos de uso pode identificar, por exemplo, fluxos ou ações com descrições textuais semelhantes, mas implementados de formas totalmente diferentes. Ou o inverso disso, textos diferentes cujas implementações baseiam-se nos mesmos componentes e estruturas.

Invertendo este ponto vista, de casos de uso para unidades computacionais, existe outra forma de análise comparativa que pode apresentar informações arquiteturalmente interessantes: computar a presença de unidades computacionais nos rastros de casos de uso, fluxos de eventos ou ações. Unidades computacionais usadas em muitos casos de usos diferentes tendem a ser algum tipo de infra-estrutura que é muito reutilizada e, portanto, é pouco específica de qualquer processo de negócio. Por outro lado, unidades computacionais usadas apenas casos de uso específicos podem ser importantes para entender o funcionamento daquele caso de uso, ou mesmo de um fluxo ou ação específicos.

5. Aplicações Práticas Com o objetivo de validar a proposta o método foi aplicado em dois sistemas. Um é uma aplicação J2EE™ de exemplo, fornecida no website da Sun Microsystems® - “Adventure Builder”™ (AB). O outro exemplo é o sistema de gerência de projeto acadêmicos da universidade, também baseado na arquitetura J2EE™.

No caso da aplicação AB os casos de uso foram criados com base na documentação fornecida no pacote obtido no website. Os fluxos de ações não estavam especificados, mas como se trata de um sistema simples, não foi difícil chegar a eles explorando um pouco a aplicação em funcionamento.

A outra é uma aplicação real que se encontra em uso hoje na universidade e foi desenvolvida por um grupo de estudantes e professores (incluindo o segundo autor deste artigo). Ao longo dos quatro anos em que o sistema tem estado em uso, ele sofreu diversas manutenções e a documentação existente estava razoavelmente desatualizada. Por isso, este é um bom exemplo de condições que podem ser encontradas no mundo real.

Diferentemente do que se possa esperar a desatualização dos casos de uso não foi crítica, pois como o nível de abstração é razoavelmente alto, as mudanças são poucas e facilmente detectadas. A maior parte do esforço na revisão dos casos de uso esteve ligada, na verdade, à inexperiência dos analistas iniciais que fez com que alguns casos de uso não mantivessem o nível de abstração adequado em todos os passos. Estas ações corretivas talvez não fosse necessárias, se os analistas tivessem mais familiaridade com a técnica.

Para o AB foram implementados oito casos de testes para cobrir os cenários selecionados de 4 casos de usos. Já no SIGEP foram escolhidos 8 casos de uso, de um dos módulos do sistema e foram criados 12 casos de testes para cobrir os cenários selecionados.

5.1. Automação da Execução dos Casos de Teste Durante a implementação do protótipo foi observado que seria possível integrar o ambiente de suporte a ferramentas de automação de testes. Como ambas as aplicações estudadas e também o protótipo do ambiente estão implementados em Java, o IBM® Rational™ Functional Tester™ foi escolhido para esta tarefa, pois também usa a linguagem em seus scripts de automação. Assim, foi possível aproveitar os componentes da Interface do Executor para fazer com que os scripts de teste fossem modificados para enviar as mensagens das ações dos casos de teste para o Gerenciador de Rastreamento; enquanto executavam os casos de teste sobre o sistema instrumentado. Do ponto de vista do Gerenciador de Rastreamento não há nenhuma diferença se a execução do caso de teste está sendo realizada por uma pessoa, com o uso da Interface do Executor, ou através de um script automatizado no RFT.

Um ponto importante é que os scripts de teste são independentes do ambiente da geração dos rastros. Caso o Gerenciador de Rastreamento não esteja ativo, o script evita o envio das mensagens com os passos do caso de teste e é executado da mesma forma. Assim, é possível reaproveitar os mesmos scripts de testes, seja na geração dos rastros, seja na execução normal de testes do sistema.

5.2. Análises Coletados os rastros, foram implementadas 3 das análises citadas anteriormente: Rastros Consolidados, Execução Post-Mortem, e Análise de Similaridades Entre Casos de Uso.

Os rastros consolidados e execução post-mortem são apresentados na forma de páginas HTML (figura 4), que permite a navegação rápida os arquivos do código fonte onde estão implementados.

Figura 4. Dois exemplos de como os rastros consolidados e a execução post-mortem são apresentados. A tela do navegador é divida em 2 frames: no lado direito é apresentado o método que faz parte do rastro. Os números 1.6, 1.1, 1.2, indicam o fluxo e passo (1.6: fluxo 1, passo 6). Clicando no link o frame do lado esquerdo apresenta o arquivo do código fonte e navega imediatamente para a declaração do método.

A análise de similaridades revelou relações que não estavam claras nos textos das ações dos fluxos de eventos. A tabela 3 apresenta alguns exemplos de alto nível de similaridade identificados entre casos de uso do sistema “Adventure Builder”. Esses passos se referem a ações de navegação e eles acabam em telas muito parecidas umas com as outras. Nenhum deles está relacionado a nenhuma entrada de dados, aplicação de regra de negócio ou algo que exija do sistema muito mais do que mecanismos restritos à camada de apresentação.

Tabela 3. Comparação entre Ações dos Casos de Uso “Escolher Pacote” e “Rastrear Pedido”.

Ações de “Rastrear Pedido” Ações de “Escolher Pacote”

1.1 1.2 1.1: Esse caso de uso se inicia quando o Cliente acessa a tela principal do sistema. 73.91304% 23.404255%

1.2: Cliente seleciona uma categoria de aventura. 85.0% 25.0% 1.3: Cliente seleciona um pacote de aventura, para visualização. 89.47369% 25.581396% 1.4: Cliente seleciona o pacote, para compra. 13.483146% 26.595745% 1.5: Cliente define e submete as opções do pacote. 11.111112% 24.324326% 1.6: Cliente escolhe as opções de transporte e submete para o sistema. 11.111112% 28.0% 1.7: Cliente escolhe seu vôo de ida e de volta e submete para o sistema. 10.784314% 27.184465% 2.1: No passo 6, o cliente pode escolher dispensar a reserva do transporte. 13.92405% 33.333336% 3.1: Apos o passo 7 o cliente pode voltar ao passo 1 e reiniciar o processo de escolha. 24.489796% 51.923077% 5.1: Apos o passo 3, o cliente pode retornar ao passo 2 e selecionar uma nova categoria 94.44444% 26.190477% 6.1: Apos o passo 3, o cliente pode selecionar outro pacote na mesma categoria. 89.47369% 25.581396% 7.1: Em qualquer passo o cliente pode decidir interromper a navegação e a escolha de pacotes. 13.333334% 29.032257%

O cálculo de similaridades é capaz de relacionar conceitos que podem estar separados no texto dos casos de uso, mas que têm implementações em comum. Neste caso a alta similaridade demonstra que estes passos não tratam conceitos fundamentais para o negócio, mas sim de características de funcionamento geral do sistema (que podem estar presentes em qualquer ponto de qualquer caso de uso).

Passos cuja similaridade é sempre baixa com relação a todos os outros, mostram onde estão tratados os fatores específicos do caso de uso. Ações cuja similaridade é sempre baixa com relação às outras mostram onde estão tratados os fatores específicos do caso de uso. Por exemplo, a similaridade dos passos 4, 5, 6 e 7 do Fluxo 1 do Caso de Uso “Escolher Pacote” atingem o máximo de 26%, e na maior parte das vezes são inferiores a 20%. Como outros passos atingem similaridades acima de 40% com passos de outros casos de uso, estes valores são boas indicações de que é nos rastros destas ações que se encontram as partes mais específicas do caso de uso.

A contagem de unidades computacionais do SIGEP revelou que apenas a entidade de negócio “ProjetoPesquisa” e alguns componentes de conexão com bancos de dados foram utilizados em todos os casos de uso. A Tabela 4 apresenta uma parte da lista da contagem de Casos de Uso por Unidade Computacional, incluindo algumas unidades que foram executadas nos oito casos de uso selecionados para o teste. Da mesma forma a análise também indica as unidades que foram executadas em apenas um caso de uso, ou mesmo em apenas uma ação ou um fluxo específico.

Tabela 16 – Contagem de Casos de Uso por Unidade Computacional

Unidade Computacional Casos de Uso

[br.ucb.sigep.util.SigepUtil].validaSessaoUsuario 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setTitulo 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setTipo 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setResumo 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setRelatorioFinal 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setObservacoes 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setIdProjetoPesquisa 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setIdPrograma 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setIdEdital 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setEstado 8

[br.ucb.sigep.entidade.ProjetoPesquisa].setDescricaoDetalhada 8

[br.ucb.sigep.entidade.ProjetoPesquisa].getIdProjetoPesquisa 8

[br.ucb.sigep.DAO.PostgreSQLDAOFactory].getProjetoPesquisaDAO 8

[br.ucb.sigep.DAO.PostgreSQLDAOFactory].createConnectionPool 8

[br.ucb.sigep.DAO.GenericDAO].setConnectionPool 8

[br.ucb.sigep.DAO.GenericDAO].closeAll 8

[br.ucb.sigep.DAO.DAOFactory].getDAOFactory 8

[br.ucb.sigep.DAO.ConnectionPool].getConnection 8

[br.ucb.sigep.DAO.ConnectionPool].free 8

[br.ucb.sigep.DAO.BookPool].getInstance 8

6. Trabalhos Relacionados Deprez e Lakhotia (2000) identificaram as dificuldades de se definir casos de testes relevantes para a análise dinâmica na localização de conceitos. Eles apresentaram um método formal baseado em gramáticas. A Localização de Casos de Uso ao adotar um método conhecido e aplicado em diversos projetos de software torna esta tarefa mais clara e objetiva.

A utilização de casos de uso como base para uma abordagem de compreensão de programas foi primeiramente proposto por Bojic e Velasevic (2000). Eles desenvolveram um método para realizar a recuperação da arquitetura de sistemas a partir de casos de uso pré-existentes. O produto final da descoberta arquitetural é um modelo UML que associa casos de uso às classes de implementação do sistema estudado. Este modelo é obtido inicialmente com análise estática, através de ferramentas comerciais, e posteriormente detalhado através de análise dinâmica. A proposta está essencialmente focada em sistemas desenvolvidos com linguagens e tecnologia de orientação a objetos, o que pode ser considerada uma limitação importante. Existem técnicas para obter casos de testes a partir de casos de uso e que poderiam tornar a aplicação do método mais clara e fácil, mas isso não foi destacado. Além disso, como a abordagem tem um foco de recuperação arquitetural o modelo UML gerado não chega a realizar a localização de código fonte, mantendo o mapeamento em um nível de abstração mais alto.

Salah et al (2005) apresentaram uma abordagem semelhante, mas no lugar de produzirem um modelo UML, criaram suas próprias visões com o objetivo de permitir análises em diversos níveis de abstração. Como principal semelhança em relação à proposta deste artigo está a especificação de um ambiente de suporte, com uma base de dados e o uso de rastros marcados com comentários do executor dos casos de teste. Esta é uma noção similar à idéia de segmentar os rastros em ações do caso de uso. Contudo, na proposta deste artigo isso é proposto de forma sistemática – não fica a critério do executor – e a segmentação é efetivamente utilizada nas análises.

7. Conclusão Neste artigo foi apresentada uma discussão das limitações no campo da localização de conceitos e como casos de uso podem trazer vantagens e ajudar a reduzir alguns desses problemas.

De um modo geral, mesmo os trabalhos que se baseiam na idéia de casos de uso enxergam as funcionalidades “monoliticamente”. Nesta proposta, os conceitos se dividem em vários níveis de abstração – casos de uso, fluxos e ações – de forma bem determinada, cada um apresentando informações de forma mais granular ou mais geral, conforme a necessidade do momento.

Entre os benefícios mais significativos dos casos de uso na localização de conceitos estão:

• Um grande ecossistema de métodos, ferramentas e conhecimento já adquirido pelos profissionais do mercado no uso da técnica;

• Conservação da validade dos casos de uso, mesmo após um período significativo de manutenção;

• Diferentes tipos de análises, em diferentes níveis de abstração: dos mais gerais aos mais detalhados;

• Sistematização na geração e automação da execução dos casos de teste.

• De um modo geral, os casos de uso vão sempre precisar de alguma revisão – ou mesmo de serem criados, quando não existirem. Contudo este tipo de esforço acaba sendo distribuído com outras atividades do ciclo de vida do software como gerência de projetos e testes que também podem se beneficiar, de diferentes formas dos casos de uso.

A automação da execução de testes é uma das formas que vêm sendo adotadas largamente nas organizações para agilizar e baratear os testes de grandes sistemas. Durante as aplicações práticas foi identificado que esta prática pode beneficiar também a análise dinâmica, tornando o trabalho mais ágil e preciso execução de casos de testes complexos.

O principal objetivo deste trabalho é trazer a localização de conceitos para o dia-a-dia do engenheiro de software, de forma mais prática. O uso de técnicas e ferramentas consolidadas na indústria de software deve facilitar a adoção nas organizações de manutenção.

8. Referências Bennett, K. H.; Rajlich, V. T. Software Maintenance and Evolution: A Roadmap.

Proceedings of the Conference on the Future of Software Engineering, p73-77, ACM Press. Ireland, Limerick, Junho, 2000.

Biggerstaff, Ted J.; Mitbander, Bharat G.;Webster, Dallas. The Concept Assignment Problem in Program Understanding. Proceedings of 6th Working Conference on Reverse Engineering, IEEE Computer Society Press. Outubro, 1999.

Bojic, D.; Velasevic, D. A Use-Case Driven Method of Architecture Recovery for Program Understanding and Reuse Reengineering. Proceedings of the Conference on Software Maintenance and Reengineering, IEEE Computer Society Press. Março, 2000.

Cockburn, Alistair. Writing Effective Use Cases, Agile Software Development Series, Addison-Wesley, 2000.

Deprez, J. C.; Lakhotia, A. A Formalism To Automate Mapping From Program Features To Code. 8th International Workshop on Program Comprehension, IEEE Computer Society Press, Junho, 2000.

Eisenbarth, T.; Koschke, R.; Simon, D. Location Features in Source Code. IEEE Transactions on Software Engineering, Vol. 29, No. 3. Março, 2003.

EL-Ramly, Mohammad; Stroulia, Eleni; Sorenson, Paul. Mining System-User Interaction Traces for Use Case Models. Proceedings of the 10 th International Workshop on Program Comprehension, p.21-32, IEEE Computer Society Press, 2002.

Gold, Nicolas. Hypothesis-Based Concept Assignment to Support Software Maintenance. IEEE International Conference on Software Maintenance, Novembro, 2001.

Jacobson, I.; Christerson, M; Jonsson, P; Overgaard, G. Object-Oriented Engineering: A Use Case Driven Approach. Reading, Mass. Addison-Wesley, 1992

Lakhotia, A. Understanding Someone Else’s Code: Analysis of Experience. Journal of Systems and Software, v.32, p.269-257. Dezembro, 1993.

Lucca, Giuseppe Antonio Di; Fasolino, Anna Rita; Carlini, Ugo De. Recovering Use Case Models from Object-Oriented Code: a Thread-based Approach. Proceedings of Seventh Working Conference on Reverse Engineering, p.108-117, IEEE Computer Society Press. 2000.

Lucia, A. De; Fasolino, Ana Rita; Munro, Malcolm. Understanding Function Behaviors Through Program Slicing. Workshop on Program Comprehension, p.9-18, IEEE Computer Society Press. Berlim, 1996.

Rajlich, V.; Wilde, N. The Role of Concepts in Program Comprehension. 10th International Workshop on Program Comprehension, p. 271, IEEE Computer Society Press. 2002.

RUP. IBM ™ Rational ® Unified Process ® versão 7.0. IBM Corp. 1987, 2007.

Salah, M.; Mancoridis, S.; Antoniol, G.; Di Penta, M. Scenario–Driven Dynamic Analysis for Comprehending Large Software Systems. Proceedings of the Conference on Software Maintenance and Reengineering. IEEE Computer Society Press, 2006.

Wilde, N; Scully, M.C. Software Reconnaissance: Mapping Program Features to Code. Software Maintenance: Research and Practice, vol. 7, pp. 49-62, 1995

Wilde, N; Buckellew, M.; Page, H.; Rajlich, V.; Pounds, L. A Comparison of Methods for Locating Features in Legacy Software. The Journal of Systems and Software, v.65, p.105-144. Elsevier Science, 2002.

Wong, W. Eric; Gokhale, Swapna S.; Horgan, Joseph R. Quantifying The Closeness Between Program Components And Features. The Journal of Systems and Software, v.54, p.87-98, Elsevier, 2000.

Zhang, Lu; Qin, Tao; Zhou, Zhiying; Hao, Dan; Sun, Jiasu. Identifying Use Cases in Source Code. The Journal of Systems and Software, v.79, p.1588-1598. Elsevier, Abril, 2006.