Ayende @ Rahien

It's a girl

Challenge: Windsor Null Object Dependency Facility

In Scott Bellware's post about dependency injection, he has a comment about optional dependencies:

Setter dependencies are optional.  Their types should have a Null Object pattern implementation, and if not it's often a good idea to decorate them with one.  For example, if an optional dependency hasn't been set, it might not be desirable to have a null reference exception when a method is invoked on it

The challenge is to provide a facility for Windsor that will detect an optional dependency and fill it with a Null Object (i.e, an implementation that doesn't do anything). It is safe to assume that all such dependencies are using interfaces.

Can you do it?

Comments

hammett
06/27/2007 10:14 PM by
hammett

Yes I can. But I dont quite agree with him. If the class exposes optional dependencies it should be capable of using default implementation of those. That's something I mention here

http://www.castleproject.org/container/facilities/v1rc3/logging/index.html#BestPractice

Ayende Rahien
06/27/2007 10:19 PM by
Ayende Rahien

I would be freaked out if you couldn't :-)

I think that this is something that should be handled in the container level, freeing the application code from checking that, or supplying a null implementation explicitly.

IUsageNotification is an optional dependency, for instance, and I may want to write it up for some controllers, and not for some, and I don't really care to maintain a NullImpl for that (rapidly changing interface, for one thing).

hammett
06/27/2007 10:24 PM by
hammett

I disagree. I think classes should be coded in a way that they can used with/without a container. So, not relying on anything to work well. And I think that Castle.MicroKernel was coded to match exactly this goal. In other words, reversibility.

Btw, can you show up on GTalk this weekend? We need to talk about the presentation..

Alex Henderson
06/27/2007 11:30 PM by
Alex Henderson

I agree with hammet on this one... components with optional dependencies should be usable with or without the container, perhaps the class itself makes use of a static NullObjectFactory to create the appropriate null object, but I think having it created/injected by the container transparently implies that constructor can't be used without the container in the mix.

Ayende Rahien
06/28/2007 12:48 AM by
Ayende Rahien

I think that at least part of the difference is that scenarios like the NullLogger is not something that I would use an optional dependency for. I would inject a null logger in the ctor and be done with it.

My use of optional dependencies is usually something that is truly optional, stuff like INHibernateInitializationAware, which lets you register into the container and affect other stuff.

Scott Bellware
06/28/2007 12:53 AM by
Scott Bellware

I tend to think that the use of a null object pattern for a dependency should be the decision of the class that holds the reference on the null object rather than the container.

If the container is going to set the value of an optional dependency, then why would it set it to the null object implementation rather than a real implementation? I can't really come up with a tangible story that would drive the implementation... but that's probably a limitation of my own rather than a statement about objective reality.

That said... it would be kinda cool to have a dynamic null object factory/facility that would allow us to get a null object implementation of an interface that is based on DyanamicProxy

Jeff Brown
06/28/2007 04:53 AM by
Jeff Brown

It can't work. There is no general-purpose rule available to a runtime code factory like DynamicProxy for it to understand the contract a given null object should really have. This is particularly true when return value or output params are met. The consumer of the null object might not crash on an NRE when it calls a method on the null object but then it might fail when it consumes the result.

Moreover, as others have mentioned here, I think it's the component's responsibility to use a suitable default implementation (such as a null object) and to guard against nulls as needed. For example, in externally visible services, I am very careful to check for null parameter values and throw ArgumentNullException if I know the component can't handle them. If I don't have a suitable default implementation then the dependency becomes a required constructor parameter.

Derick Bailey
06/28/2007 01:29 PM by
Derick Bailey

If I took a stab at actually implementing this, i would probably follow the same sort of patterns that the Automatic Transaction Facility in Windsor uses, with the [Transactional]/[Transaction] attributes and the Interceptor to handle the transactions.

I would basically do something like create a [NullObject] attribute that i can apply to a property and create an Interceptor that looks for the [NullObject] attribute and handle a null implementation through the interceptor.

that being said - i actually have no idea how to implement the interceptor. i'm only talking from the theories in my head of how i understand the interceptors in Windsor to work. :)

Comments have been closed on this topic.