BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage Articles Composite Oriented Programming with Qi4j

Composite Oriented Programming with Qi4j

This item in japanese

Bookmarks

The goal of modeling domain concepts through objects set by OOP has for a long time been handled in insufficient ways. What is the fundamental problem with how we have tried to do this so far? Is there a better way to deal with it? In this article we introduce the concept of Composite Oriented Programming, and show how it avoids the issues with OOP and reignites the hope of being able to compose domain models with reusable pieces.

The problem

Who am I? I am many things. Sometimes I'm a software developer, creating new software. Sometimes I'm a software developer who makes presentations on Java-related topics. But sometimes I'm something completely different, such as a customer to a bank, or an alumni at a university. I am many things, one for each context. Each of these contexts require me to use a different interface to interact with it, with operations that are specific to the context. In all these contexts, with all these different interfaces, I am however one and the same object. There's not one me at the bank, and another writing software.

The typical solution

And yet, if I was to be modeled in software that is probably what would happen. Using object-oriented programming, someone would model me as a Developer class. But that class would have no idea how to go to an alumni get-together, because it has no concept of partying. So I would effectively have to be modeled by several classes, and then one would have to either have several instantiated objects with the having to implement all of these in one single class we instead use the notion of mixins to handle the implementation.

Composites

A mixin is implemented as a plain Java class, that typically implements a particular interface to be exposed by the Composite that it is a part of. The way we then declare a Composite is by creating a Java interface that through annotations declare what mixins to use, and by using the "extends" keyword describe what domain interfaces should be exposed. This gives us a central point that deterministically defines the structure and behaviour of the Composite.

With COP we suggest that while it is a good idea to keep cross-cutting concerns in separate implementation classes, the description of how these should be put together, or composed, is something that should be done centrally, in Java interfaces. In order to avoid duplication of such descriptions we use the "extends" keyword to reuse declarations in the extended interfaces. By modifying an extended interface such modifications will then automatically change the Composite interface declarations that extended it, so that we don't have to modify each of them individually.

With this approach we believe that we get the best of both worlds: the separation of concerns in separate implementation classes, each dealing only with one specific task, and a centralized and deterministic declaration of what the final Composite should look like, thereby putting the developer of the Composite in charge of what should go into the definition of it and what should not be in there.

Code sample

So how would this work in practice? Well, let's take me as an example. If I was a Composite I could be described like this:

@Mixins({DeveloperMixin.class, SpeakerMixin.class, AlumniMixin.class}) 
public interface HumanComposite 
extends Developer, Speaker, Alumni, Composite 
{}

The extended interfaces would contain the actual methods to be invoked, and it is up to the Qi4j runtime to construct a Composite instance that can route invocations from clients to specific mixin instances. But it is important to note that from the clients perspective this is just a regular Java object, even though it perhaps has more interfaces than your usual domain object would have if it was implemented using regular OOP. And the domain interfaces, such as Developer, are regular interfaces with nothing specific to Qi4j, and the implementations themselves are also simply Java classes that implement the interface. The identity of the object, however, is defined by the Composite instance rather than the individual mixin instances, that solves the identity crisis: a reference to "me", as an object, can be sent around the system and casted to the interface that is useful in that particular context. If more domains and contexts are introduced, then the Composite can be extended to handle them too.

If we want to create another Composite that also uses the Alumni interface and implementation, we can do so by having that interface extend Alumni as well, and declare the same mixin to be used. The usual problems with multiple inheritance and reuse of base classes is thereby avoided.

Structural issues

Software is often designed on paper using modules and layers. We are all very familiar with diagrams like the following.

It contains Modules which are part of Layers, that are stacked on top of each other. Let's call it the Layered Modules Metaphor (LMM). It is used to communicate an overview of the entire application, without getting the audience bogged down with too many details. By rigorously following the LMM of the project, we benefit from fewer system-wide bugs, lower long-term maintenance cost and often a more flexible system that can react to change. Most projects use the LMM to explain how the application is structured, many try to follow it, but very few projects enforce it, and I think we all have seen horror cases where for instance classes in the infrastructure layer uses classes in the web layer.

Providing structure

Qi4j has taken the bold route to provide explicit support for the LMM, to discipline the developers on the team. The Qi4j application structure is a small set of rules:

  • Structure
  • All Structure is declared statically at boot time.
  • All Composite instances belong to a Module.
  • All Services belong to a Module.
  • All Modules belong to a Layer.
  • All Layers are on top of zero, one or many other Layers (but not cyclic).
  • All Layers form the Application.
  • Access
  • Modules can access all other Modules in the same Layer.
  • Layers can access the Layers directly below it (not transitive).
  • Visibility
  • Composite instances are by default only visible within the Module.
  • Composite instances can be made visible within the Layer, and between Layers.

These sound a lot more complicated than it is in reality. Essentially, Composite instances are private within the Module where they were created, unless explicitly made public either outside the Module, or outside the Layer. This is similar to how we set "public" or "private" modifiers on classes and methods in regular Java programs.

The structure is not optional, but convenience methods exist to establish common application structures, including a single module in a single layer.

Using structure

Domain code does not need to know about the application structure, it is just "there", but it shows up in the form of the @Structure annotation. Below is an example of this.

The CompositeBuilderFactory will be injected to the mixin upon creation. It will only allow the code to instantiate Composites which are visible from its point in the structure.

Another common case where Structure comes into play is when a Service is looked up. If one and only one Service of the requested type is found in the same Module, then no additional assembly will be required. Using Services becomes extremely simple.

For instance, if a GenericInventory service is declared in the Bread Module, each inventory service instance will be bound by its proximity to its respective client.

Establishing Structure

Qi4j applications need to be bootstrapped by application code. The simplest start-up possible looks like the following.

Another way to write this is to use the SingletonAssembler:

The SingletonAssembler is a convenience class that creates a Qi4j application as a single module in a single layer.

It is also possible to pass an Assembly[][][] to the newApplication() method, which will create an application context with a "pancake" layering, i.e. each layer is on top of one layer and below one layer (except the first and last one). For instance

will give the following structure:

And finally, for arbitrarily complex application structures, one needs to pass an ApplicationAssembly instance to the newApplication() method. The ApplicationAssembly is used by iteratively building up the LayerAssemblies and from them iteratively building up the ModuleAssembly. Here is an example.

This produces the following structure.

Benefits of Structure

The two main benefits from explicit coding of applications are as follows.

  1. Resolution by Proximity.
  2. Architectural Enforcement.

What this means is that composites that are nearby are easily accessed, and that nearby composites will have a higher priority, and composites private to a module or a layer is not accessible from the outside. Since services are composites, the service resolution becomes more implicit and requires a lot less assembly configuration.

Another interesting side-effect of the Structure concept in Qi4j is that every application has a static structural composition, which can be extracted and visualized by tools, instead of maintained separately. This enables architects, designers and team leads to track whether developers follow the architecture, or whether they are trying to circumvent it.

Conclusions

In this article we have briefly explored the possibilities of Composite Oriented Programming, as they are implemented by Qi4j on the Java platform. We have looked at how Composites, which implement objects in the traditional OOP sense, provide a way to achieve better separation of concerns, which leads to better quality and more reusable code. We have also explored the idea of explicitly modeling the structure of an application, which is typically only defined on paper and not in code. By doing this we can more easily handle architecture enforcement and resolution of dependencies between services. This helps us create larger systems which do not crumble under their own weight as more and more components and services are introduced.

Finally it is important to stress that most of the concepts in COP and Qi4j are not new. What we have done is to identify good ideas and patterns from previous programming practices and frameworks, and have distilled those that we believe are helpful to developers in both writing software and keeping it understandable and maintainable. Adapting age-old metaphors in new contexts is important, whether it has to do with software or life in general.

About the Author

Rickard Öberg has worked on several OpenSource projects that involve J2EE development, such as JBoss, XDoclet and WebWork. He has also been the principal architect of the SiteVision CMS/portal platform, where he used AOP as the foundation. Now he works for Jayway, and is interested in how to develop domain-oriented software that is well adapted for the new wave of Internet-centered applications.

About JayView

JayView is Jayway's magazine. Jayway is a company focusing on Java development. The magazine is where we put our passion for Java on cellulose.

We do not write about ourselves - or for that matter - how beautiful our customers are.

We write about our passion for coding, for creating great software - basically just all the things we enjoy. For more JayView visit www.jayway.com/jayview.

Rate this Article

Adoption
Style

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Community comments

  • Nice..

    by Sony Mathew,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I like the idea of bringing composites or Mixins to Java although I'm not sure about dispatch performance for something like this. Also liked the introduction of multi-module layers to object assembly and enforcing layer/module separation.

  • Get a feeling how it works ...

    by Georg Ragaller,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    ... and check out www.qi4j.org. Rickard in his modesty 'forgot' to mention it.

  • Ruby mix-ins

    by Carl Byström,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    How does this differ from Ruby's mix-ins?

  • Interesting to compare with...

    by Stephen Palmer,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Design with composition instead of inheritance? Yes!

    Actor-Role and object inheritance patterns in Nicola's Streamlined Object Modeling (www.streamlinedmodeling.com) ...

    ... and with the Party,Place,Thing - Role pattern in Peter Coad's Java Modeling in Color with UML (dn.codegear.com/article/29871)

  • Where is it useful?

    by Gregory Mostizky,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I am trying to like this but I do not understand where such an approach would be useful in a real world applications? I mean real applications are usually very focused - a person can be a developer or maybe a speaker, but if I am writing a bug tracking app I only need to model "assign to developer" behavior and I don't care if that developer can also speak well :) Without such examples this idea appears too "academical" for me.

    Gregory

  • Re: Nice..

    by Rickard Öberg,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    On performance, as always it will depend on your usecase if it is good enough or not. What I can say is that this technique is the same as I used in the SiteVision CMS, and which is now powering about 150 Swedish government websites, including one with a veeeery high load one day of the year: the IRS on income tax declaration day. The performance stats I got from that was more than good enough (overall performance of course does not solely depend on invocation performance though). But you should try it yourself. There are some microbenchmarks included in the source, so you can run that on your own machine for numbers.

  • Re: Ruby mix-ins

    by Rickard Öberg,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Good question. I'm not a Ruby-developer so I don't know. One of the things that I think separates this implementation from most implementations though is the ability to use private mixins, i.e. mixins that are only available internally in the object (sort of like "public" and "private" methods in a regular class). This can be very useful to hide implementation details.

  • Re: Where is it useful?

    by Rickard Öberg,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    My experience from previous apps using this approach is that each object will often have a primary concern related to the domain, but then it might have 10+ mixins which are of the generic kind (identity, timestamps, ACL's, metadata, tree hierarchy, etc.). And if you have generic mixins it is also much easier to do generic UI's, which is almost the real gain, in terms of lines of code saved, since UI's tend to cost a lot in coding.

    For this reason I think the approach is generally applicable. It also allows you to think more in terms of roles (i.e. "how does the CLIENT want to perceive this object?") rather than the usual class-oriented thinking (i.e. "what am I?"). Role oriented modeling, which by nature is heavily interface-oriented, leads to better separation of concerns and more reusable code.

  • Persistense issues

    by Ricardo Di Pasquale,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    I'm planning to compose several domain models (several enterprise applications) developed by third party providers. I think it's a good idea to make a concept proof with Qi4j, but can I get bottlenecked fairly with persistence issues in a EJB3 enviroment?
    Thanks

  • Sounds like Traits, as implemented in Scala

    by Dean Wampler,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    This approach sounds like traits (www.iam.unibe.ch/~scg/Archive/Papers/Scha03aTra...), a form of which is implemented in Scala (lamp.epfl.ch/~odersky/papers/ScalableComponent....).

  • Relations to Trygve Reenskaug's DCI?

    by Michael Haupt,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    It looks a bit familiar.

  • "Classes are dead" ...

    by Joubin Houshyar,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    There are clearly some good ideas here, but an early warning sign of things to come is to compare "conception" with "realization". (C.f first 3 paragraphs of JSP's specification from Sun ..).



    @Mixins({DeveloperMixin.class, SpeakerMixin.class, AlumniMixin.class})
    public interface HumanComposite
    extends Developer, Speaker, Alumni, Composite
    {}


    Related:
    www.howtodothings.com/home-and-garden/a4417-how...


    Classes are dead. Long live interfaces!


    Related?
    www.youtube.com/watch?v=mriBc6NjUhg

  • Re: Where is it useful?

    by Rafael Forte,

    Your message is awaiting moderation. Thank you for participating in the discussion.

    Hello Rickard,

    Is there any example of qi4j being used in a webapp with UI and persistence code? I am curious to see how developers could benefit from using COP in regular webapps and how it could change day-to-day design.

    Thanks,
    Rafael

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

BT