TDD train of thought

by Vlad 12. March 2010 13:30

 

I used the word "help" in this post ( We can’t use Test Driven Development! ) because TDD is not a silver bullet. NOTHING is. But that is not a reason not to look for improvements in the way we work.

I'm going to try to explain why I think TDD can help you in MOST of the software development projects out there.

First, mentioning something like "zero defects guarantee" when talking about TDD or testing in general is a hint in my oppinion that a lot of people see the tests as a way to FIND defects.

Myth: The Job of Testing Is to Find Defects

The job of tests, and the people that develop and runs tests, is to PREVENT defects, not to FIND them.

(Mary & Tom Poppendieck, "Implementing Lean Software Development From Concept to Cash")

Knowing that, correct me if I'm wrong with this train of thought (and see if it applies to your case, I can't think of a project where it would not apply):

1. To have or not to have tests. (By tests at this point I mean test cases, automatic or manual, covering the whole system or just a method. Tests in general).

Not having tests leaves me with the task of guessing whether my functionality really does what it is supposed to. Remember, computers do what you tell them to do, not what you want them to do. So having to tests would mean code -> compile-> mark task as done. Unfortunately it actually happens, and way too often.

But that's not the way we do it! The developer DOES check that it works!

Ah! That IS testing, so we MUST have tests then!

2. To have a test list or not.

Testing the software by randomly executing operations will not give you enough certainty that it does all it is supposed to do. The reasonable thing to do is make a list of tests that cover all the cases you can think of. Of course, the list is not cast in concrete - tests can be added or modified.

The list can be an excel or word document. Or code. Or a table on a whiteboard. Or a scribble on a piece of paper. Keep it in your memory only if you never forget anything (hello there, R2D2!).

The important thing is that it needs to specify the setup, execution and validation for each test so it can be shared among team members.

3. Define the tests before or after implementation.

Both work, but tests defined them after implementation (especially by the developer), will tend to validate what the code DOES, instead of what it is SUPPOSED to do. More, defining the tests before can help the developer contemplate cases he could have overlooked and serve him as a progress indicator (9 out of 10 tests passing is a hint that you are close to finishing).

4. Automated or manual tests.

Being able to run your tests automatically and have the feedback in seconds instead of minutes is, of course, a big plus. And, you can setup a Continuous Integration server to give you fast feedback about integration problems.

You have to take into account the time to implement them though. And testing whole applications can could imply slow operations like setting up data in databases or connecting to services. And, depending on your frontend technology, you might find that UI testing frameworks are still limited. Which brings us to the next point:

5. Big coverage or small coverage tests.

Small coverage implies cheaper tests - cheap to develop because you can mock external dependencies and check a specific flow without worrying about "downstream" effects, and cheap (fast) to run because everything is in memory - no database access or web service calls. This type of tests are usually called UNIT TESTS.

Having a good coverage of the internal workings of your components allows the bigger tests to cover the integration parts, the communication between them, validating that they play well together.

 

In conclusion, if the above applies to you (and if not, I welcome comments on why it doesn't): you should ALWAYS HAVE TESTS, DOCUMENT them, preferably define them BEFORE implementation, and you get a big productivity bonus if they are AUTOMATIC which is a lot cheaper if most of them are UNIT TESTS.

 

We can’t use Test Driven Development!

by Vlad 4. February 2010 02:11

“We can’t use TDD! It would increase our development times / costs too much! It’s just not worth it.”

IT’S OBVIOUS!

Of course, it depends on what do you understand by “development”. If you mean the activity of writing code, tests are code, so more code needs more time / resources to be written. Duh!

Testing / bug fixing and maintenance!?! That’s not development, that’s…uh… something else… it doesn’t count.

Most of the people I’ve heard using that remark don’t even count the tests performed by the developers as development time. So, we’ve written enough code, we can call development “done”. It’s a good moment to mark the task as 100% and congratulate ourselves. Don’t forget to impress the upper management with the updated Gantt chart showing the on time completion of 80% of the project. What’s left? Just testing and bug fixing, that shouldn’t take long, right?

As a bonus, we’ve written the code “cowboy programmer” style. Time is all that matters, so we cannot be bothered to think twice about inserting into the database directly from the presentation layer or about increasing that “core” stored procedure from 10,000 to 12,000 lines (no indentation, of course – what a waste of time that would be). Of course, we’ll refactor that later. We did manage to add some would-be-nice features though. We had to do a little harmless over engineering, but we’re sure the client will appreciate them.

Does any of this sound familiar? Can you guess what happens next? Of course, the remaining 20% take more time than the “actual development”. Every bug fix creates other bugs. In the end the client gets to be the tester, reporting defect after defect in the “stabilization phase”. No, do not call it Beta testing –the client would never agree to pay and/or participate in that.

Time has passed… we get less bug reports, but fixing them takes much more time. With much of the original team gone or assigned to other projects, it’s even more difficult to know if we’re not breaking something while fixing another. Refactoring is out of the question. The over engineering we did makes debugging a nightmare and on top of that the stupid users asked us to hide some of the “would-be-nice” features. Fear of being the one that caused the whole thing to blow up in the client’s face has made us religious – we change and pray.

Fade to black… the end. Happy end actually (well, sort of)...

But IT NOT OVER! Now we have to add a new module to the existing fragile application. Time is crucial, so we do what we do best: code like crazy, spend nights at the office and it’s done with only a small delay. “Actual development” that is.

There is a hail of defects that bury us in tickets. More nights at the office. Sleeping at home is a distant memory. Did I tell anyone to feed my cat? It’s too late now anyway. And who did this STUPID change in this method?!? Oh, that was me, last night.

The client is not happy. Stupid user! Why would he expect the existing functionality to work?!? This is “STABILIZATION PHASE”!

Now imagine that another project comes along after that storm finally settles down.

For this one, we could use TDD. Yes, more coding time, but we would have our functionality in a harness. We could do refactoring without fear. The code would be less smelly. It would be difficult to write tests for huge methods or business logic-hungry stored procedures, so we would HAVE TO keep it clean. No extra features or over engineering this time – the tests would keep us on track.  We could probably have a reliable shippable product in less time than it took is to deliver the previous, unreliable one.

There will be defects, of course, but we could reproduce them with tests and ensure that the fix is correct by running all the tests.  I could even go as far as to predict that the number of defect would be significantly lower because the tests we’ve written helped us identify exceptional cases and prevented later changes from breaking existing functionality. Also, adding more functionality later should be much faster and secure. All this would translate into fewer resources needed for maintenance. No more wasted nights…

Yeah, we could do all that… but we won’t. We’ll do things like we always do and expect different results.

Well… THEY’ll do it. I just can’t afford to lose another cat.

 

Categories: TDD