Apr 25, 2009 at 5:00 AM
Edited Jun 9, 2009 at 10:37 AM
I've been "Ninjecting" the codebase and it's pretty much complete.
(As of changeset 16047, it's safe to use again)
By "Ninjecting", I mean that I decided to use Dependency Injection in Cradiator and chose
Ninject as the container.
I chose Ninject mainly because the syntax is the simplest and most intuitive of all the containers I looked at (over Unity / StructureMap / AutoFac / Windsor). And also because it's
Cradiator is not a large app and so Ninject sounded like it was the right container for us.
Although I've used DI before, I was quite surprised at the impact on the code base. It helped remove almost all of the "crappy code".
The code coverage is now at around 75% (up from about 55%). The extra code coverage came about by writing tests that "obviously" needed to be written, not by a concerted effort to increase
In many cases, the tests could not have previously been written - an additional benefit of using DI.
Separating code into more classes (with dependencies clarified and/or mocked out) enabled me to write tests where it was previously impractical or impossible.
The super-clarifying aspect of using DI, that I hadn't quite appreciated before is,
how clear a class can be.
When you declare a class and explicitly declare it's dependencies (ie what they need to work), it becomes a very clear
doer. "This is what I do and this is what I need to do it".
With such obvious responsibilities it becomes clearer to use and test.
And it then becomes clearer if a class is doing too much.
It's then easier to split that class and declare a new class and it's dependencies and so on, add infinitum.
As I slid down the dependencies of my code, it constantly became clearer and cleaner.
I'm now at the bottom of the slippery slide and I want to go again. I don't think DI is just for large projects - I'm completely sold on this.
The Presenter went from about 150 lines of code to 80 and it was clear to me after finishing a round of DI, that this is how it should be.
It had too many responsibilities - it was the everything man.
The previous mode of feature adding went like this: "Want new functionality?... add a variable and a method to the Presenter"
Hence the well-documented "Fat Presenter" (or
Fat Controller) problem.
Using DI really helped me to SRP (Single Responsibility Principle) the application to the max.
I've used the as yet unnamed principle of "Show me a private method that belongs in the class" to flesh out methods that are hiding separate responsibilities. (We had this rule scribbled on the whiteboard at work for weeks to challenge us).
I did not purposefully seek to destroy every private method. But judging each private method on its merits, made it clear to me that most of them belonged in a class of their own.
I think the Cradiator code base is now clean.
There's a few TODO issues, but they are relatively easy to fix.
I don't think the level of SRP has made "too many small classes" or made the code harder to follow in any way - which can happen if used without balance.
If anyone disagrees, let me know your thoughts and perhaps to point to specific code and I'll be happy to discuss.