Thursday, October 12, 2006 

Cross-cutting concerns are NOT always aspects

We usually spend some effort giving structure to our software. Depending on our language, paradigm, and approach, software will be structured around functions (good ol' structured programming, or to a larger degree the functional paradigm), data (SQL-land, where data is king, and functions are servants), or classes (object oriented programming).
OOP is (mainly) built around the principle of information hiding: unstable details must be hidden behind stable interfaces. Of course, structured programming allows information hiding as well. It's just easier in OOP-land. OOP allows for some separation of concerns as well. Often, we can find a concern and encapsulate it neatly inside a class, or a small group of cooperating classes.
Structure emerges as we try to separate concerns and apply information hiding. It as been argued, however, that most contemporary languages (and paradigms) only allow ONE structure to emerge. Within that structure, we have decomposed concepts into finer-grained abstractions, and mapped those abstractions to classes. This is known as the principal decomposition, which is also the only one we have in traditional OO languages. While most authors seem to equate the principal decomposition with the inheritance hierarchy, that's a limiting view. The principal decomposition is the entire class lattice, including aggregation, composition, and so on.
Still, some concerns can't be easily isolated within the principal decomposition. It's not really that you can't - but you have to change the structure, so that those concerns become part of the principal decomposition. In some cases, by doing so, you're forced to move other concerns outside the principal decomposition.
Where do they go? Pretty simple: if they're not part of the principal decomposition, they will be scattered around. Part of a concern will be implemented in method M1 of class C1, part in method M2 of class C2, and so on. The downside, of course, is that understanding the systems gets harder, and maintenance may require more testing, as we lack the so-called "unit of change". The so called "tyranny of the principal decomposition" is what forces a concern to be either encapsulated inside it, or scattered around it.
AOP was born to deal with [some] cross-cutting concerns. It's interesting to note that AOP does not propose to eliminate the principal decomposition (except in the most adventurous hyperspace approaches). In this sense, AOP is not an antagonist paradigm: it can live side by side with existing paradigms, and it usually does. In the beginning, technological cross-cutting concerns were tackled. Logging, transactions, synchronization, contracts, were all considered candidates for cross-cutting concerns in the AOP sense. Nowadays, the focus is switching to consider aspects as a full-fledged design tool, together with classes. There is an interest in defining "early aspects", that is, to find aspects during design, without restricting to implementation-level details like logging.
It is important to understand, however, that not all cross-cutting concerns are aspects, or must be dealt with using aspects. An aspect is a relevant concern that has been left out of the principal decomposition, because modeling that concept inside the principal decomposition would move some other fundamental concepts out. Otherwise, it's just plain bad modeling: we could have easily encapsulated the concern inside the principal decomposition itself.
In this sense, I'm afraid I don't like Jacobson's idea of selling Use Cases as early aspects (see "Aspect-Oriented Software Development with Use Cases", Addison-Wesley).
I guess everybody, at one point or another, has noticed that uses cases didn't map well to an object-oriented view of the problem domain (or solution domain, anyway). Use cases are so much about functions, and so little about classes, that some clash is unavoidable. Now Jacobson is telling us that it's fine: use cases are aspects, so they naturally cross-cut the principal decomposition. Which is a pretty bad idea, for a few reasons:
1) This stuff has already been invented in the 80s by James Martin. It was called Information Engineering and relied on a matrix to model functions cross-cutting data. It didn't work great back then, and won't work great today.
2) This is rationalizing a bad development process, where your class model and the system you want to build upon that model just don't match.
3) Even if you go so far as to consider use cases as aspects, they will match poorly with current AOP languages. A use case is realized mostly a sequence of calls to other objects. There is no natural way to map this into advices and pointcuts. This is because use cases form the main functionality of the system; they're not sideways aspects we want to plug-in. They may cross-cut a class model, but they are not aspects. They're just at odd with the class model.
Where Jacobson may have a slightly stronger point is that Extension Use Cases can be seen as aspects, as they can be modeled as a single concern from one perspective (the use case view) yet often cut across several classes (or methods) in the class view, even after the base use case has been implemented. Still, is any change that requires to (e.g.) subclass more than one class an aspect? I would say no, if that change is about extending the main functionality of the system, as Extension Use Cases usually are...
Comments:
Come al solito imparo più da un tuo post sul blog che girando su internet alla ricerca di aticoli.
Mi è venuta in mente una proposta: perchè non posti una lista di articoli/libri per il software architect? Una specie di percorso guidato per chi voglia capire what are behind e non solo ad utilizzare la tecnologia. Devo dire che finalmente ho capito un po' meglio l'aop e sono riuscito ad inquadrarla meglio grazie al discorso della principal decomposition :D
 
Per ora (ma non e' la stessa cosa) nella pagina dei link appare un elenco di libri ed articoli estratto dai miei post nel blog (quelli taggati).

Tempo fa avevo pensato di aggiungere al sito un elenco di "classici" dell'ingegneria del software. Avevo anche iniziato a stendere l'elenco. Se lo recupero lo metto perlomeno sul blog. Di nuovo, non e' esattamente la stessa cosa (ovvero, non e' un percorso guidato) ma e' gia' un primo step. Poi vediamo :-).

Grazie per il suggerimento!
 
Se non ho malinteso il senso del post, ci stai mettendo in guardia dall'attuale tendenza di estremizzare l'utilizzo dei costrutti AOP, tendenza che arriva addirittura a stravolgere il senso del design OO di un sistema arrivando a definire come aspects gli use cases.
Ho la sensazione, e quantomeno nei progetti in cui sono coinvolto e' piu' che una sensazione, che l'utilizzo dei cross-cutting concerns sia una spendida scusa per non revisionare un design che NON tiene conto di aspetti importanti di un sistema (perche' sono stati dimenticati, perche' i requisiti sono stati revisionati o il committente richiede nuove funzionalita'). Nella totalita' dei casi in cui sono stato in qualche modo coinvolto, un refactoring parziale del design del sistema sarebbe stato sufficiente a includere i cross-cutting concerns nella principal decomposition, ma naturalmente la prospettiva di una re-engineering spaventa molto.
Sono propenso a pensare che l'AOP possa essere in questi casi un valido aiuto "economico" (puo' far risparmiare tempo e fatica), ma credo altresi' che la capacita' espressiva di un linguaggio OO sia sufficiente a delineare interamente una problematica applicativa.

Michel
(ma possibile che sia un tifoso cosi' sfegatato del'OOD?!?!)
 
Michel, Credo che l'intento del post non sia quello di mettere in guardia dall'uso dell'aop, anzi credo che Carlo stia diventando anche fan dell'aop (dal giusto punto di vista). Credo che lo scopo sia di far considerare l'AO come complemento all OO. Dico AO perchè il punto focale è proprio quello di inserire una fase di analisi e design degli Aspects, non intesi più solo come infrastutturali, ma anche come parte integrante del dominio del problema.
Il problema che c'è con gli use case (almeno mi sembra di capire) è che sono sì cross-cutting ma non concern, e quindi non aspect! Ma credo che il suo giudizio sull'aop sia positivo e si aspetta sviluppi complementari all'OO.

Spero di averci centrato!
 
Il vero obiettivo era "solo" quello piu' diretto: mettere in guardia dal tentativo di spacciare gli use case come "early aspects" solo perche' sono crosscutting su alcune classi del business domain.

A latere, cercavo di chiarire alcuni concetti, anche perche' vedo per ora nella AOP la solita, gran confusione degli inizi.

Come accennavo in un altro post, l'AOP e' comunque un paradigma che mi interessa molto, piu' per i suoi risvolti di design che di codifica (per ora i vari linguaggi AOP-based mi sembrano piuttosto bruttarelli, e mi convinco via via che il dynamic weaving e' per molti sistemi una via migliore rispetto allo static weaving, con alcune possibili eccezioni come Aspect-C, ammesso che abbia una chance).

Tornando alle questioni di design, incluse quelle sollevate da Michel: cio' che mi piace dell'AOP e' il suo riportare l'attenzione sulla separation of concern. Talvolta, come dice Michel, si puo' riportare qualcosa dentro la principal decomposition tramite un buon refactoring. Ma e' sempre giusto? Qui servirebbe un esempio concreto (prima o poi gli dedico un post) ma posso gia' anticipare che in diversi casi il risultato non brilla.

Prendiamo un esempio piccolo (su cui magari costruiro' piu' avanti un esempio piu' grande). Un semplice Button. Button ha almeno due grossi concern: quello grafico (disegnarsi, con tutte le variazioni del caso [piatto, 3D, con animazioni al click, all'hovering, ecc]) e quello comportamentale (segnalare un evento, o mandare un messaggio, o invocare dei listener, o quant'altro). I due concern sono "dentro" la principal decomposition solo per finta, nel senso che entrambi sono tipicamente cross-cutting su tanti altri controlli grafici.
Se guardate MFC, o il framework .NET, o qualunque altro, tutti hanno un meccanismo di notifica usato in modo cross-cutting, ed hanno aspetti grafici cross-cutting (per "consistenza").
Non e' facile a suon di sola OOP creare un sistema ben disaccoppiato ed al contempo efficiente e semplice da usare, che non comporti gerarchie parallele (es. dei ButtonRender o simili) che sono comunque dei cross-cutting concern in disguise, e che alla fine non costringa il programmatore a salti mortali in nome di una bellezza astratta del design.
Piu' facile realizzare qualcosa di buono con OOP + template, che usati per il verso giusto possono condurre verso l'AOP (sino ad un certo punto); questa era anche una delle buone idee di Alexandrescu, forse troppo mescolate alla metaprogrammazione template per diffondersi realmente.
Ancora piu' facile con un sistema a mixin layers, concetti vecchi che diventano improvvisamente piu' interessanti in ottica AOP.

Detto questo, resta vero il commento di Michel che una certa parte della letteratura AOP sembra piu' preocupata (concerned :-) di supportare attivita' di manutenzione / patch di codice esistente, piu' che di fornire strumenti di design. Un fine non meno importante, ma che per ragioni varie mi interessa meno (cosi' come mi interessano poco gli "aspetti" canonici come tracing, transazioni, ecc, perche' li trovo limitativi nell'esprimere le reali potenzialita' del paradigma).
 
Post a Comment

<< Home