Posts Tagged ‘Design Patterns’

h1

Dependency Inversion is really Dependency Inflation

September 26, 2009

This article (by Richard Martin?) looks like a good introduction to Dependency Inversion, which appears to be mostly an attempt to reduce downward dependencies (the so-called Traditional Design Approach).

As far as I can tell though, it does not really invert dependencies; you don’t end up with your low level I/O library depending on your business logic. Rather it decouples components, making both ‘high’ and ‘low’ level libraries depend on some abstract/interface library, or a runtime configuration that defines the assembly.

So, Dependency Inversion advocates creating an interface and implementation for all public classes. But it seems to me this is blindly following the ‘decoupling’ principle so far that it stops helping in practice and starts to hurt.

Where do package interfaces go?

For a start, where does the abstracted interface go? If the interface goes in the higher level library (so that it defines what it expects from the implementation), then your low level utility depends on business logic, and this is Bad – you can’t reuse it in another part of the business. It would be foolish if your TCP/IP library had to implement an interface defined in the invoicing part of your code.

If you put the interface in the utility library, then if you replace the library with another one your interface is going to be replaced by the one in the new library – with its own package name and potential differences. You might as well just use the implementation class and not have to create a redundant interface and factory class.

So interfaces really shouldn’t go in the higher library, and they’re redundant in the utility library.

To implement proper decoupling you need adaptors or façades between each coupling (see commons-logging, Java’s XML parser, etc) which gives you more code and packages to maintain. It also obscures execution: every boundary between libraries become a barrier, as it’s not clear at the point of use which library is being called upon.

Yet the desire to decouple is supposed to reflect the desire to make maintenance easier.

But coupling is… good…

Or rather, a library with a straightforward public API that defines its features is good. This API gives you a contract about how to use the library. This contract is enforced by the compiler, and by all decent IDEs, which will no doubt offer extra coding help based on those contracts. By coding to those contracts, we get compile time checking, and any student on work experience can follow the code.

The main bonus for dependency inversions is so that you can swap out low level libraries and replace them with another. For example, you may want to replace your XML parser with a new one that is much faster. But few libraries can genuinely be blindly replaced in practice as they have different features – in fact it’s likely you’re swapping libraries in order to use those new features.

If you’re using the libraries through a lowest-common-denominator interface then you’ll have to work around it using ‘generic’ methods, and that usually means you’re bypassing any compile-time checks. If at runtime a different library is used, there will be ‘undefined behaviour’ when these extra features are not available. For example, ‘property’ switches in the early Java XML libraries could be used to switch validation on and off, but some libraries allowed this and some did not, and some required different properties to do the same job.

In that case we end up with dependencies not only on the common abstracted interface, but also several implementation libraries, and on the mechanisms of deployment, to include extra checks that the right libraries are included.

Instead I much prefer early-defined, specific, suitable, easy, compile-time checks; they’re the easy first-stage check that my code is sound, they help my IDE help me, they help those who review my code and, most importantly, those who use it for real.

Runtime applications

By coupling our components through extra interface/factory packages, we can assemble different applications at runtime, rather than having to compile a particular assembly first. This might be done through a configuration file (picocontainer) or ‘automagically’ by putting the right implementations on the classpath (commons-logging). This gives you tremendous flexibility at runtime, allowing you to specify, say, faster or more robust libraries as required at various customer sites.

On the other hand, the first requires learning the format for a secial configuration file, editing it, validating it and controlling it. Which is, essentially, just more programming. The second can make classpath set ups and debugging the most frustrating nightmare – and on-site too.

Case – Commons logging

For example, commons-logging was created (I gather) to solve the problem where low level libraries used different logging mechanisms such as log4j or JLog or System.out or some bespoke one.

“If only all library writers used commons logging”, the reasoning goes, “then it would forward log messages to the mechanism preferred by the owning application, or component container such as Tomcat”. If only All Had Obeyed. Now of course, we have some libraries writing to log4j and some to JLog and some to System.out and some to their own… and some to commons-logging. And commons-logging gets confused about which library it’s supposed to write to, because there are several loaded.

It’s a particularly easy target because there were very few widespread logging libraries by the time it was implemented, so writing adaptors between them was not hard. If you wanted to use a library that logged to log4j in Websphere (which uses JLog) you could write a log4j handler that forwarded the messages to JLog. And now that JDK 1.4 includes a logging library, you could argue that all low level libraries should use that – if, that is, you think low level libraries should be logging at all.

You can see the principle behind it though; by having a single common adaptor, we could move our libraries between applications (or our components between containers) without worrying about the logging environment. In fact though, it couldn’t solve the problem; even now some library writers use log4j over JDK 1.4 logging, despite the latter being ‘zero-effort’ to include, because log4j offers them more. Instead it made the problem worse, by adding in new runtime class loader problems as well as the config file editing required by all the logging libraries in use.

On an Extra Bonus Whinge about commons-logging; logging must be reliable and robust. Bad Things happen when starting up complex applications – especially if some of it is defined at runtime – and the log must report them if you have any hope to look even vaguely professional on site.

Randomly moving jar files from directory to directory for an unfamiliar web server between mute crashes because the logger has failed is frustrating enough, but doing so sat in a customer’s office is an experience I do not want to repeat.

Conclusion

Where you have a well-defined requirement for different components to be used in different runtime environments, a configurable factory makes a lot of sense. I, however, would recommend that that factory be specific to task rather than a generic one like picocontainer, because with picocontainer you lose type constraints and early failures become late failures.

Swapping between libraries that share the same API is fairly rare; people swap to use new features. Application-wide search-and-replace on library-using code is straightforward with modern IDEs. When writing a library, define your API well with as much contractual information as possible (typing, named attributes, etc), and as little exposure to the workings as possible. This reduces effort writing, reviewing, debugging and maintaining code, and in deploying applications, that overwhelm occasional library changes.

All this applies equally well, of course, to services…

Related

See also IBM Developer Works Quality Buster Customising Applications, Think Again, and for a rude rant the Bile Blog

[An old article from my boring old site, brought to the blogosphere for fame and fortune]

h1

Singletons Are Good

September 26, 2009

Some articles (at picocontainer, MSDN and others) bemoan the Singleton pattern as Bad Design (a so-called Antipattern) because it is ”global” and therefore it causes ”tight coupling”.

Singletons are indeed usually globally available – that’s often what they’re for. But assuming ‘global is bad’ misses some good uses.

Singleton is indeed bad when it is a single global point for all components to find all global things. You can find then that the Singleton uses types or interfaces defined in component packages, and in turn these packages make use of the Singleton. So your packages, or components, depend on the Singleton which in turn depends on other packages… so all your components are interdependant through the singleton and you can’t decouple anything from anything else. This only Might Be Bad in your project, but is Always Bad in large software systems.

Singleton is also bad when used to bypass structured and/or object oriented programming; a Singleton might be used to hold data for a task instead of using a data-wrapping object and passing that as an argument. It might be used to shortcut data transfer around layers of a system. Again, this only Might Be Bad in a small prototype program, but is Always Bad in large software systems as they can make applications a nightmare to debug and update.

Banning Singletons altogether stops these abuses but also loses the benefits, which can be convenience, simple and obvious code, and easy maintenance.

Even the pico guys say that Logging is an exception, but exceptions are sneaky; they can either be one that ‘proves the rule’ because it really is exceptional, or one that demonstrates the rule is pants. In fact logging isn’t a special case; it is merely a centralised – and global – route for monitoring a particular kind of event.

Other messaging hubs – such as UI event queues – are similar. Configuration too benefits from a single class so that you can have one central place to configure your application. Pool factories necessarily require a Singleton (although Pooling is normally bad).

We want to centralise these tasks, but each one is a separate special to purpose Singleton; they are not combined into one single global Singleton. Which is how Singletons ought to be used. Note that in all these cases the Singleton implementation is ‘standalone’; our components depend on a particular specialised Singleton and its package, but the Singleton does not depend on our components or other ‘high level’ components.

This loose-coupling is best seen in message-passing hubs that tend to be Singletons (such as logging). The hub package must include whatever interfaces it requires for its message objects (or events), and these are implemented by whatever components use the hub package, either as senders or listeners

(Just trying out blog; this blog was cut and paste from web pages here)