Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.
  • I'm talking about unit tests in the TDD sense. (Not automated "integration", or what you like to call it tests.)
  • Legacy code as in: (C++) code without tests. (see: Michael Feathers' Working Effectively with Legacy Code)
  • But also legacy code as in: Code that our team has been working with for the last 10-5 years, so we very often have quite a good idea of where to put things to change something.
  • We do have unit tests in place (via Boost.Test) for some modules that came later or have been a "natural" fit for unit tests (common app specific containers, string-stuff, network helpers, etc.)
  • We do not yet have proper automated acceptance tests.

Now, recently I had the "pleasure" to implement 3 new user-facing features.

Each of those took me about 1-2 hours of getting up to speed with the code parts I needed to change, 1-2h hours to implement the (little) code I needed to change and another 1-2 hours to make sure the app ran correctly afterwards and did was it was supposed to do.

Now, I really added little code. (I think one method and a few call lines for each feature.)

Factoring out this code (via any of the methods suggested in WEwLC), so that a unit test would've make sense (and not been a complete tautology) would have easily taken another 2-4 hours, if not more. This would have added 50%-100% time to each feature, with no immediate benefit, as

  1. I did not need the unit test to understand anything about the code
  2. Manual testing is the same amount of work, as I still need to test if the code is correctly integrated into the rest of the app.

Granted, if, later on, "someone" came along and touched that code, he theoretically could have some benefit from that unit test. (Only theoretically, as that tested island of code would live in a ocean of untested code.)

So, "this time" I chose to not do the hard work of adding a unit test: The code changes to get that stuff under test would have been significantly more complex than the code changes to get the feature correctly (and cleanly) implemented.

Is this something typical for strongly coupled legacy code? Am I lazy / do we set the wrong priorities as a team? Or am I prudent, only testing stuff where the overhead isn't too high?

share|improve this question
    
what if some other department will take over your "well known legacy code"? What the guys there will do with it? –  Alex Theodoridis Nov 23 '13 at 12:18
add comment

6 Answers

up vote 14 down vote accepted

You have to be pragmatic about these situations. Everything has to have a business value, but the business has to trust you to judge what the value of technical work is. Yes, there is always a benefit to having unit tests, but is that benefit great enough to justify the time spent?

I would argue always on new code but, on legacy code, you have to make a judgement call.

Are you in this area of code often? Then there's a case for continual improvement. Are you making a significant change? Then there's a case that it is already new code. But if you're making a one-line code in a complex area that will probably not be touched again for a year, of course the cost (not to mention risk) of reengineering is too great. Just slap your one line of code in there and go take a shower quick.

Rule of thumb: Always think to yourself, "Do I believe that the business benefits more from this technical work that I feel I should do than the job they asked for which is going to be delayed as a result?"

share|improve this answer
    
What is a good piece of code? One that is well designed, tested, documented, and future proof or one that you get paid for? As always: you can have it good; you can have it cheap; you can have it fast. Pick any two, the third one is your cost. –  Sardathrion Oct 24 '11 at 10:19
2  
"I would argue always on new code" ... "new code" in a legacy codebase or "new new code"? :-) –  Martin Ba Oct 24 '11 at 10:25
    
pdr has the right idea. It's an engineering decision (one with tradeoffs). Generally if you have a big piece of vetted code it is a good idea to leave it alone. I've seen a TDD effort on legacy code (only a year, but that's enough) end up costing months and only ended up spending money and breaking a legacy app for months until the TDD refactor-introduced bugs were fixed. If the code/feature is done and tested, don't go breaking it to add instrumentation (TDD) to tell you something you already knew anyway (that it works). –  anon Oct 24 '11 at 16:31
add comment

The gain of unit tests in TDD sense is to get something that stands by itself, without needing oral tradition built over years by a stable team.

It is a big luck that the same team has been on the same project for so many time. But this will eventually change. People get sick, bored or promoted. They move, retire or die. New ones come with new ideas and the urge to refactor everything the way they learned at school. Companies get sold and bought. Management policies change.

If you want that your project survive, you have to prepare it for changes.

share|improve this answer
add comment

Writing unit tests is future proofing your code. If the code base does not have tests, then you should add new tests for all new features because it makes that bit of the code just that little more robust.

I find that adding tests, even in legacy code, is beneficial in the medium to long run. If your company does not care about the medium to long term, I would look for another company. In additions, I do not think that it takes longer to test manually than it take to write a set unit test. If it does, then you need to practice code kata focused on writing tests.

share|improve this answer
1  
But, but, but! :-) That little should translates to a 100% increase in time needed to implement a new feature. It does not decrease the time needed to implement subsequent features. It may decrease time needed when changing stuff. –  Martin Ba Oct 24 '11 at 9:25
3  
You are making sure that changes in that area of the code do not introduce new bugs, that new (less experienced users) can get a clear understanding of the code, and that side effects affecting that area are cough at testing time instead of at release time. Testing help verify that code does what it should do not make it easier to add features later. I find that adding tests, even in legacy code, is beneficial in the medium to long run. If your company does not care about the medium to long term, I would look for another company. –  Sardathrion Oct 24 '11 at 9:32
1  
@Martin because clearly what you do is code what you think the feature should be, and then ship it. No testing is done at all at any stage... no, wait. As developers, we all test our code (at least by hand) before saying it's done. Replacing "by hand" with "by writing an automated test" is not a 100% increase in time. Frequently, I find it's about the same time taken. –  Kaz Dragon Oct 24 '11 at 10:14
1  
@Kaz - "Replacing "by hand" with "by writing an automated test" is not a 100% increase in time. Frequently, I find it's about the same time taken." - YMMV, but for my codebase, this is clearly wrong (as laid out in the question). –  Martin Ba Oct 24 '11 at 10:23
1  
@Kaz: What I :-) meant was: A unit test tests my code in isolation. If I do not write a unit test I don't test the code in isolation, but only if the code is called correctly and produces the desired result in the app. This two points (called-correctly and app-does-what-it-should) I have to test anyway (manually) and are not covered by a unit test. And the unit test wouldn't cover these two points but would "just" test my function in isolation. (And this unit-test-testing would be additional and wouldn't be offset by anything as far as I can see.) –  Martin Ba Oct 25 '11 at 10:23
show 1 more comment

Certainly best practices dictate you should unit test any code you change. Real world coding however involves a lot of compromises, time and materials are finite.

What you need to do is evaluate the cost in real terms of fixing bugs and making modifications without unit tests. You then can asses against the investment in creating those tests. Unit tests greatly reduce the cost of future work but come at a price now.

Bottom line is if your system is rarely changed then it may not be worth writing unit tests but if it is subject to regular changes then it will be worth it.

share|improve this answer
add comment

All of these little rational decisions to not create tests are building up a crippling technical debt that will come back to haunt you when somebody leaves & a new hire has to come in & get up to speed.

Yes, it might have cost another 2-3 hours to write the unit tests but if the code gets sent back from testing you'll have to manually test everything again, and document your testing, again - you do that don't you? Otherwise how does anyone know what you tested and what values you used?

Unit tests document the expected behaviour of the code the test data used to check the functionality and gives new coders reasonable confidence that they haven't broken something when making changes.

It costs a couple of hours today more than manual testing but then you are testing every time you do any change saving hours over the life of the code.

However, if you know that the code will be retired in a couple of years all I've said changes because you won't finish putting tests in the code & it'll never pay back.

share|improve this answer
    
"and document your testing, again - you do that don't you?" - {putting cynical hat on:} Of course not. We are not in developer fairy land. Stuff gets implemented and tested and shipped. Later on it gets broken and fixed and tested and shipped. –  Martin Ba Oct 24 '11 at 10:17
    
I would hope that everything gets manually tested regardless of the number of unit tests. Automated acceptance tests are another matter entirely. But then acceptance tests are not made more difficult by the codebase being legacy, so are out of scope here. –  pdr Oct 24 '11 at 10:19
1  
mcottle - You are missing a vital point. The unit testing will not decrease the time taken to do "manual functionality testing" of the finished feature. I still have to click-through all the dialogs involved with a prudent subset of possible inputs to make sure the actual finished app as built does what it's supposed to do. (I grant that theoretically unit testing may help to limit this manual test cycle to only one loop if the unit tests make sure that I won't find any obvious problem only during manual testing.) –  Martin Ba Oct 24 '11 at 10:22
add comment

The value of unit tests does not only lie in testing a new feature when that is developed. The benefit of unit tests is gained mostly in the future.

Yes, you may have to spend what seems like an inordinate amount of time to make your legacy code testable.

But if you don't, you will, or certainly should, spend many, many, many more hours testing the feature. Not just on its initial development, but with every new version of your software. Without unit tests you, and other forms of automated testing, you do not have any other option but to spend many hours of manual testing to ensure that your feature was not inadvertently broken, even when that feature itself was not changed.

share|improve this answer
    
"Without unit tests you do not have any other means to ensure that your feature was not inadvertently broken, even when that feature itself was not changed." -- Unit tests won't help. To make really sure, I'd have to have automated integration / acceptance tests. –  Martin Ba Oct 24 '11 at 10:33
    
Yes, unit tests are only the first step. Edited answer to clarify –  Marjan Venema Oct 24 '11 at 10:49
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.