I'm going to express an opinion that is a little contrary to the current trends and buzz of the Java World:
I think Test-Driven Development is a useful practice, and I think having automated Unit Tests can improve the quality of your code.
How is that a contrary opinion? Well, compare that modest statement to the current evangelistic masses of postings that say that Test-Driven Development is the ONLY way to develop code, and that Unit Test must be written for 100% of your classes or your entire application is useless.
What I'm concerned about is the rampant proselytizing of the TDD crowd that is over-selling (and potentially damaging) the very cause they support. A fellow Java developer once told me that if I wasn't using JUnit, then I wasn't coding. He said it is impossible to write a professional application without JUnit. I find that to be an incredible statement considering JUnit has only existed for a few years, but people have been writing professional software for nearly 50 years.
I do use JUnit myself, but it is just a tool. It is a useful tool, but it is just one of many tools for testing your code. And TDD is just one of many useful techniques for testing your application.
I also think that different parts of an application benefit from different testing strategies. In a typical layered architecture, I do not find it as cost-effective and useful to write Unit Test for the upper layers of an applications as it is for the lower layers.
The following are observations from my own experiences with doing Test-Driven Development:
- Bugs in the top layers are cheaper (easier to find and fix) than bugs in the bottom layers. A bug in a JSP page or Controller is quick and easy to resolve. It's usually pretty obvious when you try to view the page. A JSP page can be changed on-the-fly without having to recompile anything or rebuild the WAR. A bug in a JSP page generally has minimal impact on other parts of the system.
As we go down layers in the application, bugs become have more wide-spread impact and are also more difficult to resolve. - Top layers are harder to unit test than the bottom layers. It is usually fairly simple to write a JUnit test for low-level core components. Such components are more atomic, and have fewer dependencies and simpler interfaces. Components at the top layers (at the MVC layer) are far more difficult to develop with a test-first strategy, often requiring a fair amount of Mocking and other sophisticated scafolding tools just to simulate a realistic run-time environment.
The exception to my rule that "lower levels are easier to test" is the Data Access layer. Data components can sometimes be difficult to test in isolation when they interract with tables that cannot exist in isolation. A relational database is a complex system of its own, and so your bottom-layer Data Access component becomes the top-layer of this whole new platform, and thus requires all that sophisticated scafolding to simulate what it needs. - Top Layers experience the greatest amount of flux and rework as the users change their minds about what they want to see on the screens and how they want the pages to behave. One of the drawbacks of TDD is that it doubles your maintenance cost when you have major rework. Not only do you have to rework all your application code, but you also have to rework all the tests you've previously written. (And if you are doing TDD properly, that means re-working the tests FIRST.)
Conclusion: You don't have to use TDD for everything, and you don't have to test all things equally. If bugs at the top layers are cheap, and testing the top layers is hard, and the top layers are not stable fixtures where up-front investment leads to longevity, then there much less cost-benefit justification for writing Unit Tests for your top layer components.
I think that statement would be considered heresy among the evangelistic TDD crowd. And I often wonder why so many TDD developers claim that you have to write automated Unit Tests for 100% of your objects.
Here are my theories (look out...another list of observations...):
- As I've previously mentioned in other postings, we have a huge conceptual gulf between the Java leaders (the architects, the Open Source developers, the framework developers, the book publishers) and the other 95% of us writing masses of quick real world applications. The top 5% of the Java Developers spend most of their time writing long-lasting fundamental services, frameworks, and architectural stuff that has a disproportionately high benefit from using things like JUnit and other TDD techniques.
- I also believe TDD evangelism to be a subjective personality phenomenon. Software has become so abstract and so flexible that the human factor has to be taken into consideration. Some people are more detail-oriented, some people are more goal-oriented. Some people are great planners, some are great organizers. Some people want only black-and-white, some people see only shades of grey. And our development tools and techniques are now flexible enough to adapt to human personalities.
I think for a certain range of personality types that are prevelant in the development world, Unit Testing just FEELS good to them. It makes these types of people very happy and very satisfied with their job when they can click the "Run Tests" button and get the "Green" bar telling them all is well. In fact, if you read any of Kent Beck's books, there is MUCH emphasis on the red/green bar as a motivational device for developers. (Very much like rats performing tricks for food pellets). Having constant feedback and rewards is especially motivating for many people. It practically turns coding in a game of EverQuest. :)
It also helps if you really enjoy coding, because JUnit is a tool that allows you to do all of your Unit Testing as a programming exercise. Another prevalent personality trait in the development world is a dislike of documentation and other non-technical forms of communication. So these types of people naturally gravitate toward any way to put more and more of their job into Java instead of English. (Note the popularity of JavaDoc, JUnit, and the generally overly-optimistic belief that "my code is self-documenting".)
So, I think the emotionally-charged component of the TDD revolution comes from the fact that TDD just really feels good to a certain range of personality types.
What I don't see is hard facts and evidence that prove that writing JUnit tests always pays for itself. Sure, it pays for itself in many cases and for many of your objects, but I don't think it does in all cases. I think the successful paybacks are masking the unsuccessful ones.
Unit Testing 100% of your application does probably return a reasonable ROI (Return On Investment) compared to not testing it AT ALL. But what I'm claiming is that picking and choosing the key parts to test, the easy parts to test, the valuable parts to test, will bring you an even higher ROI. And that number of objects is something far less than 100% of your application.
Spending 2 hours writing all the scaffolding and mocking necessary to test some view component that is going to drastically change 4 more times in the next week just isn't worth it.
TDD is a wonderful technique for testing core reusable and long-lived parts of your application. I just don't want to see too many developers and applications get swept up in the promises of the current hype-wave around TDD. It needs to settle back down to a reasonable level of expectation, especially for the front-line developers who spend most of their time working leaf-node, non-reusable, non-durable components.
1 comments:
Heretic heretic!!! Burn persecute etc!!!! :-)
Very well written Bert.
Post a Comment