Pages

Sunday, April 27, 2014

Ten reasons to use OSGi

In this post I will discuss ten reasons to use OSGi. The reason for this post is that there are many misconceptions about OSGi. At Luminis Technologies we use OSGi for all our development, and are investing in OSGi related open source projects. The reason to do so is because we think it's the best available development stack, and here are some reasons why.

#1 Developer productivity

One of OSGi's core features is that it can update bundles in a running framework without restarting the whole framework. Combined with tooling like Bndtools this brings an extremely fast development cycle, similar to scripting languages like JavaScript and Ruby. When file is saved in Bndtools, the incremental compiler of Eclipse will build the affected classes. After compilation Bndtools will automatically rebuild the affected bundles, and re-install those bundles in the running framework. It's not only fast, but also reliable; this mechanism is native to OSGi, and no tricks are required.

Compare this to doing Maven builds and WAR deployments in an app-server... This is the development speed of scripting languages combined with type-safeness and runtime performance of Java. It's hard to beat that combination.


#2 Never a ClassNotFoundException

Each bundle in OSGi has it's own class loader. This class loader can only load classes from the bundle itself, and classes explicitly imported by the bundle using the Import-Package manifest header. When an imported package is not available (exported by another bundle) in the framework, the bundle will not resolve, and the framework will tell you when the bundle is started. This fail-fast mechanism is much better than runtime ClassNotFoundExceptions, because the framework makes you aware of deployment issues right away instead of when a user hits a certain code path in runtime. 

Creating Import-Package headers is easy and automatic. Bnd (either in Bndtools or Maven) generates the correct headers at build time, by inspecting the byte-code of the bundle. All used classes that are not part of the bundle must be imported. By letting the tools do the heavy lifting, there's not really any way to get this wrong. This is unless there's dynamic class loading in the code (using Class.forName). Luckily this is hardly ever necessary besides JDBC drivers.

The Import-Package mechanism does introduce a common problem when using libraries. The transitive dependency madness in Maven has made some developers unaware of the fact that some libraries pull in many, many, other dependencies. In OSGi this means those transitive dependencies must also be installed in the framework, and the resolver makes you immediately aware of that. While this makes it harder to use some libraries, you can argue this is actually a good thing. From an architectural perspective, do you really want to pull in 30 dependencies just because you want to use some library or framework? This might work well for a few libraries, but breaks sooner or later when there are version conflicts between dependencies. Automatically pulling in transitive dependencies is easy for developers, but dangerous in practice. 

#3 All the tools for modern (web) backends

Even more important than the language or core platform is the availability of mature components to develop actual applications. In the case of Luminis Technologies that's often everything related to creating a backend for modern web applications. There is a wealth of open source OSGi components available to help with this. The Amdatu project is a great place to look, as well as Apache Felix. Amdatu is a collection of OSGi components focussed on web/cloud applications. Examples are MongoDB integration, RESTful web services with JAX-RS and scheduling. 

It is strongly advisable to stay close to the OSGi eco-system when selecting frameworks. Not all frameworks are designed with modularity in mind, and trying to use such frameworks in a modular environment is painful. This is an actual downside of OSGi; your choice of Java frameworks is somewhat limited by the compatibility with OSGi of the frameworks. This might require you to leave behind some of the framework knowledge that you already have, and learn something new. Besides the investment of learning something new, nothing is lost. There are so many framework alternatives, do you really need that specific framework even although it's not fit for modular development?

In practice we most commonly hear questions about either using OSGi in combination with Java EE or Spring. As a heavy user of both in the past, I'm pretty confident to say that you don't need either of them. Dependency injection is available with Apache Felix Dependency Manager, Declarative Services and others, and I already mentioned Amdatu as a place to look for components to build applications. 

#4 It's fast

OSGi has close to zero runtime overhead. Invocations to OSGi services are direct method calls and no proxy magic is required. Remember that OSGi was originally designed to run embedded on small devices; it's extremely lightweight by design. From a deployment perspective it's fast as well. Although there are app-servers with OSGi support, we prefer to deploy our apps as bare bones Apache Felix instances. This way nothing is included that we don't need, which drastically improves startup speed of applications. Though that a few seconds startup time for an app-server is impressive? That's what an OSGi framework does on a Raspberry Pi ;-)

#5 Long term maintainability

This should probably be the key reason to use OSGi; modularity as an architectural principle. Modularity is key to maintainable code; by splitting up a code base in small modules it's much easier to reason about changes to code. This is about the basic principles of separation of concerns and low coupling/high cohesion. These principles can be applied without a modular runtime as well, but it's much easier to make mistakes because the runtime doesn't enforce module boundaries. A modular code base without a modular runtime is much more prone to "code rot", small design flaws that break modularity. Ultimately this leads to unmaintainable code.

Of course OSGi is no silver bullet either. It's very well possible to create a completely unmaintaintable code base with OSGi as well. However, when we adhere to basic OSGi design principles, it's much easier to do the right thing.

Another really nice feature of a modular code base is that it's easy to throw code away. Given new insights and experience it's sometimes best to just throw away some code and re-implement it from scratch. When this is isolated to a module it's extremely easy to do; just throw away the old bundle and add a new one. Again, this can be done without a modular runtime as well, but OSGi makes it lot more realistic in practice. 

#6 Re-usability of software components

A side effect of a modular architecture is that it becomes easier to re-use components in a different context. The most important reason for this is that a modular architecture forces you to isolate code into small modules. A module should only have a single responsibility, and it becomes easy to spot when a module does too much. When a module is small, it's inherently easy to re-use. 

Many of the Amdatu components are developed exactly that way. In our projects we create modules to solve technical problems. When we have other projects requiring a similar component, we share these implementations cross-project. If the components prove to be usable and flexible enough, we open source them into Amdatu. In most cases this requires very limited extra work.

This has benefits within a single project context as well. When the code base is separated into many small modules, it becomes easier to make drastic changes to the architecture, while still re-using most of the existing code. This makes the architecture more flexible as well, which is a very powerful tool.

#7 Flexible deployments

OSGi can run everywhere, from large server clusters to small embedded devices. Depending on the exact needs there are many deployment options to choose from. Using Bndtools or Gradle it's easy to export a complete OSGi application to a single JAR that can run by simply running "java -jar myapp.jar". In deployments with many servers (as is the case in many of our own deployments) we can use Apache ACE as a provisioning server. Instead of managing servers manually, software updates are distributed to servers automatically from the central provisioning server. The same mechanism works when we're not working with server clusters, but many small devices for example.

The flexibility of deployments also implies that OSGi can be used for any type of application. We can use the same concepts when working on large scale web applications, embedded devices or desktop applications.

OSGi can even be embedded into other deployment types easily. There are many products that use OSGi to create plugin systems, while the application is deployed in a standard Servlet container. Although I wouldn't advice this for normal OSGi development, it does show how flexible OSGi is for deployments.

Also check out this video to learn more about Apache ACE deployments.


#8 It's dynamic

Code in OSGi is implement using services. OSGi services are dynamic, meaning that they can come and go at runtime. This allows a running framework to adapt to new configuration, new or updated bundles and hot deployments. Basically, we never need to restart an application. I recently blogged about this in more detail in a post "Why OSGi Service dynamics are useful".

#9 Standardized configuration

One of the OSGi specifications that I find most useful is Configuration Admin. This specification defines a Java API to configure OSGi services. On top of this API there are many components that load configuration from various places, such as property files, XML files, a database, provisioned from Apache ACE or loaded from AWS User Data. The great thing is that your code doesn't care where configuration comes from, it just needs to implement a single method to receive configuration. Although hard to understand that Java itself still doesn't have a proper configuration mechanism, Configuration Admin is extremely useful because almost every application needs configuration.

#10 It's easy

This might be the most controversial point in this post. Unfortunately OSGi isn't immediately associated with "easy" by most developers. This is mostly caused by developers trying to use OSGi in existing applications, where modularity is an afterthought. Making something non-modular into something modular is challenging, and OSGi doesn't magically do this either. However, when modularity is a core design principle and OSGi is combined with the right tooling, there's nothing difficult about it. 

There are plenty of resources to learn OSGi as well. Of course there is the book written by Bert Ertman and me, and there are a lot of video tutorials available recorded at various conferences where we speak.

Finally, when trying out OSGi, try it with a full OSGi stack, for example as described in our book or the Amdatu website. Don't try to fit your existing stack into OSGi as a first step (which is actually advise that applies to learning almost any new technology).

Video sources:
Book:



4 comments:

  1. Hi Paul,
    nice blog entry. I share nearly the same "feelings" about OSGi. I was quite surprised that you "prefer to deploy our apps as bare bones Apache Felix instances". I would have thought that you use at least Apache Karaf. Are there other reasons next to improved start-up speed why you prefer bare bone?

    ReplyDelete
  2. Ronny, I don't speak for Paul but I have similar feelings about Karaf. I'll turn your question around, why would you use it? I've never seen a good reason for taking the modular goodness of OSGi and turning it back into an application server with pre-defined and not easily replaceable stack.

    ReplyDelete
  3. Ronny,
    A container like Karaf is only required when deploying multiple applications within the same container. In that case you would need management tools to manage the container, just like you do with an app-server.

    In our deployment scenarios we (mostly) deploy in the cloud; often in a load-balanced setup. When a new machine instance starts, it gets provisioned by the provisioning server (Apache ACE) and starts the application. We never maintain instances; whenever they misbehave or when we want to scale down, we simply turn of the instance. In this kind of scenario a container like Karaf doesn't really add anything useful. We're thinking about running processes, instead of managing containers.
    It's not that containers are necessarily bad, but in most cases you just don't need them.

    Neil's question is a good one to ask yourself: "What does a container offer that I really need"?

    ReplyDelete
  4. Hi Paul, hi Neil,
    that's a tough one. To answer honestly I'd say a container serves my laziness. E.g. it already provides me with an enterprise OSGi implementation and other modules so that I don't have to care much about it.
    But starting to think about your approach mine seems not be the good kind of laziness (as stated by Larry Wall ;) ).

    ReplyDelete