Blog / 2006-04-29 aQute - Software Consultancy
Search
*

Let us not Make the Same Mistake

Several people told me to stop ranting against the popularity of the optional Require Bundle feature in the OSGi R4 Framework. I am being told that this is what people want, so give it to them. Or I am told that real world systems need these kinds of facilities, only toys can get away with more subtle dependency mechanisms. Maybe they are right; after playing with Maven it became obvious that they also use the overly simplistic require-jar model. So I tried not to rant, but as you can see on the previous sentence, I keep failing.

I can not give up because I deeply feel that it is the wrong concept, causing grave damage to our industry. A bundle or jar is a packaging concept that is unrelated to its logical functions. Sometimes you put one function in a JAR, sometimes many. There is one thing sure: the constituents of a JAR will change over time; why do you think the refactoring tools are so popular? What you need is important, not who provides it. Designing a dependency handling mechanism on the wrapper is therefore fundamentally wrong.

If there are lessons we learned from our predecessors in structured programming it must be the lessons about coupling and cohesion. Coupling should be minimized, and cohesion should be maximized. Designing a dependency mechanism around the wrapper is totally ignoring those lessons.

I get upset about this because I think we are repeating the same mistake that we Object Oriented aficionados made in the late eighties. I will never forget a management meeting in the middle eighties where I explained (can you imagine, without PowerPoint beamer!) to my colleagues how Object Oriented technology was going to change the world. Within a few years we would have all those objects in our library and building a new system would be a snap. Just get a few classes, bunch them together, write some initialization script, and voil?! Anybody that has been working in our industry for more than a year can testify that this dream did not really work out. What happened in reality was that if you took out class A from the library, the rest of the alphabet followed due to coupling. The first time I realized what was happening I felt so betrayed. We had been so careful in designing our objects, hiding our instance variables and writing proper accessors, privatizing as much as we could. Why were we being punished in this way?

We were being punished because we had forgotten the lesson from our predecessors: minimize coupling, maximize cohesion. After learning these lessons we spent many years discovering the patterns that helped us minimize these dependencies. If you read the seminal book Design Patterns by the gang of four you can see that most patterns are about decoupling. Today, Service Provider Interfaces (SPIs) are very common in Java, but they were the result of hard learned lessons. While working for severallarge corporations I have seen horrendous monolithic systems of millions of lines of code that were brought to their knees because the intricate dependencies that defied improvements and caused build times that were measured in days. Really, unnecessary coupling is bad.

Most modern software uses Factory patterns and many open source projects go ballistic in their use of Class.forName() to minimize coupling. Maybe the best mechanism around to minimize coupling is the, often undervalued, OSGi service registry and its associated set of standardized service interfaces. The standardize interface cut the coupling between implementer and user. Sometimes I get a tad frustrated by how few programmers seem to understand the importance of this watershed between usage and implementation.

But this story is not about how we fought the coupling between objects. This story is about the coupling between components (bundles or jars). However, I hope the parallel is clear. Objects could not fully live up to their promise of making system like Lego because we ignored the under-the-surface coupling we created between objects. Today, components are again advocated as the software Lego but we will also fail again if we do not clearly understand why objects failed to give us the building blocks we longed for. The Require-Bundle and maven dependency model is completely ignoring this important lesson we learned from OO over the past 20 years because they ignore the unnecessary coupling they create. Minimizing coupling between components is essential to make them reusable.

A dependency system based on the JAR (Require Bundle or Maven) is plain wrong because it couples to an arbitrary aspect of the component (its packaging) and because it couples to all parts that are included in that wrapper, even if those other parts are never needed by the requiree. A good dependency system should only couple to the functionality that is needed: no more, no less. In a Java based system, the minimum level of granularity is the class level. A class can only refer to other classes; dependencies between Java modules are therefore on the level of classes. However, this granularity is too low. A class rarely stands alone; it is closely coupled to a set of other classes that together should form a cohesive unit. Well designed systems place this cohesive set of classes in a package. Well designed systems also keep the number of packages that are needed by their clients to minimize coupling low. Patterns like the Factory pattern and mechanisms like the OSGi service registry help tunneling external access through the fewest number of packages.

Systems that do not use these patterns often expose a much larger number of packages to their clients. These systems could use a higher level of grouping. The superpackages? concept goes in that direction. However, in my experience well designed component based systems can get away with a surprisingly low number of exported packages. I have a tool that calculates the import packages and the number is often in the low tens, also for larger bundles. Anyway, the wrapper seems absolutely the worst aspect to base a dependency system on. To quote Einstein: ?Make everything as simple as possible, but not simpler?.

I am not saying that package dependencies are the best mechanism. I am saying they are the current best mechanism for Java code because they couple only the real underlying aspect, not on an artificial artifact like the wrapper. However, there are many other dependencies that can not be represented as packages. For example, a bundle could depend on a screen with a certain resolution, a specific piece of hardware, or any other capability. What is important that the dependency is expressed in the semantics of the real underlying relation, and again, not on an arbitrary artifact. This is the reason why we used a generic requirement-capability model for the bundle repository instead of expressing specific concepts.

I realize we pretty badly messed up with objects in the eighties and nineties. At least we have the excuse that we were not told about the elephant in the room that we forgot to notice. You will not have that luxury. If you look back a couple of years from now and wonder why these promises of Lego like components never materialized, you will not even have that excuses. The tangled web of components that will feel like Harry Potter?s Devil's Snare will then be your fault!

  Peter Kriens

posted by Peter @ Saturday, April 29, 2006

Copyright 2006 aQute SARL, All Rights Reserved