TDD is not (necessarily) microdesign!

Incredible how much have people been talking about TDD and problems with it over last few weeks. I thought it is mostly settled topic: it probably is not ideal, but it is pretty much best we can do for now in a long term. Yet many suddenly (or not so suddenly) decided that TDD sucks, is dead and creates more problems than it solves. One that I’ve stumbled upon and that made me write this post is: The pitfalls of test driven development (http://beust.com/weblog/2014/05/11/the-pitfalls-of-test-driven-development/).

I’ll just touch one point now: “TDD Promotes Microdesign over Macrodesign”. Go on, read that paragraph, I have time. OK, now that you read it – do you agree with it? I don’t. From the section title forward it seems to be based on very wrong idea about TDD – that TDD is the only approach you are using to write your application. Let’s clear this up. TDD is not a way (usually) to design your whole application from top to bottom. TDD is approach to write good, test covered code. TDD helps to design classes, components, maybe packages. But not applications or solutions to problem.

Imagine you have large business problem to solve. Would you really expect TDD follower to just jump in and start writing tests and code? Come on, no sane software engineer would do that. You think about the problem, you try to understand domain, all the details, all the caveats of this particular business problem. You are not thinking about the code at this moment at all. Maybe solution can be created without code at all? Are there other possible solutions to the problem? We don’t always need to write new programs, we need to solve problems.

Then you start imagining your application. What would you need, what big parts (modules) seem to be useful. Do you need distributed application to handle complex calculations? Will it be client-server solution? How much data will it process? How often? Those are all requirements you have to think before sitting down to code something.

Only after you have this broad idea of what you are doing, you can sit down and start writting code. And then TDD is what you follow. You write components and classes with tests to assert your invariants and to provide API for usage from other points in system. And you are better this way – TDD will help you create better, smaller classes, more practical solutions and so on. But on lower level. You’ve dealt with macrodesign before you even considered writting code in the first place. Now it is time for microdesign.

Yes, software writting is iterative process. That’s why having set of unit tests to cover your back is so useful. You will need to do some changes in your code. It’s better to have some tests that will assure you that all is working fine after changes. You can write them after you’ve created code or you can write it TDD style. Does not matter all that much. But don’t throw away TDD because of some missconceptions. TDD is not solution to all problems. It is solution to one specific problem – low level code testability. Not application high level design.

Advertisements

How fast should Unit tests be?

Well, fast. Damn fast, if you ask me. I have ~630 unit tests running in somewhere around 90 seconds. You can’t even imagine how slow it feels when you are trying to run them frequently. But when build time alone takes about 6 minutes, how fast your ut runs is negligible :(

And then there comes Greg Young with his idea of fast unit tests:

So I will keep trying to get to that level in my project. Hopefully so are you.

Casting to type variable – generic without Generics

Sometimes you cannot write simple generic code like Method(). When is that? Well – in unit tests for example. Imagine you have test that needs to run multiple times – each time for different type. Solution I’ve witnessed in production code is to write separate test for every type and copy-paste the code around. Terrible, terrible solution!

Another way could be to create separate tests, but extract common code to external method – now we can use generics – and just call that method. Much better, but still – having dozen methods just to call other one? There must be a better way!

And surely there is – data driven tests. [TestCase] in NUnit, [Theory] with for example [InlineData] in XUnit or even poor [DataSource] in MSTest. But it cannot pass generics, test method cannot be generic.

So I looked why exactly this test requires generic type. It all comes to this

try
{
    T result = (T)variable;
}
catch (Exception)
{
    Assert.Fail();
}

So just casting to see if object is of given type. I didn’t want to mess with test logic to much, just to reduce code quantity. So how do you write casting code without generics and knowing just the type (because we can of course get Type variable as parameter)? Simple as that:

object result = Convert.ChangeType(variable, type);

Is it perfect? Of course not – it returns object because it does not know the type it’s casting to. It might not be all that useful then. But in my case – it fits perfectly. Throws the same exceptions if casting is not possible, verifies if object can be assigned to variable of given type as the old code did. And now I can just have one test method with dozen test cases in it!

End of a day with TDD

Quick one today. You are doing TDD and it is fun and it feels right. Know how to do better? End each day/work session by writing failing test to the next thing you wanted to write. When you will be back to your code next time you will immediately know what you were doing, what you planned to do next and you will start right away. This is pretty good solution to the problem of looking through the code, source control history logs etc. to figure out where you left last time. Works for me!