3 ms·
TDD is awesome, if you have a codebase or a tech stack that makes it nice. TDD will quickly expose bad design through an unpleasant testing process. For example
by programminggeek 14y ago
TDD is awesome, if you have a codebase or a tech stack that makes it nice. TDD will quickly expose bad design through an unpleasant testing process. For example, slow tests, untestable code, or tests that you "always have to rewrite/maintain" are problems that only show up when you try and TDD your code that isn't designed to be testable.
TDD doesn't work well if you don't design your code to be testable because you very quickly become frustrated by the problems TDD uncovers.
1. Slow Tests - If your tests are taking a long time, it's probably because your code isn't written to be tested easily.
For example, if your code is hitting the database a lot and it starts to take minutes or hours to run your test suite, your code has a problem. For example, if your entities/models are coupled to an ORM like ActiveRecord, testing those is going to suck because they probably sholdn't be coupled to an ORM. Many people try to fix this by writing frameworks that make testing their code easier instead of writing better code that isn't tied to an ORM.
Tests should be fast. Most of the time they don't need to hit the DB. Slow tests make TDD suck. Avoid slow tests.
2. Untestable Code - I've run into this a lot and it sucks, especially in languages that lend themselves easily to untestable code (In my experience, that's PHP).
Until you try to test your code, you don't realize how untestable your code is. A lot of things that seem like reasonable design decisions are so untestable, that you end up doing incredibly lazy integration tests because to fix things you have to rewrite whole portions of the system.
I've been there and it sucks. The choice seems to lie between rewriting the whole system on the same platform to be testable one chunk at a time, or to rewrite the system in something that lends itself better to testing.
In either case, the answer is to take the time to learn how to write testable code. To start learning techniques like Dependency Injection. To practice writing portions of your system using TDD to see what works and what doesn't.
3. Maintaining Tests Sucks - Actually, if you don't want to maintain a test suite, don't write one.
At its core, your tests are a specification of how your system should work at a given time. When they start breaking it means your system has likely changed, so either it should be fixed to match the specification, or the specification should be changed to match the appropriate system behavior.
At a fundamental level, tests aren't something you write once, they are something you constantly rewrite to keep them in line with what your system should be doing. Thus, when they are broken, you know that either your specs need to change or something in the code isn't working right.
Test maintenance is a price you pay for wanting higher quality software. It's the same kind of cost you pay in designing a building with blueprints. If people build a building without following the blueprints, it's not going to be the building that was supposed to be built. Tests are a living blueprint of your system. If you aren't willing to treat it that way, TDD isn't going to help you.
TDD isn't for everyone because not everyone is willing to make those kind of investments in code quality and maintainability. Also, TDD doesn't make your code better if you aren't willing to let it make your code better.
- __david__ 14y ago> TDD isn't for everyone because not everyone is willing to make those kind of investments in code quality and maintainability. One thing I've noticed is that code written to be testable tends to suffer from over-abstraction. Sadly, writing nice, compact, easy to read code is somewhat at odds with TDD in my experience. I personally don't like that I have to make sacrifices to code simplicity just to make it testable. But perhaps I just suck at TDD. :-)
- programminggeek 14y agoI totally understand what you mean. I've gone to great lengths to determine what kind of architecture is needed to truly support TDD and what I've come to realize is that it's not so much about over-abstraction that is the problem, it's that testable code is pluggable, which is mostly at odds with how systems are designed. For example, standard MVC apps tend to tie models to an ORM in some way shape or form. Think Rails and ActiveRecord and you'll understand what I mean. This makes writing a simple crud app fast, but testing it sucks because you have 2 things tied together - your actual data models and your database layer. Funny that nobody would ever do that with the filesystem, but it's super common with the database. To make your models clean and easy to test, you need to pull out the ORM bit into something more pluggable. The same principle applies to writing testable biz logic. A lot of times people don't know where to put it so it ends up in the View, Controller, or Model. All of which are the wrong place usually. Testing that code becomes not awesome because you then have to write a test against what the view outputs, the controller does, or possibly what the model is doing (usually by touching the database). The answer I've found is to pull your business logic into a separate container that can be tested easily apart from any MVC structure. None of this means you need to over-abstract anything. It just means you have to figure out the right abstractions and structure for the right layers. None of this is by any means obvious at first. P.S. I'm working on an architecture framework that simplifies a lot of this to make doing TDD much easier.
- mpweiher 14y agoOdd, my experience is exactly the opposite: code that is written using TDD tends to be extremely concrete, because it does only as much as is needed to pass the test, no more. If you are making code overly abstract, that does suggest you may be overthinking your TDD approach.