ChallengeWindsor 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?
More posts in "Challenge" series:
- (01 Jul 2024) Efficient snapshotable state
- (13 Oct 2023) Fastest node selection metastable error state–answer
- (12 Oct 2023) Fastest node selection metastable error state
- (19 Sep 2023) Spot the bug
- (04 Jan 2023) what does this code print?
- (14 Dec 2022) What does this code print?
- (01 Jul 2022) Find the stack smash bug… – answer
- (30 Jun 2022) Find the stack smash bug…
- (03 Jun 2022) Spot the data corruption
- (06 May 2022) Spot the optimization–solution
- (05 May 2022) Spot the optimization
- (06 Apr 2022) Why is this code broken?
- (16 Dec 2021) Find the slow down–answer
- (15 Dec 2021) Find the slow down
- (03 Nov 2021) The code review bug that gives me nightmares–The fix
- (02 Nov 2021) The code review bug that gives me nightmares–the issue
- (01 Nov 2021) The code review bug that gives me nightmares
- (16 Jun 2021) Detecting livelihood in a distributed cluster
- (21 Apr 2020) Generate matching shard id–answer
- (20 Apr 2020) Generate matching shard id
- (02 Jan 2020) Spot the bug in the stream
- (28 Sep 2018) The loop that leaks–Answer
- (27 Sep 2018) The loop that leaks
- (03 Apr 2018) The invisible concurrency bug–Answer
- (02 Apr 2018) The invisible concurrency bug
- (31 Jan 2018) Find the bug in the fix–answer
- (30 Jan 2018) Find the bug in the fix
- (19 Jan 2017) What does this code do?
- (26 Jul 2016) The race condition in the TCP stack, answer
- (25 Jul 2016) The race condition in the TCP stack
- (28 Apr 2015) What is the meaning of this change?
- (26 Sep 2013) Spot the bug
- (27 May 2013) The problem of locking down tasks…
- (17 Oct 2011) Minimum number of round trips
- (23 Aug 2011) Recent Comments with Future Posts
- (02 Aug 2011) Modifying execution approaches
- (29 Apr 2011) Stop the leaks
- (23 Dec 2010) This code should never hit production
- (17 Dec 2010) Your own ThreadLocal
- (03 Dec 2010) Querying relative information with RavenDB
- (29 Jun 2010) Find the bug
- (23 Jun 2010) Dynamically dynamic
- (28 Apr 2010) What killed the application?
- (19 Mar 2010) What does this code do?
- (04 Mar 2010) Robust enumeration over external code
- (16 Feb 2010) Premature optimization, and all of that…
- (12 Feb 2010) Efficient querying
- (10 Feb 2010) Find the resource leak
- (21 Oct 2009) Can you spot the bug?
- (18 Oct 2009) Why is this wrong?
- (17 Oct 2009) Write the check in comment
- (15 Sep 2009) NH Prof Exporting Reports
- (02 Sep 2009) The lazy loaded inheritance many to one association OR/M conundrum
- (01 Sep 2009) Why isn’t select broken?
- (06 Aug 2009) Find the bug fixes
- (26 May 2009) Find the bug
- (14 May 2009) multi threaded test failure
- (11 May 2009) The regex that doesn’t match
- (24 Mar 2009) probability based selection
- (13 Mar 2009) C# Rewriting
- (18 Feb 2009) write a self extracting program
- (04 Sep 2008) Don't stop with the first DSL abstraction
- (02 Aug 2008) What is the problem?
- (28 Jul 2008) What does this code do?
- (26 Jul 2008) Find the bug fix
- (05 Jul 2008) Find the deadlock
- (03 Jul 2008) Find the bug
- (02 Jul 2008) What is wrong with this code
- (05 Jun 2008) why did the tests fail?
- (27 May 2008) Striving for better syntax
- (13 Apr 2008) calling generics without the generic type
- (12 Apr 2008) The directory tree
- (24 Mar 2008) Find the version
- (21 Jan 2008) Strongly typing weakly typed code
- (28 Jun 2007) Windsor Null Object Dependency Facility
Comments
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
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).
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..
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.
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.
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
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.
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. :)
Comment preview