Object Oriented Testable Designed - You must be out of your mind
Roy has posted a new design methodology: Object Oriented Programming that is Testable!
Roy and I are on the opposite sides of this methodology. I personally hate to change my production code just for the tests.
As Roy says “pure object oriented design does not go well hand in hand with the notion of testable design.” After creating a good design (without taking testability into account), there is no real business value of implementing hooks to change internal private members and to expose properties that should remain private by design! Unless you want to clutter your code with load of Totally Irrelevant Code
Please, Stop Designing for testability!!
There is no need to do this, using the right tools you can enjoy both worlds.
We all have have seen testable code. The code is hard to maintain and understand. A Testable code, will have many interfaces that have no real design value, that will just confuse developers. Have you ever tried to browse a code with loads of interfaces, it take ages because you have to keep finding the concrete implementation, and the place where the instance was created.
Think about this code smell: When you find that an interface and implementation have exactly the same public methods, it is a sign that the interface is not exposing a trait of the object but the Object itself. This is what happens when your code is Designed for Testability, you do have a safety net, but the design is flawed.
Using TypeMock.NET your code can be encapsulated (OOD) and Testable at the same time:
- OOD: Do not expose any private members or methods that are not needed by the developer using your API .
- Testable with TypeMock: Easy to replace private instances of objects without changing your code or exposing unnecessary parts
- OOD: Seal classes to inheritance by default unless you explicitly mean for others to extend them
- Testable with TypeMock: No need to extend and override your objects just to test them
- OOD: Only make methods virtual explicitly when you want others to override them.
- Testable with TypeMock: Keep your methods non virtual (its faster). you can still test the code.
- OOD: Use singletons to make sure only one instance exists. do not allow anyone to touch that private instance.
- Testable with TypeMock: Don’t allow others to replace Singleton instances, TypeMock will do it for you in your tests.
- OOD: make types private or internal by default unless you want to expose them specifically.
- Testable with TypeMock: Keep your types private so that you can hide the implementation, you can sill test the code
- OOD: Don’t add unnecessary API’s
- Testable with TypeMock: No need to clutter you production code with special API’s
Navigation
Recent Posts
- Interesting Unit Testing Survay
- May 16 2008 - Typemock Isolator 4.2.4 is available
- May 16 2008 - Ruby Style Mocking in .NET
- May 15 2008 - Understanding Mock Objects - Better Design
- Apr 29 2008 - Why Typemock-Isolator for TDD?
- Apr 27 2008 - Patent Scam
- Apr 27 2008
Categories
Archives
- May 2008
- April 2008
- February 2008
- January 2008
- December 2007
- November 2007
- October 2007
- September 2007
- August 2007
- July 2007
- June 2007
- May 2007
- April 2007
- March 2007
- February 2007
- January 2007
- December 2006
- November 2006
- October 2006
- September 2006
Managment
Copyright 2006. Eli Lopian. All rights reserved.










23 Responses to “Object Oriented Testable Designed - You must be out of your mind”
1 Yoni 27 February 2007 @ 9:32 pm
“When you find that an interface and implementation have exactly the same public methods, it is a sign that the interface is not exposing a trait of the object but the Object itself.”
What if there is more than one implementation of that interface (in the production code)?
I agree over-abstraction merely for testability is wrong but configuring runtime replacements of concrete classes for the same purpose sounds equally awkward…
2 Eli Lopian 27 February 2007 @ 11:55 pm
Yoni,
I must agree that AOP does sound awkward, but more on that later.
When there is more then 1 implementation of an interface and both have the same public methods as the interface - It is still a code smell.
In most cases the code is not designed well. You will almost ONLY see this in ‘Testable Code’.
An interface in a good design exposes a trait of an object, Take IList - when an object implements IList it has the trait of a list. When an object implements IEnumerable, you can iterate on the object. Notice that each interface is a trait that we add to our objects.
Take ArrayList that implements IList, it has many more public members then IList. Notice that even Count is not a member of IList. This is a because IList is a Trait of a list and not just an Interface used to isolate and test the code.
So basically as you say, the choice is:
1. Create these interfaces, deliver them in your production code (over abstraction)
2. Use tools that enable you to test your code without mucking with the design (automatic isolation by adding a testable aspect* to you code)
And yes AOP is really weird…
* aspect as in Aspect Oriented Design
3 Yoni 28 February 2007 @ 8:35 am
Let us consider System.Data.IDbConnection. When I create a gateway to my new database I would probably create a connection class which exposes that interface and requires no more public members in order to function as an ADO.NET provider, is this a code smell?
An interface is an abstraction that should have different concrete implementations, this does not require the implementations to have any other public members.
And, besides, if there is more than one implementaion then the code that uses the interface can be tested using a mock without designing for testability (consider code that operates on an IList).
4 Eli Lopian 28 February 2007 @ 9:16 am
Yoni,
That is a great example.
Take a look at SQLConnection is has 3 time the amount of public API’s then the IDbConnection that it implements. OracleConnection has twice as many.
I am sure that if you had to create your own Connection Class it would have to have more public methods then just the interface.
So I still stand behind: “If your interface and concrete class have the same public methods, something is probably wrong with your design”.
You might find having a base class is a better design or if think about the Traits that the object has you can extract those into interfaces.
Of course if your production code REQUIRES using pluggable and changeable components, you will have to use some kind of Dependency Injection and then this will lead to the code being testable, but the business requirements should guide you NOT the testability.
Making your code testable, is like creating a modular TV Set, with an opening at the back of the set that you can easily open (without screws) put your hand through, dislodge the Remote Receiver (which you can switch with a mock Remote and test the TV), same goes with the volume controls, speakers etc. etc.
This is great and now you can sell the Modular TV Set to the world.
The thing is that it is more expensive to make (in code this means that the code is more complex) and there is no real business value. Who wants to pay more for a modular TV set?
Of course you can say that the TV set have been tested and this has value. But then with TypeMock you can do the same and lower the price of the TV set because you don’t have to make it modular.
5 Yoni 28 February 2007 @ 2:13 pm
If you are familiar with the GoF design patterns it won’t come as a surprise that almost all of them are cases of classes that expose the same public interface as the interfaces they implement.
Take a look here:
http://www.dofactory.com/Patterns/Patterns.aspx
(this site uses pure abstract base classes but that is exactly the same as using an interface).
6 Eli Lopian 28 February 2007 @ 3:41 pm
:-)
I understand that we differ here, this is of course my opinion, you may not agree and design differently.
The GoF design patterns may have examples like you say, but these are examples, and in real life code you don’t normally just print text to the console.
My point is: when you find classes that expose only the same methods as the interface they implement - Take a GOOD look at your design
Your code might be over abstracted.
7 jons : In Defense of Testability 2 March 2007 @ 9:28 pm
[…] There is an ongoing conversation in the blogsphere about testing, specifically whether the design and code should be modified to support testing. See Roy Osherove, Eli Lopian, and Stop Designing for Testability. […]
8 JH 3 March 2007 @ 4:49 am
“Have you ever tried to browse a code with loads of interfaces, it take ages because you have to keep finding the concrete implementation, and the place where the instance was created.”
I’d suggest that that’s a problem with the tool. It _should_ give you a drop-down of the interface and all types that implement it in an intellisense-y (resharper-y) fashion.
9 Thomas Eyde 3 March 2007 @ 6:23 pm
This is probably just me, but I consider mock based tests a design smell. You see, mocks and I are not friends. Each time I found a useful mocking framework, I failed.
The root cause of my failure is my mock based tests verifies implementation and not behavior. That makes refactoring hard.
Last time I gave up a third of my tests, because I lacked the energy to do the right thing. The tests broke due to internal implementation changes, even when external behavior was unchanged.
10 Eli Lopian 4 March 2007 @ 6:38 pm
Thanks for posting your ideas.
JH, thanks for the pointer, I was really trying to point out that introducing IoC, lowers the maintainability of the code.
Thomas, I understand where you are coming from, there is a lot of truth in what you say. You have to know when to use mocks.
11 Evan 5 March 2007 @ 3:20 am
@ Eli
The modular tv analagy would fit only if the tv owners were trying to add additional features or change existing features after the set was purchased. I don’t know many TV owners who try and upgrade their analog TV to support HiDef. Every application I’ve worked on, however, has gone through an equivalent large-scale feature upgrade.
I would agree that concepts like IoC and dependency injection are code smells in an application which does not need to evolve with business requirements, but until I meet an entepreneur with a set-in-stone business plan, I will continue using my DI container and programming to interfaces.
On the other hand, my view of this topic is only through the eyes of enterprise application development. If I were developing something else (say..a mail server or general purpose library), my opinion would probably be quite different.
12 Eli Lopian 5 March 2007 @ 9:50 pm
Evan,
Thanks for your post,
Perhaps the analogy wasn’t so good.
The point is: Once a business requirement arises that required IoC, by all means do it. But not one second before.
(As you say) We are not profits and we don’t know what future requirements will be needed. Lets do it the Agile way:
Have a test bed, so that we can re-factor our code base easily and add features as they come. Do the Simplest thing that can work.
Don’t start putting hooks, this is NOT the simplest thing that can work.
13 Low Country Software Ramblings » Pot Pouri Fridays 10 March 2007 @ 5:30 am
[…] If you are interested in Agile methodologies, go see James Shore’s Agile Book draft. He is soliciting feedback from the community. The book promises to be very interesting. It’s an O’Reilly so it has to be good! I can’t wait too see the colophon design! We all know that Unit Testing is a good thing. Do yourself a favor, and check out Roy Osherove’s The Art of Unit Testing blog site. It’s a subset of his main blog related to the book he is writing and unit testing in general. Roy and Eli Lopian have an ongoing discussion about the merit of Testable Object Oriented Designs or the lack thereof. All I can say is that Eli has definite opinions! Yet another blog to add to my growing collection… […]
14 Ivan 17 May 2007 @ 8:20 am
Nice
15 Evangelos 17 May 2007 @ 12:15 pm
Cool…
16 Metrophanes 17 May 2007 @ 4:15 pm
Cool!
17 Hristos 19 May 2007 @ 5:50 am
Interesting…
18 Pericles 21 May 2007 @ 7:35 pm
Cool!
19 Leontios 23 May 2007 @ 4:45 pm
interesting
20 Demetris 7 June 2007 @ 2:15 am
Cool…
21 Tasos 9 June 2007 @ 1:26 am
interesting
22 Leo 11 June 2007 @ 5:21 am
Nice!
23 Thanasios 13 June 2007 @ 4:47 am
Sorry