In TDD, should we specifiy all classes to implement before start coding

by asinkxcoswt   Last Updated April 15, 2019 20:05 PM

My team is interested to apply TDD in our next software project. We have a discussion about how many details should be specified in design specs before the developers start coding.

Some of us propose that we should specify all classes and their relationship in specs before writing code because we have to design all test cases before implementing.

Some of us doubt that this will work practically. In previous projects, we only have a high-level design and let the developer designs the detail classes and methods on their own. The level of the detail in the specs is depending on the complexity of the requirement and experience of the developer. We write the specs only as detailed enough as to make the developer understand what should be done.

I am personally on the latter side of the discussion. I used to try to specify every bit of classes and methods in the specs in my previous projects before. Following are some example of problems that I encountered from doing so.

  • It takes too much time. To be able to design every classes and methods, an SA will more or less have to wear a developer hat to make sure that every bit of the design can be mapped to the actual code. As a result, the design often does not differ much from the implemented code. We have to work twice on the same thing: for the design and the implementation.

  • The developer does not have room to think. Writing the design this way sometimes leave only trivial logic for the developer to implement. It is like a fill in the blank kind of exercise for students.

  • The design often is premature. The design is done on a paper. We don't see how the code is actually running. There are some details we can only know when get our hand on the code. For example, the underlying framework might enforce us to design classes in some way and we don't know this while doing the design. And it is common to refactor some logic in a method to another class when we found appropriate. It's natural that new components can pop up during implementation.

I have tried researching on the Internet and found only this article related to this topic. The article seems to support my belief as it suggests that we don't have to do TDD on the detail classes.

However, the reference is not enough for us to decide. It is possible that designing every classes and methods is the right path and we just don't know the procedure to achieve that.

Please share your opinion, experience or references. Do you think we should d design every classes and methods in specs before writing code?

Answers 2

TDD is a design exercise. It does not mean "we have to design all test cases before implementing." Quite the opposite, in fact. In TDD, you repeat the following cycle many times:

  • Write exactly one failing test.
  • Write just enough of the implementation to pass that one test.
  • Refactor

It's okay to do a little bit of higher-level planning to make sure you aren't wasting time, but the idea behind TDD is most of your work is done test first, but in very small increments, usually a few minutes. Things like figuring out the exact set of classes you need falls very naturally out of that exercise.

Karl Bielefeldt
Karl Bielefeldt
April 15, 2019 19:39 PM

Some of us propose that we should specify all classes and their relationship in specs before writing code because we have to design all test cases before implementing.

If you do that, then it's not TDD (specifically, the design is not driven in any way, plus you've locked yourself out of refactoring). TDD is a way of working, it's not primarily about testing.

You should do some initial design, you should have an idea where you are going, especially at the area where the outer layers of the application interface with the core domain. You'll also be designing stuff on the go. But you should avoid big upfront design, because generally you don't know enough about the domain at that point to design every detail of the implementation.

You should take care that the tests don't know about the internal implementation details of the core application layers; in other words, you should consciously control the surface area over which tests interact with the application, so that you can refactor - meaning restructure the code in those inner layers without changing the functionality, and without changing the tests. Here, tests serve as a safety net. If you can't do that, then you are not doing refactoring, by definition. You are doing something else.

As you refactor, you'll see opportunities to reorganize code into new classes, or merge classes, apply patterns, rearrange dependencies, etc. Having a specification of all the classes up front is incompatible with that.

The tests need to be maintained, too; but you don't want to do that and refactoring at the same time. This way tests and the code sort of support each other. Sometimes, you'll write tests that go into the internals, serving as a scaffold of sorts, constructed to help you deal with a difficult problem, but then you'll want to find a way to change those tests so that they work through the outer layers. Or you may wan't to delete them (and yes, it's OK to create such exploratory tests, and delete them later).

Filip Milovanović
Filip Milovanović
April 15, 2019 20:02 PM

Related Questions

Updated November 02, 2018 15:05 PM

Updated June 26, 2017 22:05 PM

Updated March 15, 2019 16:05 PM

Updated March 10, 2018 20:05 PM

Updated December 18, 2016 08:02 AM