A Loose Coupling Strategy

Getting things done when you're only an architect*

By Julian Browne on October 18, 2007. Filed Under architecture, development, strategy

When tactical or political pressures mean you can't rewrite or restructure your applications in line with a best-practice architecture, or apply strategic measures with much effectiveness, then you don't have many options to make an architecture function meaningful. One approach that I have employed with some success is to apply a refactoring strategy to legacy applications with the aim of creating a situation that supports the 'right' kind of change later.

The majority of refactoring affects the code structure and density of software cruft, to make it more readable, maintainable etc and so is more the preserve of development teams than architects, but there is one area that has an architectural impact, and that is in adopting strategies that promote loose coupling. It's quite possible to do this without getting all big picture or donning your astronaut's helmet. Applied pragmatically it also needn't add lots of time to projects (the aim in fact is to add zero time by making margin calls very early in the lifecycle).

Coupling is a measure of how anonymous applications and components are. The more any one component knows about others, the more tightly coupled it is to them. Effectively, it's a measure of information redundancy. If prior knowledge of the detail of an operational feature of application A is required by application B, then that knowledge must exist in two places - in B as data, and in A as implementation. If the implementation of application A changes, then application B must update its data. The situation gets very complex when lots of other applications also need to know about that feature. One of the key drivers for middleware has been to address this, because with application portfolios being so heterogenuous and dynamic it's nigh on impossible to fix in the applications themselves in a consistent manner.

One very important thing to understand about the concept of coupling is that there are only looser and looser ways to be coupled, but no way to totally 'decouple', as it were. If application A communicates with application B, there is no way for them to be completely disconnected. There are ways for them to be coupled to something that isn't each other though, and we'll come on to that in a bit.

Coupling occurs at many levels and in many ways. It takes a lot of effort to address them all and for the large part you may not want to. Like many aspects of architecture, you have to take a pragmatic view on where to fight your battles, otherwise you'll find yourself in an ivory tower with only powerpoint slides as your friends. The obvious rule of thumb is that you want to be decoupled from things that change frequently and understand any design debt you may be incuring where you end up tighter than you'd like.

These tradeoffs are critical when you start looking at things like SOA. Vendors will spout phrases like 'loose coupling' all through their demos, but you won't get it in the right areas if you don't govern what the implementation looks like, in a way to fit your business. No tool provides loose coupling for free.

You could probably spend a week talking about this subject and I don't have that long, but the majority of the concepts can be covered simply by examining how one application might exchange some data with another. Once you do this, you'll have the right kind of mindset to spot other danger areas.

So let's say that we've built a dynamic pricing system. When a customer comes along and wants to buy one of our products we need to know something about them in order to give them a price. If they're a loyal big-spender we'll do them a better deal than if they're a first timer. Perhaps we change prices with the season, are running a two-for-one offer, or maybe we give a discount for shopping online as opposed to via telesales. Who cares? We just need a way to identify a customer and a way to identify the product they are interested in. Then it's time to talk to that pricing engine.

The design-decision process is similar for both refactoring existing code and for new developments, so I've tried to look at a continuum of tight to loose coupling options. They're not exhaustive but should give a flavour of how discussions could go - the objective is, not surprisingly, to coax changes towards the looser options. Also remember that adding a 'loose' interface, even one that isn't initially used by many callers, is a capability for the future. Once it's in production, it's a path of least resistance for new developments to take advantage of. Call me a cranky old cynic, but I don't beleive promotion of reuse works. In the real world, developers and project managers are under such pressure to get the job done that they'll always (understandably) look for short cuts. The trick is not to write long documents on reuse policy, but to make the best option and the easiest option one and the same. Anyway, let's get back to the aspects of that pricing query.

There are plenty of techniques that help reduce the burden of what applications need to know about each other to get their job done. Some of these make use of technology abstractions, some require the problem to be turned around so that callers become callees. None remove coupling entirely, either moving the coupling from between applications to something in the middle (which is less likely to change) and/or moving the coupling from something syntactic like API parameters to something semantic like business documents, in effect also moving complexity to the centre.

All of these concepts are the strategic and architectural decisions you would normally make early in a project to make future change as easy as possible, but applied as part of a refactoring exerise, implemented by some lightweight governance, they can still have a powerful effect without the weight or mandate needed to pursue full-scale architecture initiatives.

*With appropriate apologies to Joe Spolsky for the subtitle