Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: "Humane Pointcut Languages" [Was: Re: [aspectj-users] AW:Pointcuton a constructor with a custom @Annotation]

On 4/29/06, Wes <wes@xxxxxxxxxxxxxx> wrote:
> > The fragile nature of
> > pointcuts that refer to specific details is an example of breaking
> the
> > Dependency Inversion Principle (DIP) and the Stable Dependencies
> > Principle (SDP),

Sorry, I don't get it.  Why is concretizing an abstract pointcut any
different than concretizing an abstract class or method?  No one
expects less-abstract components to be more stable.

I didn't provide enough detail. Let me elaborate and show how these
principles encapsulate ideas we've discussed in this thread.

Yes, creating concretizations of abstract pointcuts is very much like
concretizing abstract classes and methods; done properly it is a good
design practice. The problem, in both cases, is how we do it, in part
because of the reasons you mention next about stability under
evolution.

As an example, say I have an abstract aspect that supports the
Subject/Observer pattern and I want to use it to watch for changes to
the attribute "name" in class "Person". Typically, I might concretize
an abstract pointcut that picks out the subject join points of
interest, in this case something like "set(String Person.name)". I now
have a dependency on details of a particular concrete class, which is
inherently less stable, meaning these details are more likely to
change, compared to interfaces or abstract classes. Our refactoring
tooling isn't mature enough yet to catch all affected pointcuts
(especially when wildcards are used). Of course, in a pure OO system,
this kind of dependency is also fragile, as Martin discusses in the
articles on the DIP and the SDP that I mentioned previously.

The SDP makes general statements about avoiding fragile dependencies
in favor of more stable ones, with abstractions, like Java interfaces,
tending to be more stable than concrete classes. (This also promotes
more generic and hence reusable code, of course). The interesting
thing about the DIP is that it "inverts" (the "I") responsibility for
defining the interface on which a component depends. Take a typical
layered architecture. Often a lower layer exposes interfaces for upper
layers to use; the dependency points down. This sounds fine at first,
but then the upper layers are now coupled to the lower-layer's idea of
an interface, which may not be reusable with other possible lower
layers. DIP says that instead the upper layer *should* define the
interfaces for the services it needs and the lower layer(s) should
implement those interface. More typically, the Bridge pattern is used
to glue the two layers together; it implements the interfaces defined
by the top layer using the interfaces exposed by the lower layers. If
you picture the bridge as "floating" above and to the sides of the
layers, then the dependencies from all layers to the bridge point up,
inverting the dependency. (The diagrams in the article make it clear
what I mean. I'm not doing justice to the description, either... ;) )

Back to the example aspect, instead of a concrete aspect that points
directly to Person, I should define some sort of Subject "interface"
that Person implements and my concrete observer should depend only on
it. Let's start with an "interface" that's actually an annotation on
the attributes, "@State", indicating which attributes hold state
information (Jonas discusses the virtues of using annotations in his
blog) . Now my pointcut is "set (@State * *.*)".  (First pass)

Now I'm decoupled from fragile, concrete details, going through an
abstraction instead. However, now I will pick out all JPs that are
state-related (and annotated as such). I might instead use several
annotations that partition the information, where "name" is considered
an "@Identifier", for example. However, I could get into tangling of
concerns if I push my assumptions too far.

Another approach is to define a real interface that Person implements
and the aspect advises. The true art for interface or annotation
design is keeping them general enough to handle most needs, yet
avoiding tangling concerns or assumptions about specific concerns into
the code.

Finally, as a pragmatic compromise, I might define one abstract aspect
that defines a pointcut like "set (@State String *.name)" and where
the abstraction is in virtual methods called by the advice. So, *this*
aspect is now a dependent of my more concrete "name" aspect, but it's
still reusable by any other aspects interested in "names". I've kept
the potentially-fragile coupling down to one location and the rest of
the aspects and components remain loosely coupled and stable
(hopefully).

Hope this makes more sense.

dean

I think the problem is that join points might not be intended by
the "original" programmer as such, so they have no apriori stability aside
from their history - structure and naming inferences.  (but see annotations)
Nothing in a pointcut language can make up for a shifting join point model;
indirection only displaces the work (though sometimes usefully back to
to shifting programmer).

As for more abstractions (like AO interface), I personally prefer things
the programmer says in code, so we come to agreement on semantics and
support tool chains.

Wes


--
Dean Wampler
http://www.aspectprogramming.com
http://www.newaspects.com
http://www.contract4j.org


Back to the top