Architectural Enforcement with Aid of AspectJ

After working some time within the software industry, you get a feeling for good software architecture. Or, to be more honest, you get a creeping feeling when the architecture is really bad. That is when the code is tangled like a Gordian knot. After some futile refactoring attempts, you consult the software architect at your company and you will be given a design document stating the architectural principles that should be obeyed during software development. It is a nifty piece of paper and you can tell by looking at it that someone has spent a lot of time working out how the software should be structured. The bad news is that it has little resemblance of the current state of the code base.

Recipe

So how can you shape up the code? Yet better, how can you prevent that the code turns into spaghetti in the first place? One way of looking at architectural requirements is that they are crosscutting concerns that are scattered throughout the software. As such, they can be implemented and enforced by using AOP, aspect-oriented programming. The recipe is pretty straight forward:

  1. Implement a pointcut that finds the violations of your architecture.
  2. Implement an advice that notifies you about the violations.
  3. Wrap the pointcut and the advice into an aspect.
  4. Refactor your code and exercise your aspect until all architectural violations have been removed.

Example

This recipe of using aspects as a way of enforcing architectural rules can be applied in any kind of project, for example to enforce the MVC pattern, to separate one domain from another in a DDD project and so on. In this particular example, the application is based on a three layer architecture. The top layer being the GUI layer, the middle layer is the service layer and then there is the DAO layer in the bottom. Each layer has a separate package, as stated below:

SomeGui.java

SomeService.java

SomeDao.java

Architectural Enforcement

Architectural Rules

Four architectural rules have been defined:

  1. The GUI layer must not access the DAO layer
  2. The Service layer must not access the GUI layer
  3. The DAO layer must not access the Service layer
  4. The DAO layer must not access the GUI layer

These rules are the candidates for defining the pointcuts that should be implemented. An example of code that would violate the first rule is:

BadGuiImpl.java

Using AspectJ, two pointcuts have been implemented to trap the violation. Additionally, AspectJ also provides the @DeclareError annotation that can be used for the advice implementation. Finally, an aspect that comprises the pointcuts and the advice has been created:

ArchitecturalEnforcement.java

Exercise the Aspect

How should you use your aspects to enforce the architecture? Since we now have the tools to automate the architectural review, you should use them frequently. AspectJ has support for compile time weaving which means that the advices can be woven into their corresponding join points during source code compilation. The aspectj-maven-plugin can do it for you:

pom.xml

Result

If you have put everything together correctly, you will find that you will get a compile time error when you attempt to execute mvn compile:

You can also see the error in your Eclipse IDE if you are using the AJDT – AspectJ Development Tools plugin:
Eclipse Screenshot

Notably, the implementation above was just one of the stated rules. The implementation of all four rules together with some examples that break them and the Maven pom file are available for download for your convenience.

Considerations

There are some things that you may want to consider before introducing aspects as a tool for automated architectural enforcement:

  • Error or Warning

    A compile time error is a powerful tool that prevents the developer to commit any code that does not conform to the architectural rules (presumed, of course, that the code is actually compiled before being checked in). A less brutal way of introducing aspects as a part of architectural review is to use the @DeclareWarning annotation rather than the @DeclareError that was used in the example. Consequently, any architectural offenders will be punished with a compiler warning rather than a compiler error.

  • Performance

    The compile time will increase when you add more architectural rules that should be obeyed, that is when you add more pointcuts. Likewise, the compile time will also increase when your code base grows, because of the increasing number of join points in the code. By limiting the aspectj-maven-plugin to certain maven profiles, the developers only have to verify that their particular module conforms to the rules. Alternatively, all modules can be verified by the integration server during nightly builds. The drawback is that the advantage of having the architecture enforced before the code is committed to the version control system will be lost.

  • Limitation

    The aspect above can only trap architectural violations when a method is being called. Regrettably, any unused declaration that would violate the architecture will pass unnoticed:

    AnotherBadGuiImpl.java

    One solution is to create another pointcut, such as @Pointcut("set(*..*.*dao*..* *)"), that traps the assignment of the someDao member variable.

Wrap Up

Education of the developers and repeated manual code reviews have been the traditional ways of improving software architecture. Unfortunately, it is not good enough. It is always a good idea to have skilled employees, but even experts do make mistakes. After all, people that manually review code are only humans, which implies that the reviews are resource demanding, yet error prone. With the powerful tools of today’s IDEs it is very easy to do refactoring hastily and soon the code starts to degrade. With a proper implementation, AspectJ offers one way to automate architectural enforcement, hereby preventing architectural drift.

Edit

2010-04-16: Added screenshot of AJDT plugin and an example of how the “set” pointcut can be used.

Mattias Severson

Mattias is a senior software engineer specialized in backend architecture and development with experience of cloud based applications and scalable solutions. He is a clean code proponent who appreciates Agile methodologies and pragmatic Test Driven Development. Mattias has experience from many different environments, including everything between big international projects that last for years and solo, single day jobs. He is open-minded and curious about new technologies. Mattias believes in continuous improvement on a personal level as well as in the projects that he is working on. Additionally, Mattias is a frequent speaker at user groups, companies and conferences.

This Post Has 17 Comments

  1. @Matt: Thank you! If you like, you can replace the interceptor in your example with a pointcut that finds a marker annotation. All you have to do is to replace the withinGui() pointcut in my example with:
    @Pointcut("within(!@YourMarkerAnnotation *)")
    public void missingYourMarkeAnnotation() {}

    @William: Interesting project. I guess one would track the package names of the executing classes by using the BEFORE_BEGIN and AFTER_END events (similar to an around advice, but using instrumentation rather than aspects), and throw an exception if any architectural rule is violated?

    @Matt and @William: I find your articles interesting and they both address my key concern; automation of architectural enforcement. From my point of view, there is an advantage of using compile time verification rather than runtime verification. It enables early architectural enforcement of the entire code base. In other words, the architectural enforcement is decoupled from the need of executing code, let it be tests or the application itself. This would probably not be an issue if project is well managed, but if the project is immature, has poor test coverage or lots of dead code, it is possible that architectural violations will pass unnoticed.

  2. Very cool. I’m going to investigate this for the large legacy project that I’m stepping up as a Solution Architect for. I’ve seen several horrifying examples that is breaking the architecture in that code base.

    Have you thought about packaging this as a plug-in and present the information visually in Hudson or Sonar? I think this kind of functionality practically begs to be encapsulated in a plug-in that is easily configurable and resusable across projects.

    Magnus

  3. Just like in security you need to combine/layer multiple defense mechanisms so I see a need for both compile time and runtime checking.

    I will post a blog entry next week demonstrating how this [your use case] can be easily achieved a number of ways today using events, stack and tierpoint probes provider extensions.

    By the way our probe naming is not coupled to Java so we can do this for any JVM supported language including JRuby, Jython, SQL, even HTTP requests. You could even use additional context information related to the current activity.

  4. Hi Mattias,
    nice post. However, you can write pointcuts that declare errors/warning also for situations different than a method call, using the get/set point cuts, or hasField, hasMethod. You could trap if a field containing a dao is accessed (setting or getting it) or if a view class contains a DAO in a field, or even if a view class contains a method that receives in some form a DAO.

    Other than static error/warning delcaration, we often emply also runtime checks, that will throw an exception during test execution, in the case where, for example, from a view we “reach” a DAO without going thru the service. Runtime checks can express more complex rules, cause there are situations where the compiler alone cannot determine the application state correctly, while at runtime you have much better support. Since code should be compiled AND tested before checking it in, runtime checks should protect the code as well as static checks.

  5. AOP can indeed be used for architectural policy enforcement; see examples 2 and 4 here:
    http://www.javaworld.com/javaworld/jw-04-2002/jw-0412-aspect3.html
    However, I think that the 3-Tier example above calls for much simpler means. In this case we should have three modules/projects in our IDE, each having a dependency just on the one it needs. Next, use the power of the build tool (Maven/Ant), by configuring its compile task dependencies accordingly, and cleaning up the classpath of each task accordingly.

  6. @Magnus: I don’t know if there are any specific build server plugins that are particularly useful in this context. The JDepend Hudson plugin will display all dependencies, but as far as I know it has no support for adding architectural rules. If you are an Eclipse user, you can install the AJDT plugin. Once enabled, it will list the errors and warnings in the “Markers” tab, and there will be a notification visible in the margin of the source code if a violation is trapped. Additionally, you may also consider buying a commercial tool that allows you to manage the architecture of your software without caring about the implementation details.

    @William: Exciting, I am looking forward to reading your post.

    @Simone: Do you have any good links with hasField and hasMethod that you mentioned? I would like to see a working example, because I am not previously familiar with them.

    @Hagai: Thank you for the link. The point I am trying to make is that aspects can be used as one tool for architectural enforcement. I deliberately chose a simple example with clear, well-defined rules for illustrational purposes. Agreeably, separating different packages into separate projects and monitoring their dependencies is a good way to promote good architecture, especially if the cuts are as obvious as in this case.

  7. Good post! The limitations of the AOP based architectural enforcement approach can be complemented by static analysis tools such as Structure101 and FindBugs. I talk about all this in my presentation I did last year at JFokus, http://www.infoq.com/presentations/Controlling-Architecture-Magnus-Robertsson

    The general idea should be to keep as much of the architectural aspects in the code as possible. There are frameworks attempting to do this such as Qi4J http://www.qi4j.org/ which I find really interesting.

  8. Hi,

    I was able to do compile time weaving with maven…but with ant, it creates class files from .aj files. However it doesn’t enforce the aspect during compile time

    My ant script..

    After above task, i compile source files using javac task…

    Any guess what i could be doing wrong? I want to enforce aspects during compile time .

  9. @rams: First of all, sorry for the late reply.

    It was a long time ago since I last used Ant. As a matter of fact I have never used it together with AspectJ. Nevertheless, here are some thoughts:

    The normal javac compiler does not weave the aspects into the source code, so this must be handled separately (that’s why I provided the aspectj-maven-plugin in the blog post). In your case, I guess that you have to run the AjcTask or the Ajc11CompilerAdapter as described in AspectJ Ant Tasks of The AspectJ Development Environment Guide.

    You can also search the AspectJ User Mailing Lists to see if anyone else has similar problems or post a question there if you do not find the answer you are looking for.

    Good luck!

  10. Hi,

    first of all thank you for this very good article.

    I have question:

    I’m developing a library to be used within the company where I work and, I want to enforce ‘limiting collaboration’ and ‘factory pattern’ but I have control only on my library and not on the clients of my library, therefore in my case the policies can’t be applied on compile time but must be evaluated only in runtime time.

    My question is: can I enforce runtime policies using AspectJ weaving only my library? Can it work? or it’s necessary to weave both clients + my library?

    Thank you very much again.

  11. @Indrit: Thank you. There are several possible options, depending on the nature of your project.

    First, the simplest solution is to use a default (empty) access modifier for the objects that the factory creates. In order make that possible, you have to place the classes that the factory instantiates in the same package as the implementation of the factory. The advantage being that the constructors are not accessible from any other package, and thus forcing clients to use the factory. Consequently, the architecture is enforced without any aspects.

    Secondly, if your colleagues rebuild the entire system including your library, you can still use static compile time enforcement by using some appropriate pointcuts. For example, if your library’s public api is in the public package and its implementation is in the internal package:

    Lastly, if you deliver binaries, you could weave your aspects during compile time and then add some notification in runtime like you suggest. Using the same pointcuts as above, you could for example implement a before advice:

    Yet again, depending on your project, you should also consider whether or not you should weave in the aspect for production builds. Alternatively, you may choose to implement a different kind of notification when the application runs in production. The reason being that if your library is used by some untested code, it may blow up the entire application if the advice throws an exception.

  12. Hi,

    thank you for responding me. A clear and esaustive answer, very useful for me.

    I don’t know much of AspectJ but I have a question about the call join-point. As you have showed I have to use the ‘Call’ joint-point matching within the pointcuts. What I know (if I’m not wrong obviously) is that in the case of the call joint-point the weaver weaves only the method invocation locations and therefore I have to weave (compile) also the clients of my library otherwise no advice could be inserted between my-clients and my-library.

    As an ‘alternative’ I can use the ‘execution’ join-point, in this case the advice would be available at ‘runtime’ (no need to weave clients, the method body is weaved instead) but in this case it can’t work neither ( I believe ) because you can’t express conditions on the callers.

    Therefore my conclusion is that there is no real help from aspectj when:
    – you need a ‘runtime’ policy enforcement
    – you don’t control your clients (no possibility to weave them)

    What I don’t understand is that why I need to apply a ‘policy enforcement’ to code that I already own(compile)?
    Would be more useful if I could apply policies at clients that I do not control and I don’t know (runtime)?

    Is that correct or I’m doing something wrong?

    Thank you very much again.

  13. @Indrit: Unfortunately, compiling the code does not necessarily mean that you own it. I am not encouraging it, but I have seen projects where hundreds of developers work on the same project and they all compiled the entire source code (they did not have a company internal maven repository at that time).

    That said, I think I was a bit to fast in hitting the reply button the other day. As you stated, the “call” pointcut that I suggested will not work, because the enclosing code is not available at compile time. Someone may think that the “execution” pointcut would solve this problem, but as you pointed out that will not work either, because when the pointcut traps the thread of execution it is already inside the method itself. Or more formally “execution(void m()) && withincode(void m()) is the same as execution(void m())” as it is expressed in the AspectJ Development Guide.

    So I guess that we are left with load time weaving. One disadvantage is that you must manipulate the runtime that your library is deployed in, e.g. by using an agent or custom class loader, see the AspectJ Development Guide for details. If you are working in a Spring environment, you may find Load time weaving in Spring helpful.

Leave a Reply

Close Menu