Aspect-Oriented Programming Considered Harmful
kupci writes "The 'x considered harmful' cry is a little overused, but there is a Forrester report that discusses some of the pro's and con's of Aspect-oriented Programming, and includes some interesting links. It is mainly based on papers from the University of Passau. It's worth it just for Clark's 'COME FROM' article." From the article: "Aspect-oriented programming (AOP) is intended to address common problems that object-oriented programming (OOP) doesn't address well, plus some problems that OOP itself created. However, AOP is a risky solution: It is a very generic mechanism for solving some very specific concerns and has been likened to a kind of "GOTO" statement for OOP. Like GOTO, it can cause more harm than good."
Wikipedia linkage
In computing, the programming paradigm of aspect-oriented programming (AOP) centers on constructs called aspects, which treat concerns of objects, classes, or methods. The aim of AOP is to separate program code related to the main purposes of the application (its core concerns) from code related to secondary purposes (cross-cutting concerns).
For example, a telecommunications application might have a core concern of routing calls, while code for timing and billing those calls would crosscut the whole object hierarchy. AOP aims to separate the billing concerns from the core concern. It moves code not related to solving the domain problem from the business logic into a separate module. The application code no longer contains pieces of crosscutting concerns scattered across modules; instead, programmers maintain crosscutting concerns in aspects; this makes it easier to maintain both core and crosscutting concerns.
Any program has principled points (join points) where programmers can identify and modify the program semantics. In AOP, programmers specify join points using a language feature called a pointcut, and specify the behavior to join those points by using advice such as methods or functions. Some variants of AOP allow programmers to extend the types in the system. These features enable aspects to implement behavior for concerns that crosscut the core concern of the application.
The goto operation can be rather useful if used sparingly and correctly. If I see a goto jump up (earlier in the function) instead of down, I tend to get worried. But it is useful to break out of nested loops or complicated logic statements.
It is also exceedingly useful for error handling, in that it allows you to skip the bulk of a function and still hit the cleanup section of the function. This gives you two things:
1) you avoid a deep, deep mess of nested if statements
2) you eliminate duplication of code in error handlers (and the bugs that occur later on when someone forgot to update one of those handlers to release some resource they just added)
You have to catch [execeptions] at every point to free stuff, and the nested structures become even uglier than gotos.
The freeing of resources, all resources not just memory, is automatic in C++ once you learn to use RAII.
Look it up. It is one of major improvements of standard C++ over C/C++.
Anyone who generalizes about slashdotters is a typical slashdotter.
Sure. This is an example using the boost::function and boost::bind libraries which have both been available for a long time and are in the process of becoming part of the standard C++ library.If you don't want to use libraries just assign function objects or static class functions.
If you want to do several callbacks at once check out one of the many available signal/slot libraries.
Anyone who generalizes about slashdotters is a typical slashdotter.
A very well respected (if a bit obscure) OO language is Objective-C. It has a few features that are analogous to aspects.
First it has categories, which allow you to add new methods, or replace the implementation of a method in a given class. You add a category to that class that includes, say, a replacement description method, and the new implementation replaces the old. Or you can add a path utility methods to the String class, as another example.
It also has "poseAs", which allows you to insert an object into a hierarchy. Say you have Class B which extends Class A. But you want custom behaviour to be accessible to all As children (including, for example, B). You create Class C, which extends A, and make it poseAs Class A. Now the runtime hooks all clesses that inherit A off of C, which replaces A. A still exists, but is in the background, providing normal inherited functionality to C.
These abilities were one of the things that made Objective C a very powerful OO language. In particular, it allows a particular kind of reuse, by virtue of allowing one to patch someone else's library without having source. So if you want to add the aforementioned path utilities to NSString, you just added a Category in your own code, and your code would run with the extended functionality in NSString (no one elses would, unless they used your category too). This means that often you can make the most out of someone else's code without a complete rewrite.
It isn't all powerful. There are access and visibility restrictions. It is also used to partition code for ease of organization and better modularization. Here's the point:
Because it is a well known feature of the language, you think in terms of categories, and you know to look for categories. This can be aided by tools, but you most definitely need to pay attention to them. But because of this, they are only "dangerous" if you aren't paying attention. And guess what! That's true of programming, period.
i - This sig provided by
AOP is not the answer to everything, but one of the main points of a talk I give at the NFJS show is that you can find tons of uses w/ development aspects without ever having to migrate them into production.
You can enforce (and detect violations of) various architectural decisions (i.e. no direct JDBC connectivity without going through a facade), define and enforce contracts (and leave them out of production), detect threading issues (How would you find all Swing thread abuse cases in a large, multi-threaded application?), get a sense of code coverage, etc. around any arbitrary cut of your system.
If you take the time to build around interfaces and support Object decoration via some variant of factories, you can do some of these things using Decorator and Dynamic Proxies, but you don't always have that luxury.
Tool support has been fundamentally lacking until things like recent versions of the AJDT. It still isn't perfect, but should serve to answer many of the early critics complaining about debuggability and losing track of what is going on.
I am an advocate of AOP in production systems, but you don't have to drink the whole glass to find aspects tremendously useful in development alone. With support for Ant-based builds and whatnot, it isn't even really an onerous task to give it a try.
Don't use AOP for things it isn't a good fit for, but there are quite a few things that can't be done as easily and elegantly without it (at least in Java). As others have pointed out, languages like Lisp and Objective-C have support for AOPish things built in.