• Nenhum resultado encontrado

Aplicação dos Casos de Uso na Compreensão de Programas

Os casos de uso podem ser usados na compreensão de programas, através da localização de sua implementação no código fonte. Entre as razões que tornam os casos de uso especialmente interessantes neste contexto estão:

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

• É muito fácil identificar cenários e criar casos de testes a partir de casos de uso. Existem métodos para criar casos de teste a partir de casos de uso que vêm sendo largamente adotados, em especial por organizações que baseiam seus processos de desenvolvimento e manutenção de sistemas no RUP (2007);

• A técnica de especificar funcionalidades com casos de uso está tornando-se 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).

Uma questão relevante é o melhor aproveitamento de esforços. Usando técnicas de engenharia de requisitos, como casos de uso, por exemplo, é possível beneficiar não apenas a compreensão dos programas mais as atividades de manutenção como um todo (ZANLORENCI e BURNETT, 2003).

Utilizar 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 com análise estática, através de ferramentas comerciais, e está organizado em visões e sub-visões, geradas através de análise dinâmica formal de conceitos. Os sete passos que compõem o método são os seguintes:

1. Identificação dos casos de uso de um dado sistema, ou um subconjunto de interesse.

2. Para cada caso de uso, definem-se casos de teste que o cubram. 3. Coleta de informações de execução de cada caso de teste.

4. Construção da relação de contexto entre casos de uso e entidades de código do sistema.

5. Realização da análise formal de conceitos que determinará as visões do modelo 6. Avaliação da qualidade da decomposição com base no grafo da análise formal de

conceitos. Se necessário devem ser acrescentados novos casos de teste e a relação casos de uso-entidade de código deve ser refinada.

7. O modelo UML é gerado pela ferramenta de análise estática e decomposto com base na análise formal.

Entre as limitações deste trabalho podemos citar que ele está essencialmente focado em sistemas desenvolvidos com linguagens e tecnologia de orientação a objetos. Existem técnicas para obter casos de testes a partir de casos de uso e que talvez pudessem deixar 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 ao invés de produzirem um modelo UML, eles criaram suas próprias visões com o objetivo de permitir análises em diversos níveis de abstração. As visões obtidas são pela aplicação desta abordagem são (do mais abstrato para o menos abstrato):

• Casos de uso;

• Interação entre módulos; • Interação entre classes; • Métodos das classes.

Ao utilizar diversos níveis de abstração a abordagem permite uma visão arquitetural, mas que pode ser detalhada até o nível do código fonte conforme a necessidade do mantenedor.

O ambiente utilizado para a obtenção das visões – Figura 4 – possui diversos componentes, entre os quais podemos destacar:

• uma ferramenta – trace marker – que permite a um operador interagir com a coleta dos rastros para “marcar” e destacar mais precisamente os momentos do início e do fim da execução de um caso de teste;

• um modelo de dados relacional onde os rastros são armazenados, juntamente com dados da análise de conceitos, realizada estaticamente;

• consultas em SMQL – especialização do SQL para tratamento de modelos – são usadas para gerar os dados das visualizações

Figura 4 – Ambiente de Compreensão de Salah et al (2006)

O trabalho de Salah et al (2006), como o de Bojic e Velasevic (200), também está fortemente relacionado às linguagens orientadas a objetos – pois suas visões se baseiam em classes e métodos. Além disso, na sua aplicação, os casos de uso não tinham um nível de abstração muito alto (ver seção 4.2.3) o que faz com se reduzam as vantagens da sua utilização.

Outros autores, ao invés de trabalharem no mapeamento de casos de uso pré-existentes no código fonte dos sistemas, inverteram o processo e buscaram extrair casos de uso diretamente do código fonte. Este foi o caso de Lucca et al (2000), El-Ramly et al (2002) e Zhang et al (2006).

Lucca et al (2000) apresentaram uma técnica para extrair casos de uso de programas através de uma abordagem que se baseia na análise de caminhos M-M (método-mensagem) que são formados por seqüências de execução de métodos ligados por mensagens, encontradas estaticamente. A análise dos caminhos M-M leva à identificação de trheads e sub-threads.

Assumindo que cada thread define um caso de uso diferente, eles aplicam heurísticas para sugerir um modelo de casos de uso. O modelo resultante deve ser avaliado pelo engenheiro de software a fim de gerar descrições, documentos de especificação, com os fluxos básico e alternativos, ou mesmo para unir em um único caso de uso casos de uso que tenham sido sugeridos em nível muito baixo de abstração. A clareza do código fonte e o conhecimento da pessoa a cargo da tarefa são fundamentais para a aplicação da técnica.

El-Ramly et al (2002) observaram que a abordagem dos grafos M-M se restringia a sistemas implementados em linguagens orientadas a objetos, com forte suporte ao encapsulamento. Além disso, a análise estática poderia ser prejudicada pela presença de código morto – que não é executado em nenhuma situação possível. Acreditando que estudar o uso real que é feito do sistema pode trazer informações relevantes, eles estenderam um método anterior – CelLEST – que tinha o objetivo de suportar a reengenharia de interfaces de usuário baseado na utilização de rastros de interação usuário-sistema. Para “descobrir” modelos de caso de uso os rastros de interação da interface de usuário são processados por algoritmos de descoberta de conhecimento e busca de padrões a fim de identificar os termos e tarefas que devem corresponder ao interesse principal dos usuários. É necessário então que seja feita uma triagem eliminando termos indevidos e/ou refinando a configuração dos algoritmos de descoberta. Por fim os casos de uso são gerados em forma de texto de linguagem natural a partir de uma ferramenta de inteligência artificial que confere semântica aos padrões de uso obtidos.

Zhang et al (2006) também adotaram uma abordagem baseada em trheads, parecida com a de Lucca et al (2000). Contudo eles chamaram a atenção para o fato dos caminhos M-M não levarem em consideração o controle do fluxo do programa – em comandos como “if”, “while”, “for” e outros desvios condicionais – a premissa de que cada thread define um caso de uso poderia levar a obter casos de uso que não existem na realidade. Assim eles utilizaram um tipo de grafo que leva em conta este tipo de comando, chamado de Grafo de Chamadas com Reserva de Ramificação – Branch-Reserving Call Graph – e a partir dele é que os casos de uso são extraídos, também através de algumas regras heurísticas sobre o grafo, assumindo que cada thread representa um caso de uso. Na última fase, os engenheiros de software precisam ainda validar os resultados gerados automaticamente para determinar se todos os

casos de uso identificados são realmente válidos, os atores que estão envolvidos e assim por diante.

Mesmo procurando extrair os casos de uso diretamente do código, nenhum dos autores consegue prescindir do conhecimento humano em algumas etapas do processo. Essa limitação pode ser relacionada à constatação feita por Biggerstaff et al (1993) de que os conceitos humanos e das linguagens de programação têm naturezas tão diferentes que a automação algorítmica de um mapeamento entre os dois universos é praticamente impossível.

Outra limitação de todos os trabalhos que utilizaram casos de uso na compreensão de programas, deriva do fato de que a estrutura dos casos de uso permite pensar em diversos níveis localização de implementação: caso de uso, fluxo e atividade. Nenhum autor se ocupou de localizar a implementação nestes níveis mais baixos – fluxos e ações. Desta forma os casos de uso poderiam representar conceitos de nível mais alto de abstração, tais como, “emissão de extrato” ou “venda de produto”, enquanto os conceitos menos abstratos, como “salvar” e “imprimir”, poderiam estar descritos nas ações.