- It’s best to program to interfaces, rather than classes. Spring reduces the complexity cost of using interfaces to zero.
Everyone knows this is a Good Thing - but why is it good?
The answer lies in achieving decoupling. Object oriented programming in Java draws on the precedent set by Smalltalk in which objects communicate by passing messages. When a method is called, this is akin to a message over an interface. Indeed if the object being invoked is actually known only by its interface, the similarity to message passing is even greater.
So in Spring we like to use interfaces to provide services. It’s easy to insert any implementing object as the target by using Spring’s dependency injection. This allows us to change the actual implementation class as and when required. No longer are we tied to specific implementations but a much more pluggable system results.
For a good example of using this in practice, consider writing business logic that functions by reading and writing a database. Had we hardwired the data access object into our business logic, then testing might be quite a challenge. Every time we wanted to run our regression tests, we might find it hard work to set up data in the database, assuming that it would be feasible even to specify which database we’re using (are other developers using it? will our tests interfere with their data?) Regression testing rapidly spirals into complex and expensive context-dependent test harnesses. Far from ideal.
But this is where the Spring approach comes to the rescue - rip out the DAO and provide an interface that offers a database access service to our business logic. Now we can mock up an alternative implementation for testing (perhaps using SQLite holding canned test data on the fly). Our alternative implementation class has the same interface. Using Spring, we inject it into the business logic during testing. Now we have achieved simple reliable regression testing in which the test system is independent of all other developer activity, as it should be.
Spring generalises this by advocating decoupling for pretty well everything where a service is provided or a service is needed.
A Lesson from History
The technique of using interfaces rather than concrete classes has an interesting parallel in multi-threaded programming. Back in the 1970s, Edsger Dijkstra invented the semaphore as a way to restrict access to shared resources, which are usually variables in shared memory of a multiprocessor. Using semaphores helps prevent unstable races between the processing threads. Semaphores and their equivalent, the monitor, are used in multi-threaded code that tightly couples the threads through the services of a named monitor (or sempahore). The monitor is an extension of the semaphore and was invented by Brinch Hansen and C.A.R. Hoare.
Hoare went on to explore this further. Initially, he developed the rendezvouz concept - an improvement on monitors and a means by which threads could be considered to be independent of each other except during a rendezvouz. This was ground-breaking and led to the Ada programming language having tasks (i.e. threads) that isolate data within each task, except when data is exchanged during a rendezvouz. This was a successful and powerful idea - but it had a major drawback. Just like classes can be tightly coupled, Ada’s tasks are tightly coupled. They don’t work by interface but by knowing who to talk to - explicitly fixed in the software.
Hoare realised this was not good. He realised that decoupling provides great scope for building software from pluggable systems. Therefore, he took this further with his revised theory of communicating sequential processes (CSP), which is a formal language for describing interactions between parts of a concurrent system by analysing the interaction events between threads (or ‘processes’ as Hoare called them). Although CSP is a formal mathematical language, it spawned several programming languages such as Occam and Erlang, in which the decoupling between threads was provided explicitly by the use of communication channels.
Decoupling is therefore seen in several facets of software programming as a means to build component-based systems that plug together in a structured way. Interfaces allow us to write decoupled Java systems and, as we have seen, this is now recognised to be a Good Thing.
(As a footnote, there’s a certain irony that Java overlooked the lessons learned from applying decoupling to multi-threaded systems. In Java, the convention is to synchronize threads via tightly coupled monitors; if you’re worried by this, take a moment to have a look at JCSP.)comments powered by Disqus