Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Test Driven Development take the focus from Design? [closed]

I have mixed feelings about TDD. While I believe in testing I have a issues with the idea of the test driving my development effort.

When you code to satisfy some tests written for an interface for requirements you have right now, you might shift your focus from building maintainable code, from clean design and from sound architecture.

I have a problem with driven not with testing. Any thoughts?

like image 409
Daniel Avatar asked Sep 17 '08 05:09

Daniel


People also ask

What is the main focus of test driven development?

In layman's terms, Test Driven Development (TDD) is a software development practice that focuses on creating unit test cases before developing the actual code. It is an iterative approach that combines programming, the creation of unit tests, and refactoring.

Does TDD helps the design process?

Using TDD you build up, over time, a suite of automated tests that you and any other developer can rerun at will. Better Designed, cleaner and more extensible code. It helps to understand how the code will be used and how it interacts with other modules. It results in better design decision and more maintainable code.

What are the disadvantages of test driven development?

Cons of Test Driven Development In the beginning, it may slow down development, but in the long run, it actually speeds up development. The whole team needs to buy into Unit testing for it to work well. Difficult to apply to existing and/or legacy code.

Is TDD a design principle?

TDD (test-driven development) has become a popular method to design and develop software to ensure that the code base is sufficiently tested and its behavior is captured in tests.


4 Answers

No.

If done right, Test Driven Development IS your design tool.

I hope you forgive me for linking to my own blog entry, wherein I discuss the pitfalls of Test Driven Development that went wrong simply because developers treated their tests as, merely, tests.

In a previous project, devs used a highly damaging singleton pattern that enforced dependencies throughout the project, which just broke the whole thing when requirements were changed:

TDD was treated as a task, when it should have been treated as an an approach. [...]

There was a failure to recognize that TDD is not about tests, it’s about design. The rampant case of singleton abuse in the unit tests made this obvious: instead of the test writers thinking “WTF are these singleton = value; statements doing in my tests?”, the test writers just propagated the singleton into the tests. 330 times.

The unfortunate consequence is that the build server-enforced testing was made to pass, whatever it took.

Test Driven Development, done right, should make developers highly aware of design pitfalls like tight coupling, violations of DRY (don't repeat yourself), violations of SRP (Single Responsibility Principle), etc.

If you write passing code for your tests for the sake of passing your tests, you have already failed: you should treat hard to write tests as signposts that make you ask: why is this done this way? Why can't I test this code without depending on some other code? Why can't I reuse this code? Why is this code breaking when used by itself?

Besides if your design is truly clean, and your code truly maintainable why is it not trivial to write a test for it?

like image 169
Jon Limjap Avatar answered Nov 04 '22 12:11

Jon Limjap


There's always a risk of overdoing either the TDD design or the upfront design. So the answer is that it depends. I prefer starting with a user story/acceptance test which is the base of the requirement that my tests will aid in producing. Only after I've established that, I start writing detailed unit tests TDD-style. If the only design and thinking you do is through TDD, then you risk too much of a bottom up approach, which might give you units and classes that are excellent in isolation, but when you try to integrate them into the user story fulfilling task you might be surprised by having done it all wrong. For more inspiration on this, look att BDD.

A great "debate" about this has been recorded between Robert C. Martin and James Coplien, where the former is a TDD advocate and the latter has stated that it ruins the design of a system. This is what Robert said about TDD and design:

"There has been a feeling in the Agile community since about '99 that architecture is irrelevant, we don't need to do architecture, all we need to do is write a lots of tests and do lots of stories and do quick iterations and the code will assemble itself magically, and this has always been horse shit. I even think most of the original Agile proponents would agree that was a silliness."

James Coplien states that merely driving your design from TDD has a great risk:

"One of the things we see a lot, in a lot of projects, is that projects go south on about their 3rd sprint and they crash and burn because they cannot go any further, because they have cornered themselves architecturally. And you can't refactor your way out of this because the refactoring has to be across class categories, across class hierarchies, and you no longer can have any assurances about having the same functionality."

Also he gives a great example of how a bank account probably would look if you test drove it as compared to using your upfront knowledge to drive the architecture:

"I remember when I was talking with Kent once, about in the early days when he was proposing TDD, and this was in the sense of YAGNI and doing the simplest thing that could possibly work, and he says: 'Ok. Let's make a bank account, a savings account.' What's a savings account? It's a number and you can add to the number and you can subtract from the number. So what a saving account is, is a calculator. Let's make a calculator, and we can show that you can add to the balance and subtract from the balance. That's the simplest thing that could possibly work, everything else is an evolution of that.

If you do a real banking system, a savings account is not even an object and you are not going to refactor your way to the right architecture from that one. What a savings account is, is a process that does an iteration over an audit trail of database transactions, of deposits and interest gatherings and other shifts of the money. It's not like the savings account is some money sitting on the shelf on a bank somewhere, even though that is the user perspective, and you've just got to know that there are these relatively intricate structures in the foundations of a banking system to support the tax people and the actuaries and all these other folks, that you can't get to in an incremental way. Well, you can, because of course the banking industry has come to this after 40 years. You want to give yourself 40 years? It's not agile."

The interesting thing here is that both the TDD proponent and the TDD antagonist are saying that you need design up front.

If you have the time, watch the video. It's a great discussion between two highly influential experts, and it's only 22 minutes long.

like image 44
Peter Evjan Avatar answered Nov 04 '22 11:11

Peter Evjan


There are many informal opinions here, including the popular opinion (from Jon Limjap) that bad results come from doing it wrong, and claims that seem unsupported by little more than personal experience. The preponderance empirical evidence and published results point in an opposite direction from that experience.

The theory is that a method that requires you to write tests before the code will lead to thinking about design at the level of individual code fragments — i.e., programming-in-the-small. Since procedures are all you can test (you still test an object one method at a time, and you simply can't test classes in most languages), your design focus goes to the individual methods and how they compose. That leads, in theory, to a bottom-up procedural design and, in turn, to bad coupling and cohesion among objects.

The broad empirical data substantiate the theory. Siniaalto and Abrahamsson, (Comparative Case Study on the Effect of Test-Driven Development on Program Design and Test Coverage), ESEM 2007, found that "Our results indicate that the cohesion may be worse (even though Beck claims that TDD produces highly cohesive systems). In our second study we noticed that the complexity measures were better with TDD, but the dependency management metrics were clearly worse." Janzen and Saledian (Does Test-Driven Development Really Improve Software Design Quality? IEEE Software 25(2), March/April 2008, pp. 77 - 84) found that “[T]he results didn't support claims for lower coupling and increased cohesion with TDD”.

A literature review will uncover other publications furthering these cases.

Even my dear friend Uncle Bob writes: "One of the more insidious and persistent myths of agile development is that up-front architecture and design are bad; that you should never spend time up front making architectural decisions. That instead you should evolve your architecture and design from nothing, one test-case at a time. Pardon me, but that’s Horse Shit." ("The Scatology of Agile Architecture," http://blog.objectmentor.com/articles/2009/04/25/the-scatology-of-agile-architecture)

However, it's worth noting that the broader failure is that people think it's a testing technique rather than a design technique. Osherov points out a host of approaches that are often casually equated with TDD. I can't be sure what's meant by the posters here. See: http://weblogs.asp.net/rosherove/archive/2007/10/08/the-various-meanings-of-tdd.aspx.

like image 32
Cope Avatar answered Nov 04 '22 13:11

Cope


I completely agree with pjz. There is no one right way to design software. If you take TDD to an extreme, without any forethought except the next unit test, you may make things harder on yourself. Ditto for the person who sets out on a grand software project by spending months on diagrams and documentation, but no code.

Moderate. If feel the urge to draw up a quick diagram that helps you visualize the structure of your code, go for it. If you need two pages, it might be time to start writing some code. And if you want to do that before you write your tests, so what. The goal is working, quality software, not absolute conformity to any particular software development doctrine. Do what works for you and your team. Find areas where improvements can be made. Iterate.

like image 43
user15074 Avatar answered Nov 04 '22 13:11

user15074