Artigos

Tecnologia

Entendendo a Programação Orientada a Aspectos

A Programação Orientada a Aspectos - Aspect-Oriented Programming ou simplesmente AOP - foi introduzida em 1996 por Gregor Kickzales, quando estava no Xerox Palo Alto Research Center.

A AOP, assim como a Programação Orientada a Objetos (Object-Oriented Programming ou OOP), introduz um novo paradigma e um conjunto de diretrizes para facilitar o desenvolvimento de software. Ela pode ser vista como um estilo de programação, por abordar de maneira mais elegante questões que poderiam ser resolvidas de outras formas.

A AOP lida com um problema específico: capturar unidades consistentes de um sistema de software que as limitações dos modelos de programação tradicionais forçam a ficar espalhados por diversos pontos do sistema.

Para entender o espírito da AOP, temos que entender alguns conceitos fundamentais.

Responsabilidades (concerns)

Sistemas de software consistem de um conjunto de "áreas de interesse" ou responsabilidades distintas como, por exemplo, responsabilidades funcionais (lógica de negócio) e não-funcionais (performance, persistência de dados, logging, autenticação de usuários, segurança, verificação de erros, etc.). Existem também as preocupações relacionadas com o processo de desenvolvimento de software, como clareza de entendimento, facilidade de manutenção, rastreabilidade, simplicidade de evolução do software, etc.

Separação de responsabilidades (separation of concerns)

A melhor maneira de se projetar um sistema é através da separação de suas responsabilidades distintas de tal modo que podemos alterar/re-projetar cada uma sem que isto afete as demais partes do sistema. A eficiência do desenvolvimento aumenta na medida em que conseguimos separar as suas diferentes responsabilidades em módulos estanques. Este princípio é razoavelmente antigo, e a OOP nos trouxe uma importante resposta a ele: a classe como uma dimensão para a decomposição de responsabilidades. Mas algumas responsabilidades não são tão facilmente decompostas em apenas uma dimensão...

Responsabilidades transversais (crosscutting concerns)

Em sistemas complexos, sempre existem responsabilidades de interesse comum que são utilizadas por vários módulos. As responsabilidades não-funcionais que citamos geralmente têm esta característica, mas também algumas funcionais. Estas responsabilidades são difíceis de isolar porque são necessárias em vários pontos do código. Em OOP, uma classe oferece uma boa maneira de se separar a maioria das responsabilidades funcionais, mas é bastante limitada quando se trata de responsabilidades transversais. Com a OOP, os crosscutting concerns ficam espalhados por vários módulos em pequenos trechos de código que são, em geral, repetitivos, resultando em sistemas difíceis de projetar, entender, implementar, manter e evoluir.

Um exemplo pode ajudar a esclarecer melhor os conceitos. Imagine um sistema bancário. Este sistema tem como uma de suas responsabilidades funcionais centrais o controle das contas correntes dos clientes, candidata natural a se tornar uma classe. Mas este mesmo sistema tem diversas outras responsabilidades não-funcionais como: logging, integridade das transações, autenticação dos usuários, segurança, performance, etc., que são necessárias como suporte a várias classes funcionais, isto é, elas são transversais às divisões de responsabilidades entre os múltiplos módulos básicos do sistema (crosscutting concerns).

A AOP complementa a OOP por introduzir uma nova dimensão para a decomposição das responsabilidades transversais: os aspectos.

O paradigma da AOP consiste na separação das responsabilidades transversais de um sistema em aspectos (unidades modulares) e a sua posterior composição junto às classes, formando um sistema único. Os aspectos podem ser inseridos, alterados ou removidos em tempo de compilação. Por estarem em um único bloco de código, sua manutenção é mais simples, diminuindo a complexidade do sistema e facilitando o seu entendimento. Além disso, o código das classes fica livre do código relacionado às responsabilidades transversais, o que facilita sua reutilização em diferentes contextos, combinando diferentes aspectos dependendo das necessidades da aplicação.

A AOP envolve três fases distintas:

  • Decomposição: os vários concerns do sistema são identificados e classificados como comuns ou crosscutting.
  • Implementação: os concerns são implementados separadamente em classes (para os concerns comuns) e aspectos (para os crosscutting concerns).
  • Recomposição: o sistema é recomposto à partir dos concerns implementados segundo regras de recomposição. Esta fase é chamada de weaving.

Uma implementação básica de AOP consiste em: uma linguagem para programar os componentes (por exemplo, Java), uma linguagem para programar os aspectos (por exemplo, o AspectJ) e um weaver para combinar as duas linguagens (ferramenta que também faz parte do AspectJ). O weaver é uma espécie de montador que tem como entrada um programa de componente e o(s) programa(s) de aspectos e como saída um programa em uma linguagem específica (por exemplo, Java).

AspectJ

O AspectJ é uma ferramenta open source que acrescenta os conceitos de AOP à linguagem Java, através de uma extensão à linguagem: os "aspects". Ele utiliza Java como a linguagem para a implementação dos concerns individuais, e tem construções para a especificação das regras de weaving, que são especificadas em termos de join points, pointcuts e advices, e tudo isto é encapsulado em um aspect.

Join points: representam pontos bem definidos na execução de um programa onde um determinado aspecto pode ser aplicado. Em AspectJ, join points podem ser chamadas de métodos, acessos a membros de uma classe, etc. Join points podem conter outros join points.

Pointcuts: pointcut é um agrupamento de join points baseando-se em um critério pré-definido.

Advices: trechos de código que são executados nos pointcuts. Um advice contém as alterações que devem ser aplicadas ortogonalmente ao sistema.

Aspects: são similares a classes: têm um tipo, podem ser estendidos, podem ser abstratos ou concretos e podem conter campos, métodos e tipos como membros. Mas são diferentes de classes: não têm construtor nem destrutor, não podem ser criados com o operador "new", podem conter pointcuts e advices como membros e podem acessar membros de outros tipos.

Conclusão

A aplicação de técnicas de OOP para a implementação dos crosscutting concerns resulta em sistemas que são trabalhosos para implementar, difíceis de entender e manter, e também dificultam a evolução do sistema pois pequenas modificações na especificação podem resultar em intervenções em um grande número de classes.

Utilizando a AOP, pode-se criar implementações que são fáceis de desenhar, entender e manter. Deste modo, AOP traz maior produtividade, qualidade e facilidade para a implementação de novas funcionalidades.

Acreditamos que os conceitos relacionados com aspectos estão na sua infância. Muito trabalho de pesquisa ainda está sendo realizado sobre o assunto, mas, apesar disto, já podemos tirar proveito prático deste novo paradigma de programação com o AspectJ.

Referências:

AspectJ Project: www.eclipse.org/aspectj/
AOSD Aspect Oriented Software Development: aosd.net/
Multi-Dimensional Separation of Concerns: www.research.ibm.com/hyperspace/