This blog post is part of the mini series about Framework Design Principles.

How can we make sure that our code is extensible? How can we enable or even encourage the users of our library to use the library in new, interesting and unexpected ways? First of all, Simplicity is really important here. Also, we should support inversion of control (IOC) - and if possible we should not constrain our users to a specific IOC container. You can deliberately create “leaks” in your abstractions. And, last but not least, lambda expressions and closures can be an awesome tool for providing extensibility.

Simplicity

Only simple code is extensible.Useless abstractions in the code, trying to anticipate future requirements and even adding design patterns where they are not needed can make the code unnecessary complicated. Just as I have mentioned in my blog post “Simplicity”, the benefits of these things are local and grow linear, while the drawbacks have global effects and grow exponentially.

To ensure extensibility it is vital to keep things simple. There are some principles we can keep in mind that are based on the idea of simplicity. The Single Responsibility Principle, the Single Level of Abstraction Principle and the Direct Call Pattern are only a few of them. See also SOLID object oriented design.

Inversion of Control

Inversion of control - and especially dependency injection - can make extending existing code easier (even if it violates the direct call pattern - at least somewhat ;) ). This does not mean that your framework should be an IOC container. It also does not mean that you should force the users of your framework to use a specific IOC container.

You should just make sure that the framework or library you created can be used with an IOC container. Wicket, for example, lets you specify an “Injector” which is called every time a component is created to inject dependencies into this component. There are several Injector-implementations that support popular IOC containers, like Spring or Google Guice.

Leaks

Your library and framework should create new Abstractions and/or Simplifications. These abstractions will be (to some degree) leaky. But is this a bad thing?

Not necessarily. You can even create such “leaks” deliberately if it makes extending the framework easier! For example, Apache Wicket abstracts the fact that you are dealing with a web container. But sometimes, when writing a web application, direct access of the container would be handy! And it does not really make sense for the wicket developers to wrap all of the functionality of the container.

So, when you really need access to the container, you can get it:

getRequest().getContainerRequest()

You can do this too: Create your abstractions for the common case - for the 90% of the use cases where creating abstractions is easy. But, when these abstractions are not enough, allow your users to access the underlying technology in a controlled and defined way.

Lambdas and Closures

Paul Graham posted the following challenge in his essay Revenge of the Nerds:

We want to write a function that generates accumulators-- a function that takes a number n, and returns a function that takes another number i and returns n incremented by i. (That's incremented by, not plus. An accumulator has to accumulate.)

In Javascript the solution looks like this:

function accgen(n) {
	return function(i) {
		return n += i;
	}
}

A function that creates another, anonymous function. How would the solution look in Java? Well, you can not solve this problem in Java - That is, you can not write a (reasonably short) solution that fulfills all the requirements. You might think “Well, nice, but what does that have to do with extensibility?”. With anonymous functions and closures it is very easy to write reusable algorithms, like map reduce.

Of course you can simulate a lot of this behaviour in Java too, but there is a lot more boiler plate code you have to write. So, if your programming language supports closures and anonymous functions, use them to make your libraries and frameworks extensible.