Slashdot Mirror


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."

31 of 470 comments (clear)

  1. Executive Whining by idsfa · · Score: 5, Insightful

    There's a new idea in field I am incapable of getting a job in that is gaining in popularity among people I wish cared about my opinions. Buzzword I am dissing is intended to address common problems that buzzword everyone likes doesn't address well, plus something into which I have no insight. However, buzzword I am dissing is a risky solution: Complaint which betrays my ignorance and has been likened to somthing everyone hates. attack by analogy. Buzzword I am dissing will find some uses among people I secretly envy, but for the needs of (me) typical application developers, language gurus would do better to write something I can understand. My paper is important, pay me $50/page to read it.

  2. I'm missing something. by Lord+Kano · · Score: 2, Insightful

    There IS a GOTO statement in C++, an OOP language.

    So how can AOP be like GOTO for OOP when GOTO is already the GOTO for OOP?

    LK

    --
    "Hi. This is my friend, Jack Shit, and you don't know him." - Lord Kano
  3. I like GOTO! by Wabbit+Wabbit · · Score: 5, Insightful

    At the risk of being modded troll, nuking my karma, being yelled at, laughed at, and otherwise folded, spindled, and mutilated, I'm gonna say it:

    I like GOTOs. GOTO has it's place. Even in C++. Sorry all you purists, but there are times when it just plain works.


    *runs and puts on Chinese wicker fighting suit and hides, trembling, behind a flame-retardant wall*

    --
    Nothing is inexplicable; only unexplained -Tom Baker, Doctor Who
    1. Re:I like GOTO! by Anonymous Coward · · Score: 1, Insightful

      Well then the reason I've never encountered that would be that [when not using a garbage collected language] I use exception handling - a better way to handle that situation provided your language supports it.

      I initially wrote "provided your language supports it - I guess that's the crux", but I realised that would be the same fallacy as saying "goto is good because some languages don't have any other branching mechanism". Dijkstra's point was that languages should have good branching mechanisms and ditch goto.

      Thanks for taking the time to post that example.

    2. Re:I like GOTO! by Anonymous Coward · · Score: 1, Insightful

      As somebody else in this thread said regarding an error-checking/cleanup example:

      "suggestive more of the poor expressive power of C than the worthiness of GOTO"

      I'd have to agree. Taken to an extreme, if you're working in a language that only provides goto, then goto will always be the most elegent way to to something.

    3. Re:I like GOTO! by Keeper · · Score: 4, Insightful

      Gotos in C++ are limited to the same method, so no stack problems there.

      Exceptions incur an obscene performance hit, and should be used for 'exceptional' conditions and not expected/handled errors. You also have to worry about the case where someone else adds another exception handler that inadvertantly 'catches' your thrown exception (which makes for maintainance problems later down the road).

    4. Re:I like GOTO! by evvk · · Score: 3, Insightful

      The example was in __plain C__. And besides, exceptions are worthless in a non-garbage collected language. (Ugly kludges in C++ don't count as proper GC.) You have to catch them at every point to free stuff, and the nested structures become even uglier than gotos.

    5. Re:I like GOTO! by Pete · · Score: 3, Insightful
      ur comment Callbacks are everywhere in C++ although these days gives an impression as if, callbacks are part of standard C++ way.

      Well, callbacks are a fairly straightforward concept. They're most commonly used in things like GUI programming, where you do a lot of (asynchronous) event handling.

      But more generally, callbacks are just a very specific example of functional programming, which is just another style of programming that emphasises functions as first-class elements. And because C++ supports several programming paradigms, you can do object-oriented programming, functional programming and/or generic programming - often all at the same time.

      Just like in Perl, there's more than one way to do it. And there isn't any one "correct" way - whatever gets the job done is fine.

      If u r aware, OOP was first implemented on pascal (rather than C).

      No.

      Object-oriented programming is widely recognised as first being implemented on a language called Simula in the 1960s. 1962 to be precise - for Simula I - though Bjarne Stroustrup based C++ most closely on the OO concepts in Simula 67 (1967).

      Pascal was first implemented in 1970, though the original Pascal didn't support object-oriented programming.

      And Pascal had inherent capability, while C++ did not.

      I'm not quite sure what you mean by that. Most implementations of Pascal don't support object-oriented programming at all, much less have "inherent capability". Those implementations that do support OO-style programming usually aren't called Pascal - eg. Delphi, Oberon, Modula-2.

      I could go with the list of many things. For example: C++ did not provide any mechanism to identify whether this object is instance of *THAT CLASS*.

      You're using your terminology confusingly here, so it's difficult to work out exactly what you're saying. But I can say that I've only seen a few occasions where it'd be useful to work out if Base* p is actually pointing at a Derived object, and usually those cases arise when you've started out with a bad design or bad logic. Usually the whole point of having a (pointer-to) Base is that you're supposed to rely on using Base functionality. You're not supposed to care if it might actually be a Derived, the only thing that should matter is that it is substitutable-for a Base. If you need to access Derived functionality, you should have a Derived.

      But anyway, in those cases where you're dealing with someone else's badly designed code, a dynamic_cast should be enough to get around it. Take your Base* and try to dynamic_cast it to a Derived* - if that fails, you haven't got a valid pointer-to-Derived. Go find the person that built the code you're using and kick them. Hard. :-)

    6. Re:I like GOTO! by Anonymous Coward · · Score: 1, Insightful

      Hah! Tell me about how exceptions and named breaks are simpler than GOTOs.

      GOTOs are how computers work. They're close to the machine. If you're thinking in terms of GOTOs, conditional GOTOs, and GOSUBs, and of pointers that are really ints, you're thinking about how the computer works.

      I don't understand what is wrong with all of these programmers who seem to hate how computers really work and want to work in some arbitrary model that distorts their perceptions of efficiency and clarity.

      A programmer can become decent later if he starts out with BASIC, provided he learns assembly next. But no mind can ever be truly adequate to the task of programming if raised on a goto-less language like Pascal or Java.

    7. Re:I like GOTO! by Keeper · · Score: 2, Insightful

      Here is what happens in your scenario:

      void MyFunction()
      {
      char *szString = new char[25]; // do something

      if (somethingfailed)
      return; // do something else

      delete [] szString;
      }

      szString leaks.

      Now, that can be modified as follows:

      void MyFunction()
      {
      char *szString = new char[25]; // do something

      if (somethingfailed)
      {
      delete [] szString;
      return;
      } // do something else

      delete [] szString;
      }

      Now imagine you've got 20 "somethingfailed" type conditions in your method. Now imagine that the cleanup code is non-trivial. And then imagine you need to make a change in that cleanup code... This gets ugly very fast.

      There are lots of ways to 'work around' this sort of problem. All of them, IMO, are unacceptable for various reasons. Either they perform poorly, are hard to maintain, can have unobvious side effects, don't work in all but simple cases, or are obtuse (ie: result in WTF comments from people trying to figure out what is happening).

  4. Buy this document? 249.00??? by the-build-chicken · · Score: 3, Insightful

    Two fifty to hear some twat tell you that a new technology is good, but only in the right circumstances used by trained people.

    What bollocks.

    Do any CIOs still buy this crap? Do the sensationalist headlines do the job and actually sell this bs? "AOP considered harmful"...be afraid...be very afraid!

    I personally don't have a week go by when we don't find another great use for AOP...and we write financial apps...so that blows his 'frameworks only' theory out of the water.

    But I suppose "AOP, useful sometimes in the right circumstances if you make sure you train your people on how to use it, not so useful in others" doesn't exactly sell those $250 a pop articles, does it Carl

  5. Re:For those unfamiliar with AOP by starling · · Score: 5, Insightful

    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.

    Excuse me, but was that supposed to mean something?

  6. I happen to LIKE C++! by n0nsensical · · Score: 1, Insightful

    You insensitive clod!

  7. Re:For those unfamiliar with AOP by Keeper · · Score: 2, Insightful

    It's an example, geeze. It is obviously going to be contrived and simple so that someone unfamiliar with the concepts being demonstrated will be able to understand it.

  8. Re:For those unfamiliar with AOP by Keeper · · Score: 4, Insightful

    Let's say you've got objects a, b, and c.

    Objects a and b do something useful (the core of the application)

    Object c (an aspect) wants to perform an operation when something happens in object a (a concern).

    Object c (an asepct) also wants to do different things when something happens in object a and b (crosscutting a concern).

    I look at this as a really complicated event notification system. Comments calling this 'goto for OOP' also seems rather appropriate.

  9. Side effects++ by evvk · · Score: 5, Insightful

    The bad thing about AOP is that it adds lots of side effects to function calls and can thus make the program very hard to reason about. This is completely orthogonal to (purely) functional programming that intends to remove side effects thus making it easier to reason about programs.

    Functional programming: f(1) == f(1) always, with no other effects to "global state" etc.

    Imperative programming without AOP: f(1) != f(1) necessarily at every point of the code, as the function can access globals. It can also change the global state, so its effect is more than returning its value; it can have side effets.

    Imperative programming with AOP: Same as above, plus the side effects may happen somewhere unrelated to the definition of f itself.

  10. Re:AOP?! by sv0f · · Score: 3, Insightful

    OP is not specific to Java -- I've seen it done with Python

    And it was invented by Kizcales working in Common Lisp. For example, see this brief history.

    Those [like the grandparent] who do not know history...

  11. Forrester is just another clueless IT consultancy by tyates · · Score: 5, Insightful

    The big IT consultancies like Forrestor, Meta, gartner, etc are intellectually bankrupt. If you want an example, read the free article off of Forrestor's web page on IT metrics. It's absolutely worthless. Believe it not, it says that you should evaluate your IT department based on a balanced scorecard that is calculated by, among other things, the number of steering commitee meetings you have. Yes, you read that right, the more meetings the better your department is.
    These consultancies ran out of ideas a long time ago, and are trying to turn IT ito some Six Sigma pseudo-science. It doesn't work, but idiots still buy into it because it sounds impressive.

    --
    Tristan Yates
  12. Re:Oh gee by Bodrius · · Score: 4, Insightful

    No, the problem with GOTO is that, as a consequence of being an unstructured flow control change, it makes it impossible to trust your reasoning about code because it destroys your ability to scope it.

    To quote: "... it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress ..."

    I think Dijkstra's point was that any construct that does this is harmful.

    Structured constructs are typically less liable to do this, but only because they are visible and the structure is known.

    AOP does have the ability to inject arbitrary code in your function that can change its semantics and you cannot see this when reading the affected code.

    No matter how structured that change is, its invisibility makes it impossible to fully understand your code from the source code without 'weaving in' all the aspects explicitly. Like GOTO, it destroys your ability to scope your reasoning of the code to the local view.

    As much as I love AOP for a class of problems, this is a very valid concern that needs to be addressed.

    It's certainly not the first language featureset that faces this problem; OOP can deal with its own issues with design by contract, either through documented best practices or by enforcing it in the language. I haven't seen much in AOP there, beyond the absence of problematic examples (which would typically come from real-world use).

    --
    Freedom is the freedom to say 2+2=4, everything else follows...
  13. To paraphrase Mr Heston... by andrewjhall · · Score: 2, Insightful

    All these arguments about different methodologies and techniques being harmful or not boil down to one thing:

    "There are no good constructs, there are no bad constructs; a compiler in the hands of a bad programmer is a bad thing, a compiler in the hands of a good programmer is no threat to anyone - except the patent system."
  14. Re:best tool for the task by Bodrius · · Score: 2, Insightful

    Funny, this is not the first time I heard of this complaint and, for example, I wouldn't think Anders Hejlsberg was afraid of learning a new language feature considering his career... (the question on AOP is asked within the first two mins if you don't want to watch the whole thing).

    The concern predates the report for quite a bit, and from some reliable sources. This is not a surprise, as I would think the role of companies like forrester is to communicate trends like these, not to create them out of the blue.

    You are right, programmers should choose the best tool for the task. But an issue with AOP as commonly proposed is that you can use the wrong tool and do the wrong task whether you choose it or not, because the weaving is not happening on your request (pointcut), but on the aspect's (advice).

    Depending on the approach of the AOP framework this could be a risk at the team level (static weaving), or at the user level (dynamic weaving) because keeping track of all the aspects introduced by other people in your code is hard/impossible.

    AOP based on declarative annotations could help a lot, but for dynamic weaving (which still can be extremely useful) the main problem doesn't go away.

    Maybe providing limitations to the semantics of an aspect (in terms of invariants it must keep) would be a solution, but that would limit AOP to a non-general programming model, and for that we would have to define the classes of problems where it may be 'useful' or 'harmful', or provide a general way to define these limitations by the application (since we assume they are domain-specific).

    In any case, this does not seem to me like the kind of criticism coming from people afraid of a "new thing".

    Rather, it seems the kind of criticism a new technology faces when applied to 'real world' problems and projects, which is a good sign that AOP is taken seriously enough by mainstream development teams, and that there will be people working on solutions to these problems.

    --
    Freedom is the freedom to say 2+2=4, everything else follows...
  15. Re:Of course by drsquare · · Score: 3, Insightful

    Well, assembly is hardly a language that encourages large, well-organised programming projects, so you've pretty much supported his point.

  16. Re:best tool for the task by 10am-bedtime · · Score: 2, Insightful

    if you don't try to write OO code in lisp, how do you know it cannot be done (and done well)?

    hint: AOP is just half-assed CLOS.

    (no worries, i don't use any of this stuff, either. ;-)

  17. This doesn't deserve to be a Slashdot article by PleaseDontBeTaken · · Score: 2, Insightful

    A story that refers people primarily to a uninformative abstract on a $249 for-purchase paper simply isn't worthy of being an article on Slashdot.

    If I could mod down the story choice, I would.

    Sorry to be a downer, but this needed to be said.

    --
    --
  18. Re:best tool for the task by pkhuong · · Score: 2, Insightful

    You lost your credibility when you wrote: "Nor do I try to write OO code in LISP (despite the horrid OO extensions for LISP) because each language has it strengths and weaknesses." Given that Common Lisp is actually CLOS, an object-oriented language (one of the first ones, and one that has been called one of the few real OO language by Kay), I find it difficult to consider the standard as an "horrid extension".

    I think that, a priori, we should read criticism as an opportunity to improve concepts, not merely dismiss them. The "each language has its strengths and weaknesses" PoV, while often true, makes it easy to fall into a trap where each language or concept evolves in a vacuum, instead of becoming better and unifying concepts together by generalisation.

    --
    Try Corewar @ www.koth.org - rec.games.corewar
  19. Re:best tool for the task by maraist · · Score: 2, Insightful

    It's very rare that java code at least doesn't call a million functions to perform even the most basic operations.. Want to iterate over a collection.. Most likely you use collections instead of arrays anymore for EVERYTHING.. Why? because there are a million tools which enhance collections, filters, queries, dynamic expansion/contraction, nice default toString capability, arbitrary nesting, etc. So if what you're trying to do is print something in a while loop, you can custom taylor your aspect to capture the exact looping point.

    Likewise with the dozens of other "no-function-is-larger-than-a-screen" operations. If you want a logging point, make sure you throw it into a method.

    Ok, what about the overhead of calling functions in loops.. Got you covered, it's called JIT. Performance is no longer the reason to use C over VM's. A good C compiler might not know the optimal time to inline code verses leave functions separate. But a JIT can.. Sure it'll take many iterations to figure it out.

    This applies to aspects as well. Even though you're adding large amounts of code each each method (entry/exit points), it's likely that the most commonly used points will be inlined, re-arranged for optimal execution, etc.

    That being said, I haven't been happy with using aspects for anything that directly affects functionality.. So the example of grabbing a semephor would make me ill.. In a previous life, we used aspects as a security model.. Every method invocation of a certain category had it's returned contents acess-control-restricted. The problem was that functionality started relying on it. We wouldn't redundantly check for things, but that meant that there was magic in the code.. We justified it by saying that we're effectively segregating the database.. You physically can't get to data that you don't directly or indirectly own, so you can simplify your programming assuming that you have access to everything. Of coures this doesn't translate into SQL calls that return counts, and what-have you, so the limitations creapt up too often..

    But logging has no direct affect on an application. Statistics gathering, or run-time debugging of hard-to-reach code. Trace-paths. Possibly even event generators. Things that at the very least don't affect the operation of what a class logically wants to do or provide. Afterall most event generators are hidden from the general work-flow. They have internal fireXEvent, and side-interfaces which expose registerX or what-have-you.

    That being said, current AOP adoption is too shaky.. Either you have to manually wrap objects with proxies, or you have to run a post-compiler, which plays havoc with other post-compilers (like cactus).. You can only really safely have one post compiler, and so you should probably have no post-compilers; it's a broken concept. Something like jboss with it's class-loader runtime bytecode enhancement is cool, but not everybody wants to run under jboss.

    So unless the language itself adopts it, I'm not a huge fan of AOP right now.

    --
    -Michael
  20. Re:Oh gee by maraist · · Score: 2, Insightful

    AOP does have the ability to inject arbitrary code in your function that can change its semantics and you cannot see this when reading the affected code.

    Well, except that AOP can only modify code in a structured way.. You can replace a method (no more obscure than method over-loading), you can wrap a method, turning it's body into a nested scope (again similar to a method which calls super). Yes they have before and after methods, but these are mere conviniences to the wrapping of a method.

    My argument is only that while AOP does hurt readibility, it's not MUCH different than holding a reference to a base class, and not realizing that your instance is really a derived class which over-loads your method. If you don't have the proper tools to warn you that a method is over-loaded (IntelliJ's Idea, or I believe eclipse), then you aren't privy to the details of execution. Moreoever, there ARE AOP analysis tools which can warn you that an aspect has wrapped this method. Thus, provided sufficiently intelligent tools v.s. sufficiently obscure inheretance points of basic OOP, the whole readibility point is moot.

    My only concern with AOP is in definine an aspect that is more than you can chew. It may initially solve your problem VERY elegantly, but as the scope of the aspect grows, you can find more and more hacks which dramatically reduce understandibility of the code. And worse, can allow obscure bugs to appear. As I've said in other posts, I prefer aspects which do not directly affect the ability of a code block to do as it conceptually is designed to do. They must have side-effects which are useful to the aspect, and nothing else. Logging/tracing are perfect examples. Problem is to find other examples. Moreoever, these are "aspects" which could easily be implemented by a given VM.

    --
    -Michael
  21. Re:Of course by iamacat · · Score: 1, Insightful

    I swear C.Sci professors ban using goto for much the same reasons religions control sex - to bully students into total obedience by giving them difficult, meaningless restrictions. In this case, transforming code that is naturally expressed with goto by adding boolean flags, switch statements and so on. Unnecessary inline functions is a new one for me though :-)

    In fact, C if statements nested more than 3 levels are damn hard to read, especially once "}" is not on the same page as "{". It's a very common mistake to put some code after the wrong brace. In this case, outer levels of if/else should be replaced with if (...) goto for readability.

  22. AOP is a two edged sword by MemoryDragon · · Score: 2, Insightful

    Just like goto, which I would not totally consider harmful. Goto has its place in programs which need a precise command which maps directly to a processor jump instruction, therefore goto or similar constructs are widely used in system near programming.

    I have to admit, I stayed away from AOP for a long time, but that stuff can be really useful if applied in the proper manner. The usual application has lots of sideconstraints which basically stain your algorithms up to a point, where you end up having 2/3rd side constraint code, 1/3rd algorithmic code. The side constraint is constantly the same over and over again, only altered slightly according to the state of the algorithm.

    Now if you move that code in a well documented and clean manner into aspects, you can gain a lot. Aspects however are a deadly construct, if you go the AOP is everywhere manner and dont limit yourself to the basic rule, use it seldom and use it wisely but use it whenever you can achieve a cleaner code with it. If you go the aspect here aspect there route, you end up in a bigger mess than with a huge spaghetti code and 100 gotos in there.

    Perfect examples for AOP are, to move the error handling code of checked exceptions out of the algorithms into aspects, another one would be to get a clean semi automatic transactional scope in methods which are called from the outside. Both things can be achieved with aspects in a much cleaner way, than with traditional programming, but if you use this stuff in that manner, document it and comment it, otherwise the persons who will follow you cannot see that the method is in a transactional scope.

    So aspects are definitely worthwile using (I learned that once I jumped over the wall of considering it a deadly construct), but you really have to be careful to limit it to a few problem domains.

  23. Re:For those unfamiliar with AOP by mysticgoat · · Score: 3, Insightful

    A better example might be a computerized patient record system (CPRS).

    In a CPRS, it is clear that the core concerns involve information related to the patient's health. However if the institution is going to stay in business, there is a strong secondary concern with regard to diagnosis and treatment costs, billing, and so on. Obviously a healthy hospital has to deal with both of these.

    AOP's promise in this situation is to allow these two mission-critical concerns to be temporarily divorced from each other, so that in a medical emergency the patient will get the treatment he needs in a timely way, without doctors and nurses having to deal with billing and cost issues (Clippy: "It looks like you want to defibrillate the patient. Would you like me to compare the costs of alternate treatment modalities?")

    I've not run into this "AOP" thingee before. My impression is that the problems it is supposed to solve would be better approached by a change in the object hierarchy-- that its use would be sort of like adding epicycles to epicycles when a Copernican revolution is really needed. In the CPRS example, rather than having a PATIENT object with healthcare and billing concerns, it might work better to have TREATMENT and BILLING objects that were separate components of the PATIENT object.

    I'm not convinced that the problems AOP is intended to solve couldn't be finessed by refactoring into a different hierarchy of objects.

  24. Re:Of course by Dachannien · · Score: 3, Insightful

    For example, C has break, continue, and the closing squiggles of for and while statements.

    But all of those statements are used in the context of some logical block, and in some sense "operate" on that block. GOTO is/does not - in C/C++, at least, the only restriction is that you must GOTO a label that's in scope at the time.

    "High" level languages makes programmers not as aware as they should be when they're moving a different value into the instruction pointer,

    High level languages also relieve the programmer of the need of thinking about things like stack frames, heap management, and register usage. A programmer should in a general sense understand how these things work, but there doesn't need to be a constant awareness of those factors, because the compiler is designed to take care of them instead. Programmers working on hardcore optimization might have an interest in those low-level details, but a good optimizing compiler will take care of most of that before the programmer even starts to think about optimization.

    The point in my original comment was that, in assembler, not using JMP reminds one of, "You can't get very far in life without saying 'is'". But the last time I've needed a GOTO was when I was a teenager naively programming in BASIC on my old C-64.