Most developers appreciate that applications should be modular. Indeed logical modularity in the form of “Design Patterns” was rapidly embraced in the early years of object-oriented programming (see http://en.wikipedia.org/wiki/Design_Patterns). However, it has taken the industry much longer to appreciate the importance of structural modularity and its fundamental relationship to application maintainability and agility.
Today it is not unusual for an agile Java development team to break large Java artifacts (JARs) into a number of smaller ones. As these, in turn, grow in size, they are again broken down into yet smaller units. The development team understands that its agile objectives cannot be achieved with a large, monolithic code-base.
While the dependencies and the impact of change are understood by the development team that created the application, this structural information is not explicitly associated with the software artifacts. Should members from that development team leave, knowledge concerning application structure is lost. This exposes the organization to significant long-term governance problems, increased operational risk and spiraling maintenance costs. Also, for a third party (e.g. a different team within the same organization), the application may as well have remained a monolithic code-base since the components can only be understood by cracking open each Java JAR and reading code. All the components must be analyzed this way as the dependencies between them cannot be inferred in any other way!
The use of Maven helps the situation somewhat. Maven expresses dependencies between Java JARs in terms of component names (Project Object Model – POM). This enables a Maven based application to be simply assembled by a third party that didn’t create the original code. However, as we already know from the initial examples, the value of name based dependencies, is limited. As the dependencies between the components are not expressed in terms of requirements and capabilities, third parties are unable to deduce why the dependencies exist and what might be substitutable. The application can be assembled, but it cannot be changed. As no metadata exists that adequately describes the inter-relationship between the components, the resultant business system remains intrinsically fragile.
Aware of these issues, Kirk Knoernschild explores the relationship between agility and structural modularity in his book “Java Application Architecture”7 and identifies the problem of the “missing middle.” Knoernschild concludes that essential structural layers are missing in the architecture of traditional Java applications. At the coarse-grained end of the modularity spectrum we have traditional services, whereas at the fine-grained end of the modularity spectrum we have Java packages and classes. However, there is a void in the center.
Figure 6: Structural hierarchy: The Missing Middle
Based on open industry standards created by the OSGi Alliance, OSGi directly addresses this issue by providing Java with the required modularity framework.
- OSGi bundles express dependencies in terms of Java package requirements and capabilities. Hence it is immediately apparent to a third party, whether a particular OSGi bundle can be substituted with a potential alternative.
- OSGi bundles use semantic versioning. Hence it is immediately apparent to a third party whether a change to an OSGi bundle is potentially a breaking change to those using it.
With enforced isolation, dependencies expressed via requirements, capabilities and semantic versioning, OSGi bundles’ are the natural choice for enabling Java code re-use. OSGi bundles are also essential elements in an application’s composition hierarchy (unit of composition) and provide the basis for a natural unit of deployment, update and patch (unit of deployment).
One structural layer up, OSGi also provides µServices. These are lightweight services that are able to dynamically find and bind to each other at runtime. OSGi services may be co-located within the same JVM, or via use of an implementation of OSGi’s remote service specification, distributed across JVMs separated by an IP network. Coarse-grained business applications may then be composed from a number of finer grained, co-located or distributed OSGi µServices (Unit of Intra/Inter Process Re-Use), so completing OSGi’s “Agile – All the Way Down!” story.
Figure 7: Structural hierarchy: OSGi services and bundles
Knoernschild concludes that:
“Not only does OSGi help us enforce structural modularity, it provides the necessary metadata to ensure that the Modular Structures we create are also Agile Structures.”8
8 k Knoernschild -Java Application Architecture