Your environment can have a profound effect on how you develop software. The details of what I discuss here have zero practical meaning outside of the .Net world (though you can probably find parallels in other environments). That’s because .Net developers have access to tools that invalidate rules of software design that are fundamentally important elsewhere (before you question whether an environment can effect what is good design, consider the difference between good design in C and, say, Prolog). For .Net, the free availability of a tool like Typemock makes a major design consideration simply disappear—namely, testability. Typemock literally robs the term “testability” of meaning in .Net design considerations. That’s a freedom that should leave other developers gasping in envy.
I don’t want to be a running commercial for Typemock here (they’re certainly not paying me to say any of this), but it is a truly revolutionary tool and its effect on development in .Net needs to be examined and understood. The thing is that using Typemock means that you can unit test literally any public method of any public class, regardless of any and all internal dependencies that class might have. And you can do so without changing the design and/or architecture of your software at all.
In other words, using Typemock means that everything is testable. Unit testable. Seriously. Everything.
Stepping into a world where literally everything is testable is like stepping into a world where you wake up at a designated spawn point instead of dying—fundamental considerations about what is risky and what isn’t need to be remapped. Which makes listening to .Net developers discuss testability considerations of various designs a little like listening to World of Warcraft players who are afraid to get too attached to characters that might die—it seems like a lot of effort for something that has little meaning.
Which is why I had such a hard time reading Jeffrey Palermo’s latest blog post entitled “Inversion of Control is NOT about testability”. Since I know Jeffrey Palermo is a .Net developer, my initial response is a big fat “Duh. He must be using Typemock.” Sadly, this is not the case.
That’s too bad because there are some very interesting things in that post that get obscured by continually dragging in testability. For one, he gives a good explanation of Inversion of Control accompanied by a discussion of why you might want to use it outside of unit testing. His statements about coupling in particular piqued my interest. He said:
NOTE: There is no such thing as LOOSE COUPLING. There is coupled, and not coupled. Either a type is coupled to a type or it is not. More accurately. Loose coupling exists much like the concept of "cold". When we say "close the door, you’ll let the cold out" on a hot day. Cold doesn’t exist. Either heat is there or it isn’t. We use cold to communicate, but it serves as a shortcut for the lack of heat.
Now, he got hold of a bad analogy (because there are degrees of heat—it’s not a binary value—so there is nothing wrong with describing something as “less hot” just as we say "less coupled") and his point is technically wrong (because whether you call it loose, deferred, proxied, or something else, when you are coupled to an interface that a class implements, you have a relationship to that implementing class that is similar enough to coupling that an adjectival modifier is an acceptable descriptor) but the core of his point is still a good one. Tying your class to an interface is a profound change and it is probably a good idea to examine what “loose coupling” means (i.e. how “loose” modifies a coupled relationship).
He later said something I found profound:
In order to do anything useful in software, you must couple. You must couple to something. (emphasis his)
and he later concluded with
You must decide where coupling is appropriate and where it is not.
Here’s why it’s a tragedy that Jeffrey didn’t make use of his Typemock-granted freedom from testability concerns: that’s all he said about coupling. He wasted so much unnecessary time with things that have no value or meaning in a .Net environment that he didn’t better explore what coupling means and when to mask coupled relationships.
And here’s my wider point: concerns about testability are imported from other environments. .Net folks discuss testability as if it has value in and of itself (because in other environments it does). We forget that testability is no more of a first-order good than quality is. “Testable design” only has value in the things it allows us to do—namely, unit test our classes. If we can unit test our classes as easily no matter what design patterns we choose, then that frees us up to explore other aspects of design choices. It isn’t that <le design du jour> ceases to have value, it’s just that testability is no longer a factor in evaluating its utility.
Those that realize this will have a competitive advantage over those who do not. If I can test no matter my project structure, then I can choose a design that more exactly fits other aspects of my development needs. Which means I can allocate resources more efficiently than someone who has design concerns that don’t fit the actual environment. I can choose <Der Entwurf des Tages> when and where it is actually, immediately useful instead of doing so in order to achieve testability. And efficiency kicks butt in the marketplace.
So, uh, forget all I just said. Spend lots of time making sure your .Net projects are testable. Also: Typemock sucks. Don’t bother going there...