Alguns problemas são resolvidos de maneira mais elegante com a AOP?


19

Eu me deparei com a idéia de Programação Orientada a Aspectos e tenho algumas preocupações com ela.

A idéia básica parece ser que queremos ter preocupações transversais que não são bem modularizadas usando objetos e modularizá-las. Está tudo muito bem e bem.

Mas a implementação do AOP parece ser a de modificar o código de fora do módulo. Assim, por exemplo, poderia ser escrito um aspecto que altera o que acontece quando um objeto específico é passado como parâmetro em uma função. Isso parece ir diretamente contra a idéia de módulos. Eu não deveria poder modificar o comportamento de um módulo de fora desse módulo, caso contrário, todo o ponto dos módulos será revertido. Mas aspectos parecem estar fazendo exatamente isso!

Basicamente, os aspectos parecem ser uma forma de correção de código. Pode ser útil para alguns hacks rápidos; mas, como princípio geral, talvez não seja algo que você queira fazer. A Programação Orientada a Aspectos me parece adotar uma prática ruim e elevar a um princípio geral de design.

AOP é uma boa prática? Alguns problemas de programação foram resolvidos de maneira mais elegante com o AOP?


ahhh, o famoso patch de macacos!
Muad'Dib

1
Eu editei a pergunta para melhorar seu tom e votei para reabrir.
Robert Harvey

O Questio também foi solicitado novamente de uma forma diferente aqui: programmers.stackexchange.com/questions/19344/…
Peter Boughton

Respostas:


19

A Programação Orientada a Aspectos possibilita a execução de certos tipos de programação difíceis de executar, sem espalhar códigos desnecessariamente por todo o aplicativo ou biblioteca, não relacionados às principais funções do seu software (por exemplo, preocupações transversais). Exemplos incluem:

  1. Registro e Monitoramento
  2. Análise de desempenho
  3. Depuração e rastreamento
  4. Desfazer funcionalidade
  5. Validação de entradas e saídas
  6. Transformando o comportamento de objetos existentes
  7. Filtros de Objetos
  8. Implementação de segurança
  9. Gerenciando transações

Confinando essas preocupações transversais a uma única parte do aplicativo e fazendo referência a esses recursos no código por meio de atributos, interceptação de chamada de método ou proxies dinâmicos, você permite o encapsulamento do comportamento transversal; isso tem todos os benefícios (ou seja, um único ponto de modificação) que o encapsulamento forneceria em qualquer outro lugar do seu aplicativo.

O ponto principal aqui é que o AOP encapsula o comportamento 1) comum em todo o aplicativo e 2) periférico à funcionalidade principal do aplicativo.


7

Chegando atrasado para o jogo, mas forneço isso para desenvolvedores posteriores que podem se deparar com essa pergunta.

Eu recomendaria fortemente contra o AOP se o seu aplicativo depender dele para funcionar corretamente. Aspectos funcionam assim:

  • O conselho (comportamento adicional) é aplicado a
  • Pontos de junção (locais onde o código extra pode ser anexado, como início ou fim do método ou quando um determinado evento é acionado)
  • ... onde os padrões pointcut (um padrão que detecta se um determinado ponto de junção corresponde) correspondem aos padrões

Para quem trabalha com computadores há muito tempo, o fato de os padrões serem usados ​​pode ser algo para examinar de perto. Então, aqui está um exemplo de um pointcut que corresponde a qualquer método nomeado, setindependentemente dos argumentos:

call(* set(..))

Portanto, esse é um argumento bastante abrangente e deve ficar claro que é recomendável lidar com isso com cuidado (sem trocadilhos), porque você está aplicando conselhos a muitas coisas.

Ou, diabos, vamos aplicar conselhos a tudo , independentemente do nome ou assinatura!

execution(* *(..))

Então, claramente, devemos ter cuidado porque há muito poder aqui, mas este não é um argumento contra aspectos - é um argumento para cautela, porque há muito poder aqui e a correspondência de padrões pode facilmente dar errado (basta pressionar o seu mecanismo de busca favorito para aop bugs e divirta-se).

Então, aqui está o que parece ser um argumento relativamente seguro:

pointcut setter(): target(Point) &&
                   ( call(void setX(int)) ||
                     call(void setY(int)) );

Isso fornece conselhos explicitamente se forem encontrados métodos nomeados setXou setYem um Pointobjeto. Os métodos podem receber apenas ints e devem ser void. Parece bem seguro, certo? Bem, isso é seguro se esses métodos existirem e você aplicou o conselho correto. Se não, muito ruim; falha silenciosamente.

Para dar um exemplo, um amigo estava tentando depurar um aplicativo Java em que todos de vez em quando retornavam dados incorretos. Foi uma falha infreqüente e não parecia estar correlacionada com nenhum evento ou dados em particular. Foi um bug de segmentação, algo notoriamente difícil de testar ou detectar. Acontece que eles estavam usando aspectos para bloquear métodos e torná-los "seguros para threads", mas um programador renomeou um método e um pointcut falhou em correspondê-lo, causando uma interrupção silenciosa do aplicativo.

Assim, digo às pessoas que, se precisam usar AOP, para tratar aspectos como exceções: em um sistema bem projetado e se nada der errado, eles podem ser removidos e o software ainda funciona corretamente. No entanto, se a funcionalidade do programa depender da AOP, você introduzirá uma fragilidade injustificada no seu programa.

Assim, o log, a depuração e o rastreamento são ótimos exemplos de comportamentos perfeitos para aspectos, mas segurança? Não. Segurança de rosca? Não.

Para uma alternativa robusta à AOP, consulte Características . Em vez de serem apegados ao idioma, eles são integrados diretamente a ele, não precisam de um IDE "sensível a características" (embora possa ajudar) e apresentam falhas no tempo de compilação se os métodos necessários não estiverem presentes. As características fazem um trabalho muito mais limpo ao lidar com a separação de preocupações, porque o problema foi melhor definido desde o início. Eu os uso extensivamente e eles são fantásticos.


Em vez de argumentar que o AOP não deve ser usado para a funcionalidade principal, pode ser mais apropriado dizer que os atalhos que dependem dos nomes dos métodos são uma má idéia. Eu provavelmente argumentaria que o bloqueio e a sincronização também não são bons casos de uso para a AOP.
Código Bling

2

Uma situação em que a AOP pode ser a única solução decente e prática é quando você não tem acesso ao código-fonte . Para usar o exemplo antigo e cansado da preocupação transversal com o registro em log:

Digamos que você queira registrar o fluxo de controle em uma biblioteca de terceiros que você consome. Você tem seu próprio código totalmente instrumentado com instruções de log. No entanto, para esta biblioteca, você não possui a fonte, tornando impossível adicionar suas instruções de log. Desde que você faça ter o bytecode, AOP permite instrumento que terceiros biblioteca de qualquer maneira.

E se você estiver criando um aspecto de Log de qualquer maneira, considere implementar o Log com AOP através do seu próprio código.


O registro é para coisas "interessantes". Como você pode fazer outras coisas além de "entrar com esses parâmetros" e "sair" com o log de AOP?

@Thorbjorn: O registro / depuração / rastreamento é apenas uma das muitas áreas de funcionalidade que o AOP pode ajudar. Eu usei como exemplo para ilustrar meu argumento. O ponto que estou tentando enfatizar é que o AOP oferece mais controle sobre o bytecode de terceiros.
Joseph Tanenbaum

claro, mas eu realmente queria saber se o log do AOP pode fazer mais do que apenas entrar e sair do log?

Depende da ferramenta AOP que você usa, mas certamente existem limites para o que você pode fazer. Pode ser impossível ir além do log de entrada e saída.
Joseph Tanenbaum
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.