TOOD? TOOP?

Roy Osherove has noted a discrepancy between pure object-oriented design and testable design principles, and suggests that it's time to revisit how we think about software design. His current example is how the FxCop team has decided to internalize an apparently rather large portion of their API. Although I don't want to go into the particular discussion about FxCop, I can feel Roy's pain. Some of the APIs put out by ISVs (including Microsoft, I'm afraid) are notoriously hard to subject to unit tests, and often, this is because they take the principle of encapsulation too far.

Roy suggests adding the word test to object-orientation, turning it into Object Oriented Testable Design (OOTD) and Object Oriented Testable Programming (OOTP) . However, I'd humbly like to suggest that we call it Testable Object Oriented Design (TOOD) and Testable Object Oriented Programming (TOOP) - that's makes for some more pronouncable acronyms :)

In any case, I'm all for it!

Although the term is new (to me, at least), I've been using TOOP for years, so here's my take on it. The first thing we need to establish is that TOOD must embrace the best of both worlds. Although testability is important, so are many of the design principles of OOP, which means that we can't just blindly sacrifice OO principles for testability. If we do that, we are just test-driven, but not following TOOP. Obviously, the reverse is also true.

This means that to apply TOOD, you must be able to answer both of the following questions:

  • Is my API testable?
  • Is my API object-oriented?

If you can't answer yes to both questions, your API is not a TOOD.

The first question is quite easy to answer: In its extreme, testability is a binary feature of an API: It's either testable or it's not. On the other hand, whether an API is object-oriented or not is a lot more fuzzy. This is where I become a pragmatic idealist: If it's not testable, it's certainly not a TOOD. In practice this means that testability is a much more fixed feature of TOOP than object-orientation: Whenever we have an unresolvable conflict between testability and object-orientation, testability must win out.

This doesn't mean that I think that object-orientation is secondary to testability in importance. Note that I wrote unresolvable conflict. The trick is to not have any conflicts that are unresolvable. How do you achieve this quality in practice?

In my experience, utilizing test-driven development (TDD) is a very good tool in this regard, as this very effectively ensures that your API is testable; you will very quickly discover if it's not :) Every time you make an API design decision, you must then also think about whether it makes sense in a object-oriented way, since it not okay to expose members or types that should have remained hidden, just for the sake of testability.

Most of the discrepancies noted in Roy's original post concerns the conflict between testability and encapsulation. Although I agree that you can certainly have too much encapsulation, you can certainly also have too little. Each time you decide to expose an internal implementation detail, you make it part of the public API - not just for test purposes, but for all developers using your API. That can make refactorying very hard if you also want to maintain backwards compatibility.

Back at TechEd: Developer 2006, I had a rather interesting discussion with Udi Dahan about encapsulation vs. testability, where Udi's stance was that encapsulation was secondary to testability if you don't write frameworks or other APIs for mass consumption (I hope I don't misrepresent Udi here). This is a standpoint I meet a lot. To paraphrase:

The .NET framework design guidelines [which are, incidentally, policed by FxCop] are nice, but they don't apply to enterprise development, since I own all clients of my API, so I don't need to worry about backwards compatibility, etc.

In my book, all production code should be treated as framework code, even if I'm the only developer, and I'm writing and maintaining all upstream callers myself. Maintainability is excactly the main point here: If I follow a consistent set of conventions for my API, it will be much easier for me to return to it half a year later, and then still immediately understand what's going on. Someone else would in theory be able to do the same, since I follow conventions that should be broadly recognized.

Although FxCop (or the Code Analysis feature of Visual Studio) doesn't capture all object-oriented principles, it does capture a lot of them, so using this tool rather rigorously ensures a good degree of OOD.

In practical terms, then, a good approach to TOOP is TDD combined with Code Analysis, and I hope it goes without saying that suppressing code analysis violations to enable testability is not allowed :)

Comments

  • Anonymous
    February 28, 2007
    PingBack from http://weblogs.asp.net/rosherove/archive/2007/02/25/why-you-should-think-about-ootp-object-oriented-testable-programming.aspx

  • Anonymous
    February 28, 2007
    Pair-programming is getting a lot of attention latley. What should we call Object Oriented Programming that was tdd by a pair of programmers, Paired Object Oriented Programming? Should we really call it POOP ? I think not!!! :)

  • Anonymous
    February 28, 2007
    Heh, heh :) In all seriousness, though, I don't think we need a term for OOD that was developed using any particular methodology. How you arrive at a specific design is orthogonal to the design itself. What Roy and I are talking about is a need to reconcile two apparently opposing design philosophies into a common one; hence the need for a name.

  • Anonymous
    March 04, 2007
    When writing unittests, I always check whether or not, my code follows the principles of OOD: Single-Reponsibility, Open-Closed, The Liskov Substitution, Dependency-Inversion, Interface-segrgation, Commmon Closure, etc. If I have to violate any of these principles, in order to test the code, I must find another way to test it or rethink the design. In other words, while I do agree that OOD is secondary to testability, I would argue, that it is only marginally so. One should take meassures to follow boths sets of priciples (TDD and OOD), and only in extreme cases neglect the OOD, in favour of testability. Nice article by the way. It's a subject that is not covered well-enough IMO.

  • Anonymous
    March 04, 2007
    Hi Jan Thank you for your comment - I totally agree, and I hope that comes across in the post as well :)

  • Anonymous
    March 05, 2007
    Yeah ... It does. But I just felt like clarifying it a bit and humbly hoping to contributing a bit of wisdom. (and draw attention to myself - LOL).

  • Anonymous
    March 08, 2007
    COOD Continuous OOD or T-DOOD Test Driven OOD (I resisted TOOT and COOT).

  • Anonymous
    June 07, 2007
    At the upcoming Softwareudvikling på tværs conference, I'll be presenting a session on TOOD on the second