With the perceived desire nowadays amongst the unwashed (blogging) masses to simplify the way their code acquires dependencies (whether it be via setter or constructor or ego injection), a recent problem made me take a step back and look at the problem from a slightly different angle – before you start wondering about how to acquire your dependencies you should really be asking questions of yourself as to why you need those dependencies, and whether or not in your drive to simplify one piece of code you end up complicating the system as a whole.
Lets take the scenario I’ve been looking at recently. We have a @View@ object that represents a domain object. Next we have a @Viewer@ – this object is responsible for providing a display environment for the view. From time to time, a @View@ might need to display an error – this is something the @Viewer@ handles for it. Lets look at one approach to giving @View@ access to @Viewer@
public class MyView implements View {
public void doSomething() {
...
//Report error
Viewer.instance().displayError(errorMsg);
}
}
Here we are using a singleton instance of @Viewer@. Not only does it assume that we can have only one @Viewer@ object in the system, we are actively having to go out and find the Viewer for ourselves – many would argue doing more work than is required.
We could of course pass in the @Viewer@:
public class MyView implements View {
public MyView(Viewer viewer) {
this.viewer = viewer;
}
public void doSomething() {
...
//Report error
viewer.displayError(errorMsg);
}
}
This is better. Now we can have multiple Viewer objects, and the code is a little more testable.
Added complexity?
The code to create the second type of object though has now become more complicated. For the singleton example, I could create the object like this:
View view = new MyView();
Now though I have to get the @Viewer@ from somewhere:
Viewer viewer = getViewerFromSomewhere();
View view = new MyView(viewer);
Tools like Pico can help simplify this a bit – you could create a Picocontainer which automatically creates a @View@ with a @Viewer@, however this can end up hiding what’s really going on – and if the @Viewer@ object is not itself being created by Pico then you still have the problem of locating it and passing it into Pico. In the above example you would probably agree that the second example is still the better solution – there is a minimal added complexity to the constructing code.
In a larger system don’t underestimate the potential confusion introduced by using tools such as Pico or Spring for dependency handling – the complexity they can help hide can often give the impression the code is working as if by magic. This can be further compounded when such tools are introduced bit by bit, something both these lightweight frameworks are capable of. When you start getting a mixture of code with explicit and non-explicit dependency management it is often a recipe for much developer anguish.
Maybe there is a better way…
In this example, I actually realised there was no need for the dependency in the first place. The linkage between @View@ and @Viewer@ always felt wrong – it was too brittle and didn’t account for changes in business/application logic surrounding error handling. I ended up removing the need for the dependency altogether by moving to an event model – a technique I’ve been finding more and more useful of late. The code now looks like this:
public class MyView implements View {
public void addListener(Listener l) {...}
public void removeListener(Listener l) {...}
public void doSomething() {
...
fireError(errorMsg);
}
protected void fireError() {
//inform listeners there has been an error
...
}
}
At present, @Viewer@ happens to be the listener, although I’m going to change this to be a controller class. The dependency is gone, the code is more flexible, and no IoC framework in sight.
18 Responses to “Simplifying dependencies, increasing complexity?”
Ah, the power that is Design Patterns 🙂
With decoupled events you could gain even more independence as the View could simply post an error event, and the Viewer could register for any error events. Of course this comes at the price of requiring an event framework that dispatches the events.
Yep – that’s why I went that route in the end. I wouldn’t advocate the use of events simply to remove dependencies (unless your app was really tangled).
Of course. For most (GUI) apps this would be plain overkill. But every now and then I got an app that consist of multiple components with several threads that all have to communicate with each other. And in this case I don’t want to maintain listeners because it will get messy (esp. when not using weak references).
Certainly providing a generic listener framework is a much more powerful solution in the case you’ve shown above. However, you would still have to provide some way to register your listener classes, whether it’s an IOC container or not. You may also require either multiple sets of listeners for different types of notifications, or some sort of event information along w/ each notification to allow listeners to behave appropriately in different scenarios.
Interesting comparison w/ the dependency injection scenario that’s getting so much play lately. Thanks!
In the original IoC Type 3 form, the @View@ object knows that it will be communicating with a @Viewer@ object, and presumably knows the contract associated with the @displayError@ method. In the Listener form, the @View@ object has no idea what the @Listener@ object will do when notified of an error.
When combined with your plan to use a Controller class as a Listener, this is playing with fire. Suppose that halfway through your @doSomething@ method something goes wrong, causing it to fire the event. The event firing causes the Listeners to be called, and one of them is the Controller. The Controller must resist the urge to _do_ something about the problem that in any way involves or affects the @View@ object. The @View@ object is in an undeterminable and possibly unstable state, because its @doSomething@ method has only partially completed. In Design by Contract™ terms, the class invariant for the @View@ object is not required to hold until @doSomething@ completes.
Two obvious ways around this:
# Define a specific @ViewErrorListener@ interface with contracts that forbid such trouble-making, and
# Place the events on a notification queue that will not be processed until after @doSomething@ has completed.
Hmm… it seems to me that choice #1 essentially turns it into an IoC Type 2.
Grr… the “Live Preview” shows perfect formatting of paragraphs and lists. And the actual posting stripped them out.
_Snipped by sam_
Sorry Doug, the Javascript isn’t stripping out HTML – I’ve fixed up your original post and edited your followup.
Doug said:
bq. In the Listener form, the View object has no idea what the Listener object will do when notified of an error.
Why should a @View@ object care how the error is displayed? Does a @View@ know how it should be handled? What if I want more than one thing to listen to errors? If I was only ever going to display an error dialog then I agree that calling a displayError method is fine. That said I never stated that @View@ and @Viewer@ implementations would always be rich UI objects…
bq. In Design by Contract terms, the class invariant for the View object is not required to hold until doSomething completes.
But errors do happen. And sometimes errors from which an operation cannot recover, but may still be in a valid state. Validity of state and errors being thrown during an operation are two seperate concerns. Sometimes an error being thrown is expected, and might be a valid thing to happen (polling an outside service for example). If my @View@ is calling @fireError@ or whatever, it knows it wants to tell people that an error occured. Its then up to the listeners to decide what to do. If the @View@ doesn’t want third parties getting involved, it shouldn’t of called @fireError@ in the first place.
It’s not about “how the error will be displayed.” It’s about “what ELSE will happen?”
An example from (painful) personal experience: an object was iterating through a list and found something it didn’t like. It notified its listeners, one of whom tracked down the offending list item and removed it from the list. After the listeners returned, the original object attempted to continue using the iterator, with unpleasant results. (In Java it would be a ConcurrentModificationException).
This is where the danger is: the listener interface being used had no contracts which said what the listener was (and more importantly, wasn’t) allowed to do. The listener went off doing something that seemed to be perfectly reasonable and quite helpful: eliminating the trouble-making situation. However, the original object was in a state which could not tolerate that particular kind of help.
Not a problem in Java, but I’ve seen an extreme example in C : one of the listeners made a “fixup” that indirectly resulted in the original object being deleted. When the listeners returned, hilarity ensued.
Certainly the Observer pattern CAN be used without problems; people have been doing so for an awful long time. But there are hazards that must be considered, and having no contracts on the Listener and then using a Controller as a Listener definitely increases the “threat level.”
That’s supposed to be “C Plus Plus” in the penultimate paragraph. Apparently plus signs do something weird, too 🙂
You have simply changed your dependency from a Viewer to a listener list. Dependency injection can be used to set up either the Viewer or the listener list dependency, so this design decision has nothing to do with dependency injection but rather with tighter vs looser coupling.
What if both the Viewer and the Listener implemented the same interface and you passed that in instead? Wouldn’t the code for both examples then be exactly the same? The list of listeners could also be imagined as a CompositeViewer, which would take the responsibility of iterating over the list of listeners out of the View.
I tend to think of ‘construction time’ and ‘use time’ of an object as distinct and separate. An object’s instantiator may not be the thing that uses it, and passing dependencies into a constructor isn’t really adding complexity, just making the complexity that is already present in the system more explicit.
Darren wrote:
bq. An objects instantiator may not be the thing that uses it, and passing dependencies into a constructor isnt really adding complexity, just making the complexity that is already present in the system more explicit.
But the use of some tecnniques to instantiate the object (I’m thinking Spring and Pico here) can often obsure how the dependencies are being created and passed in in the first place. I’m not saying that this is a reason _not_ to use Spring or Pico, but that when using them in a system (especially an existing system) you can end up muddying the water somewhat.
Really interesting discussion. Often I’ve wanted to use listeners but frequently the infrastructure required to deal with adding and removing listeners, firing off events, creating interfaces put me off. I wish adding listeners didn’t require so much code.
Doug brings up some pretty good points too.
bq. the infrastructure required to deal with adding and removing listeners, firing off events, creating interfaces put me off
Java does provide the java.util.Observable class and java.util.Observer interface. Too bad Java doesn’t believe in multiple inheritance, though. Or at least, if Observable had implemented an interface that your class could implement by delegation.
Of course, if you have multiple events that might want to be observed independently, then you _need_ multiple Observable objects and inheritance wouldn’t do the job anyway. Then the simplest approach is for the observer to request the appropriate Observable from your object, and register itself with the Observable. A nicer approach is for you to create event-specific add/delete methods in your object that simply delegate to the appropriate Observables.
There are also some support classes, such as “EventListenerList”:http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/event/EventListenerList.html and “PropertyChangeSupport”:http://java.sun.com/j2se/1.4.2/docs/api/java/beans/PropertyChangeSupport.html which can make this process easier. I agree with Doug – this is one place where multiple inheritance would be nice. I typically end up creating Abstract implementations to handle event firing, or else use support classes. Another approach would be to use CGLIB proxies to create listenable implementations, although the amount of upfront coding, performance implications of using proxies and potential for confusion are rarely worth it.
I must say I really like this subscribe to comments feature.
I’m aware of the support classes. It’s still a lot of buggering around for what really should be a simple thing. Perhaps what we really need here is better language support for this idiom. Not sure what form that would take however.
I’ve often thought the same thing myself. Attributes coming in 1.5 might provide some of this – I guess we’ll have to wait and see how it’s handled. Off the top of my head I can’t think of any language which has support specifically for event firing/listening – some languages make it easy by their very nature of course. Speaking personally I’d rather code an event/listener pattern in Java than in C or Pascal 🙂