Slashdot Mirror


Working Effectively with Legacy Code

Merlin42 writes "I recently took a Test-Driven-Development (TDD) training course and the teacher recommended that I read "Working Effectively with Legacy Code" by Michael Feathers. First things first, a note about the title. Feathers defines "Legacy Code" a bit different than you may expect, especially if you are not into the XP/Agile/TDD world. I have heard (and used) a number of definitions for "legacy code" over the years. Most of these definitions have to do with code that is old, inherited, difficult to maintain, or interfaces with other 'legacy' hardware/software. Feathers' definition is 'code without tests.' For those not into TDD this may seem odd, but in the TDD world, tests are what make code easy to maintain. When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything." Read on for the rest of Kevin's review. Working Effectively with Legacy Code author Michael Feathers pages 456 publisher Prentice Hall rating 9/10 reviewer Kevin Fitch ISBN 978-0-13-117705-5 summary Excelent overview of how to apply TDD to an existing project Overall this is definitely an interesting read, and useful to anyone who has ever yelled "FSCKing LEGACY code!" It will be most useful to someone who already has some appreciation for TDD and wants to use it to 'pay down the technical debt' in a legacy code project. In my opinion adding unit tests (a sort of retroactive TDD) is the best ... err ... most effective approach for getting a legacy code project into a more malleable state.

One caveat is that most of the book is focused on working with object oriented programming languages. There is some coverage of techniques for procedural languages (mainly C), but this is not the main focus of the book. In a way this is unfortunate, since there is a lot of really useful C code out there gathering dust. But in the book he states that "the number of things you can do to introduce unit tests in procedural languages is pretty small." Unfortunately I would have to agree with him on this point.

One of the greatest things about this book is that it is written by someone who has worked with a lot of legacy code, and there are numerous real world anecdotes sprinkled throughout the text that really serve to help drive the points home. The code examples are plentiful, but not verbose. They all look like real code you might find lurking in a dark corner at work, not some fanciful made up snippet.

The high level goal of the book is show you how to write good unit tests for code that wasn't designed with unit tests in mind. The first step for writing unit tests is getting individual classes or functions into a test harness where you can apply known inputs, and check the outputs or behavior. To do this you need to break dependencies in the original code. The bulk of the book is dedicated to looking at different approaches to breaking dependencies.

Much of the book is organized like a FAQ. There are chapter titles like: "I Need to Make a Change. What Methods Should I Test?" and "My Project Is Not Object Oriented. How Do I Make Safe Changes?". This organization makes the book work a bit better as reference than as learning material. After the first few chapters there is very little flow to the book. Each chapter tends to stand as an independent look into a particular problem common in legacy code. As a result, you can read the table of contents and usually skip to a self-contained chapter that will help with the problem at hand.

The final chapter of the book is a listing of all the refactoring techniques used throughout the rest of book. So if you have a particular dependency-breaking technique in mind, you can skip straight to the description of the technique you want to use. This can be quite helpful when you need to perform a refactoring before you can get your code into a test harness. The descriptions are straightforward and provide a little checklist at the end that will help you make sure you didn't miss anything.

In conclusion I would definitely recommend this book to a colleague who is trying to introduce unit tests into code that was not designed with testing in mind. In fact I have already lent the book to several people at work, most of whom have bought their own copy.

You can purchase Working Effectively with Legacy Code from amazon.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.

208 comments

  1. Not needed by eln · · Score: 5, Funny

    This book is a waste of paper. Everyone knows the proper way to deal with legacy code:

    1.) Spend 2 weeks looking at code you don't understand.
    2.) Loudly complain about the poor quality of the code, particularly algorithms that you don't understand.
    3.) Make derogatory comments about the previous developers. Be sure to paint them as monosyllabic imbeciles who probably got dropped on their heads multiple times as children.
    4.) Make minor changes to the code. If they blow up in your face, blame the previous developers for their poor grasp of basic programming practices. Make references to the previous programmers' relationship with their mothers.
    5.) Delete the whole thing and start from scratch.
    6.) 18 months of fumbling around later, realize that the previous code may have been better than you gave it credit for.
    7.) Deny this.
    8.) Release cobbled-together mess that lacks half the features of the previous codebase and features twice the bugs.
    9.) Get job elsewhere.
    10.) Company hires new programmer who starts the process over at step 1.

    1. Re:Not needed by jellomizer · · Score: 4, Insightful

      You work at GE right?

      --
      If something is so important that you feel the need to post it on the internet... It probably isn't that important.
    2. Re:Not needed by JazzyMusicMan · · Score: 1

      If I had points, I'd mod you up, thats exactly how I've seen it.

    3. Re:Not needed by Fizzl · · Score: 2, Funny

      Now that the statute of limitations has run its course, I can safely admit that this sounds really much like my first "professional" project. Too much responsibility for the inexperienced.

    4. Re:Not needed by jellomizer · · Score: 4, Insightful

      I have goten you sarcasm, however I feel some people may miss it, so I will comment on these ideas as if you were serious, as this is actually more like real life then most people want to admit.

      1. Trying to analysise the code is a lot of extra work not needed as you can take it for granted that it works correcly and you just need to focus on what doesn't. For most apps a quick search for the button or menu item that is causing the problem will allow you to trace you way to the module and the area that needs to be fixed.

      2., 3. and part of 4. Remember people are people. I bet you even write some bad code from time to time. Either you are really tired, under a deadline, or had to work around an other bug that may have been long since fixed, or make the code so optimized that it is unmaintainable. We all do it, most of us won't admit it. So remember that when you are about to critize someones elses code. As well you need to reference the code quality to the time it was made. Look at code in the 1980's it was usually written by people with out Computer Science Degrees, so there will be Goto and the like.

      4. Making minor changes when possible is a good method. However if it blows up then you will need to make a larger change... For legacy apps your job isn't as much fixing a bug, but the user of the application has a different process that you need to adjust the computer to account for. The process may have worked for 20 years, and it worked. But it changed sometimes you can get away with a little tweak but sometimes it requires more.

      5., 6. Starting from scratch could kill the company. Or be way to expensive. It has been working for 20 years and just needs some minor tweaks, yes maintaining it takes a bit more work then before but it could cost millions (not just programming time, but change management, training, research, bug fixes, missed area....) vs. Paying some guys $100k a year (taking decades to recover the cost of the inital effort)

      7. If you admit to the failure you may be able to get the legacy back and running, you may still have a job, although you may get some angry bosses for a while. However you made a mistake it is better to admit it then go down the path of distruction.

      8. If you did go threw the full rewrite process you should have put more effors in specing it out, and giving a clearer quote. And accounted for bugs to be fixed.

      9. If you messed up to much, sometimes getting a new job is not that easy. Your reputation can spread.

      10. Managers should have learned from the mistake and not allowed the new developer to do the same things.
       

      --
      If something is so important that you feel the need to post it on the internet... It probably isn't that important.
    5. Re:Not needed by Greyfox · · Score: 4, Insightful

      Good management usually reacts to calls to rewrite with skepticism. Usually (but not always) this is a good thing.

      --

      I'm trying to teach myself to set people on fire with my mind... Is it hot in here?

    6. Re:Not needed by The+Redster! · · Score: 1

      2a.) Bonus soapbox points for every section with comments like "????" or "I think this works."

    7. Re:Not needed by Anonymous Coward · · Score: 0

      11. Inform company that you'll be working from home
      12 Hire programer from third world country, at one tenth your salary, to do the work.
      13. go on vacation.
      14. ???
      15. Profit!

    8. Re:Not needed by hairyfeet · · Score: 1

      Wow,must be nice working in some big place where all that applies. Try walking into a SMB to do what you think is a simple hardware upgrade and maybe streamline the network a little and have them go "OMG! Thank God you're here! Our mission critical app is dying and we have all our inventories and payroll tied to it!" and it turns out to be some God awful POS VB3 app written by some guy named Chuck that worked there ages ago on a wheezing and ready to croak any second old NT box.

      Of course Chuck never bothered to set up any kind of backup plan and apparently never heard of commenting code and he REALLY liked GOTOs and his code looks like it was written be a drunk in a bad mood. While I have nothing against VB,in fact I think it makes a perfect tool for SMBs if the code is actually well written,trying to figure out the mess that old dumbass Chuck wrote is about as fun as getting hit repeatedly in the head with a sledgehammer. That to me is the real headache of legacy code. When you find some ancient POS program that a company has become way too dependent on that was written as a stopgap by some sloppy coder ages ago. But hopefully you guys don't run into that problem as often,right?

      --
      ACs don't waste your time replying, your posts are never seen by me.
    9. Re:Not needed by zifn4b · · Score: 1

      5., 6. Starting from scratch could kill the company. Or be way to expensive. It has been working for 20 years and just needs some minor tweaks, yes maintaining it takes a bit more work then before but it could cost millions (not just programming time, but change management, training, research, bug fixes, missed area....) vs. Paying some guys $100k a year (taking decades to recover the cost of the inital effort)

      So... they would pay me $100k/year to spend several years working on a new, interesting project. I don't have to work with someone else's crappy code. I can get experience as an architect and add credentials to my resume. I get to potentially have a lot of job security for being the only one that knows how the new system works. If the company goes under, I can use the experience to find an even better job and just blame the company's demise on its bad business model.

      I'm really not seeing a problem here. ;)

      All tongue and cheek humor aside. The problem here is that what's best for the business's bottom line is quite frequently not what makes developers (or any other employee for that matter) content. If the employees can go work somewhere else that allows them to have creative freedom and be more intellectually stimulated they will. As a result, businesses have to balance these two things because if they can't retain employees, they can't do business and likewise, if they cater to all the demands of their employees, they probably can't do business either.

      --
      We'll make great pets
    10. Re:Not needed by harry666t · · Score: 1

      11.) ???
      12.) Cthulhu

    11. Re:Not needed by dcollins · · Score: 2, Funny

      "Look at code in the 1980's it was usually written by people with out Computer Science Degrees, so there will be Goto and the like."

      Look at my code from yesterday, it was written by a person without a Computer Science degree. There was a Goto and the like.

      --
      We know where leadership by an anti-intellectual "strongman" who scapegoats minorities and likes boisterous rallies goes
    12. Re:Not needed by Anonymous Coward · · Score: 0

      "1. Trying to analysise the code is a lot of extra work not needed as you can take it for granted that it works correcly and you just need to focus on what doesn't. For most apps a quick search for the button or menu item that is causing the problem will allow you to trace you way to the module and the area that needs to be fixed."

      That's all fine and dandy when it's already modular. There are times though when you really need to understand what it does and rewrite it from scratch. Example? I'm rewriting a Perl web app that's been developed over 10 years that has HTML and JavaScript fragments embedded within print statements within the code, along with hard coded "font" tags (yes, it's that old).

      There is no easy option to just write tests and get it moved over to an MVC framework.

      So, I'm *having* to understand the code so I can document the features and then rewrite the features cleanly.

      On the brighter side, it adds a level of job security over the next year or so :)

    13. Re:Not needed by Fujisawa+Sensei · · Score: 1

      11. Inform company that you'll be working from home

      12 Hire programer from third world country, at one tenth your salary, to do the work.

      13. Profit!

      14. find another job.

      15. GOTO 11

      There I fixed it for you.

      --
      If someone is passing you on the right, you are an asshole for driving in the wrong lane.
    14. Re:Not needed by DigitAl56K · · Score: 1

      Goto's aren't always bad.

    15. Re:Not needed by stephentyrone · · Score: 1

      Probably 10% of the ugliest code I read is mangled *precisely because* someone went out of their way to avoid using a goto when it really was the appropriate control structure. They couldn't even tell you why they did it, just that they heard somewhere to avoid goto. They probably think that it's a performance hazard or something.

    16. Re:Not needed by mrjb · · Score: 1

      Goto's aren't always bad. Of course they aren't. But beware the velociraptors.

      --
      Visit http://ringbreak.dnd.utwente.nl/~mrjb/growingbettersoftware to download your free copy of the book
    17. Re:Not needed by Anonymous Coward · · Score: 0

      Years ago I told a boss of mine to write code without a GOTO once. I'd used a GOTO because "it really was the appropriate control structure." Boss didn't like it. I told him to see if he could write it in a straightforward way without the GOTO statement. He tried then came back later and said "I finally managed to write it without the GOTO but it was an ungainly mess." In the end the GOTO got committed to the code repository.

    18. Re:Not needed by NotBorg · · Score: 1

      Velociraptors are extinct much like the languages which had no other means but to use goto's.

      BASIC was the largest offender. Everyone had it and did it back then. For many it was their first language. Being limited to goto's and no formatting other than line numbers, its no wonder these programmers had a rough start with some of the more refined languages.

      BASIC was bad not because it used goto's, but because it did so rather exclusively. But nobody uses BASIC (in classic form) anymore. So the need for such disdain for goto's isn't necessary anymore because it is no longer such a defining bad influence which everyone starts with.

      The velociraptors are dead.

      --
      I want this account deleted.
    19. Re:Not needed by lwriemen · · Score: 1

      Good management would have had a plan in place for maintaining the code to avoid having to throw a new person at it and expect them to be fungible.

    20. Re:Not needed by witte · · Score: 1

      Good management

      I keep those stored next to the flying pigs.

    21. Re:Not needed by Greyfox · · Score: 1
      Well that's true. The best projects I've worked on have already had a team in place who were familiar with the code base. Plus those code bases were usually extremely well commented. I know, shocking right? The projects where one guy was maintaining a complex code base and then he leaves for another company... that's usually a warning sign.

      And yeah, the ones with teams are much more likely to ask you to justify rewriting any portion of the code that you want to rewrite. And since the team knows the code base, they can also tell if your reasoning is sound or not.

      It still boggles my mind that the other companies would leave the operation of vital portions of their business to one guy who may or may not be on crack.

      --

      I'm trying to teach myself to set people on fire with my mind... Is it hot in here?

    22. Re:Not needed by Zwicky · · Score: 1

      Yes they are. goto hell.

      (Hint: I'm just kidding!)

      --
      "Three eyes are better than one" -- Lieutenant Columbo
  2. Whatever by Anonymous Coward · · Score: 3, Informative

    Buy Martin Fowler's Refactoring instead.

    1. Re:Whatever by CharlieG · · Score: 2, Insightful

      No - buy BOTH books, they really do compliment each other

      --
      -- 73 de KG2V For the Children - RKBA! "You are what you do when it counts" - the Masso
    2. Re:Whatever by regeb · · Score: 2, Insightful

      Buy Martin Fowler's Refactoring instead.

      Remember that in Feathers' book "legacy" means not to have unit tests.

      Refactoring starts with the assumption that unit tests are in place. The challenge with legacy code is that very often its current structure makes it impossible to write unit test for it. This book is about techniques of safely transforming untestable code to a form that is testable.

      Only after that come actual unit tests, and after that refactoring.

      All in all, the two books are complimentary.

    3. Re:Whatever by Ciarang · · Score: 1

      Surely it would be impossible for the one written first to have foreseen the latter and incorporated praise for it. Or did you mean complement?

    4. Re:Whatever by CharlieG · · Score: 1

      Yes -

      Eats, shoots, and leaves

      --
      -- 73 de KG2V For the Children - RKBA! "You are what you do when it counts" - the Masso
    5. Re:Whatever by Anonymous Coward · · Score: 0

      No - buy BOTH books, they really do compliment each other

      Really? Those must be scary books. I didn't realize we had already reached the Singularity.

    6. Re:Whatever by Anonymous Coward · · Score: 0

      Buy Martin Fowler's Refactoring as well.

    7. Re:Whatever by Anonymous Coward · · Score: 0

      'ave iiit!

  3. Not Object Oriented. How Do I Make Safe Changes? by DJ+Jones · · Score: 2, Informative

    Put all your changes in "int main()", use obscure variable names like xspatyc05 or funct123, always use static buffer sizes for any IO operations and under no circumstances should you add comments, it's a waste of time and no one besides you is ever going to have to understand it anyway.

    - I <3 Legacy code

  4. Not exactly... by Kindaian · · Score: 5, Insightful

    The simple passing of all tests doesn't necessarily means that you didn't broke anything.

    It means only that you passed the tests.

    If the tests don't provide coverage for ALL the business issues that the piece of software is supposed to solve, then you pass the tests, but will have no clue if you broke or not things apart.

    Best approach is to evaluate current test procedures and check if they provide enough coverage for at least all user related actions and all the automated actions.

    Only after you know that your testing procedures are sound, you can have that assurance... ;)

    1. Re:Not exactly... by Anonymous Coward · · Score: 1, Funny

      A tenet of TDD is that the basis path coverage if the unit tests is complete.

      Was that intended to be a sentence? In English?

      A tenant of programming is to write code that doesn't have any bugs - sometimes it even happens - about as often as the test cases cover all the possible cases.

    2. Re:Not exactly... by Anonymous Coward · · Score: 1, Informative

      A tenant is someone who pays rent.

      A tenet is a principle or belief on which a piece of doctrine is based.

    3. Re:Not exactly... by Surt · · Score: 1

      Ok, maybe you were joking, but tenet was not the part of his post that was wrong/confusing, but it was wrong/confusing in yours:

      http://www.merriam-webster.com/dictionary/tenet
      http://www.merriam-webster.com/dictionary/tenant

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    4. Re:Not exactly... by kramer2718 · · Score: 1

      The simple passing of all tests doesn't necessarily means that you didn't broke anything.

      It means only that you passed the tests.

      If the tests don't provide coverage for ALL the business issues that the piece of software is supposed to solve, then you pass the tests, but will have no clue if you broke or not things apart.

      Here here.

      Test should also be developed at various levels of implementation. Both unit tests and integration tests are necessary.

      I've worked with code that was fairly well covered by integration test, but which had little to know unit tests (due to the various modules being overly tightly coupled. It's very very difficult to reproduce issues in that case.

      At the same time, I also feel that the term legacy should probably be used a bit more literally.

    5. Re:Not exactly... by stephentyrone · · Score: 1

      Your first "sentence" makes no sense. That point aside, you seem to be saying that TDD will test every possible usage of a program, thereby guaranteeing that bugs will be found. This may be possible for very, very limited toy examples, but is impossible for any real world code. You can't even test all possible input pairs to a single-precision floating-point divide in a reasonable time period for a development cycle -- how will you completely test code that does anything interesting?

      Of course, it could be that I'm just misinterpreting the (horribly mangled, non-sensical) sentence you wrote.

    6. Re:Not exactly... by plover · · Score: 2, Informative

      If the tests don't provide coverage for ALL the business issues that the piece of software is supposed to solve, then you pass the tests, but will have no clue if you broke or not things apart.

      That's not true at all. You have a lot of clues based on the tests that passed. You'll have confidence in the code that passed the tests. Overall, it's less to worry about. It's certainly of more benefit than no tests. And if you failed tests, you'll have 100% confidence that you broke something, and you can get it fixed.

      Consider the end goal of unit tests would be 100% assurance that all code paths are covered, and that all behavior is tested. Not that it's realistic in many places, but that is the goal.

      Now consider "Legacy Code" as defined by Michael Feathers -- code that does not have unit tests. You have no idea if a single line of it works, other than what your integration or end-user testing shows.

      His book is a set of procedures you can try to insert tests into untested or hard-to-test code. His strategy is fairly simple: jam a test into the middle of the code. Chop something in half, place tests on either side of the wound, and see if it still works. Now you have a big ugly gash separating two halves of the code, but you have less code to execute when running the tests on each half. Now, using that line as a starting point, begin refactoring the code, and adding unit tests to prove your refactorings are safe. Sure, you'll still need end user testing and integration testing, but your developers can move forward faster, and you're more confident that your new changes will improve the code, rather than break stuff.

      He's trying to help solve a hard problem: how do you refactor (which is inherently a test-driven-development strategy for improving your code) without tests that help ensure you didn't break anything? Once you've got tests, refactoring becomes easier. The more tests you have, the more assurance you have that your changes aren't breaking code. Ultimately, when you are 100% covered, you should be a lot closer to bug-free than you were when you started.

      I'll tell you right now that on a large legacy project, most people couldn't tell you where to begin placing tests. Michael's book helps jump start the process. And while the end game might not be 100% test coverage of all the legacy code, it leaves you a lot better off than you were before you started writing the tests.

      --
      John
    7. Re:Not exactly... by smellotron · · Score: 2, Insightful

      Many systems have moving parts that are very difficult (if not impossible) to handle from a unit-testing perspective. This is particularly true for distributed systems or even multithreaded applications, where you need execution coverage, data coverage, and all combinations of all possible race conditions.

      Unit testing can give you a lot of confidence for individual isolated software components, but it was never intended to address the "system as a whole".

    8. Re:Not exactly... by k.a.f. · · Score: 1

      The simple passing of all tests doesn't necessarily means that you didn't broke anything.

      It means only that you passed the tests.

      If the tests don't provide coverage for ALL the business issues that the piece of software is supposed to solve, then you pass the tests, but will have no clue if you broke or not things apart.

      Of course it doesn't prove that, but remember that this is fundamentally impossible to prove anyway. Testing can demonstrate the presence of errors, but not their absence. (E.W. Dijkstra) Your tests can never be "enough" in that sense. But a code change that re-satisfies the existing test suite is at least much more likely not to break the system than one which doesn't.

    9. Re:Not exactly... by Count+Fenring · · Score: 1

      At the same time, I also feel that the term legacy should probably be used a bit more literally.

      Here, here.

      Unit testing is a good thing. That doesn't mean that code without it is automatically legacy. I mean, does that mean that the instant the first object-oriented system showed up, all of the procedural code currently being written was suddenly legacy? Does it mean that the Linux Kernel is legacy, now? No. Because legacy already HAS a definition in this context.

      It's bad enough having seventeen things with 'Java' somewhere in the name*. Do we have to make things more confusing by trying to map one name over two entirely separate concepts?

      * Hyperbole intentional. Java/Javascript doesn't actually confuse me or most people for more than 5 minutes. But still. C'mon...

    10. Re:Not exactly... by gatkinso · · Score: 1

      Hard, but not impossible.

      --
      I am very small, utmostly microscopic.
  5. testing is a waste of time by larry+bagina · · Score: 0, Troll

    testing is a waste of time and only means you satisfy the test conditions. You're better off just proving your code correct.

    --
    Do you even lift?

    These aren't the 'roids you're looking for.

    1. Re:testing is a waste of time by Anonymous Coward · · Score: 1, Insightful

      Test driven design works if the tests are complete. Though I will admit I have rarely seen a complete set of tests; and you still need to some old fashion testing (integration testing, real world monkey testing, etc...).

      Honestly I think if you're working with "legacy" code, most companies will view the time needed to get add tests as a waste of time.

      TDD seems to work better with new projects where you can plan for the testing framework.

    2. Re:testing is a waste of time by Anonymous Coward · · Score: 0

      Um, isn't that what testing does (proves your code is correct)?

    3. Re:testing is a waste of time by Jellybob · · Score: 1

      I'm currently in process of writing a test harness for some old C code at work, with precisely that aim, so that I can then go on and make changes without worrying that I broke everything else.

      Testing doesn't *have* to be on a method by method basis, and sometimes that just doesn't work. In this case it's a program that takes some input, and compares the program's output to what it should be producing.

      It's not the most elegant solution ever, and it certainly doesn't test every little corner of the code, but it does prove that the output is correct.

    4. Re:testing is a waste of time by Surt · · Score: 2, Informative

      No, testing verifies that your code works under certain conditions. A proof that your code is correct demonstrates that your code works under all conditions in a mathematically rigorous way.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    5. Re:testing is a waste of time by CrazedSanity · · Score: 1

      Building tests for your code proves the code "is correct" (read: "works properly") and bug-free to the extent the testing covers. When new bugs are discovered, tests can be added/modified to check for that, proving your code is still good.

      The process of "proving your code is correct," to me, involves lots of face-to-face see-I-told-ya-so's, and displaying how it works. Tests allow you to say with authority, "I wrote 4,322 tests to make sure the system works the way it's supposed to. If you got an error message without the system crashing, you did something wrong."

      --
      Sanity is like a condom: rather have it and not need it, than need it and not have it.
    6. Re:testing is a waste of time by HuguesT · · Score: 2, Funny

      No. Remember Knuth's aphorism :

      Beware of bugs in the above code; I have only proved it correct, not tried it.

    7. Re:testing is a waste of time by Ragzouken · · Score: 2, Insightful

      Testing can prove your code incorrect, which you can react to, but it won't prove your code correct.

    8. Re:testing is a waste of time by antifoidulus · · Score: 2, Insightful

      Huh? Despite the fact that proving code correct can be a major burden itself, the long and short of it is that outside of a few niches, most programs have to interface heavily with various hardware vendors, OS's, APIs etc. For example, a lot of our code at work runs on Linux and thus is dependent on Linux behaving a certain way. So go ahead, prove the correctness of Linux first, then maybe we can prove the correctness of our code.

    9. Re:testing is a waste of time by Anonymous Coward · · Score: 0

      Maybe not the crap you write. Tests ensures the correctness of your software. "Correctness" being what you are trying to prove (e.g., requirements testing).

    10. Re:testing is a waste of time by phoenix321 · · Score: 2, Funny

      So you solved the Halting Problem, eh?

    11. Re:testing is a waste of time by Anonymous Coward · · Score: 0

      Remind me never to hire you.

    12. Re:testing is a waste of time by Surt · · Score: 1

      Because I know the difference and can make an informed decision about which to use? I've only once employed a proof of correctness, I use testing every day. The time we needed a proof there were hundreds of billions of dollars at stake.

      You use the right tool for the job.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    13. Re:testing is a waste of time by Surt · · Score: 3, Informative

      Either you misunderstood my post, or you have a fundamental misunderstanding of the halting problem.

      It says that no algorithm can decide in general whether or not a given program / input pair will halt or not. The emphasis on the in general is the key.

      It is actually trivial to do in many, many specific cases.

      http://en.wikipedia.org/wiki/Halting_problem

      In particular, take note of the second sentence:

      Alan Turing proved in 1936 that a general algorithm to solve the halting problem for all possible program-input pairs cannot exist.

      (emphasis mine)

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    14. Re:testing is a waste of time by Mr.+Slippery · · Score: 1

      You're better off just proving your code correct.

      Why would you trust the proof any more than the code? People make mistakes in proofs just like they make mistakes in coding.

      --
      Tom Swiss | the infamous tms | my blog
      You cannot wash away blood with blood
    15. Re:testing is a waste of time by IamTheRealMike · · Score: 1

      Yeah, great. Only if you define "correctness" with some useless definition the customer doesn't care about.

      Here's a trivial problem that I came across at work a few weeks ago. The codebase has a library of string functions, one of them has a contract like "search string A for substring B within N characters". The original implementation did not stop at a null terminator. At some point the function was changed so it would stop at a null. This broke some piece of code that used that function somewhere else.

      That function was unit tested. The change still broke things because:

      • The change which modified the semantics of the function also changed the unit test to reflect the new "correct" behavior.
      • The code which relied on the function was also unit tested, but the unit tests didn't test the particular edge case that would fail when this basic function did something different. Nonetheless it would occasionally occur in production.

      Result - fail. Arguably if the reliant code had been better unit tested, eventually somebody would have noticed the problem. However, that's rather like saying "if only nobody wrote bugs, software would be much better". Actually testing every possible unusual boundary condition in your code is very hard. Code coverage metrics can't find all the corners.

    16. Re:testing is a waste of time by JesseMcDonald · · Score: 1

      Only if your testing involves every possible combination of inputs, which is impractical for any non-trivial program. Otherwise you have some evidence that your program works -- a lack of observed bugs in likely locations -- but you haven't proved that the program correctly implements all its requirements under all circumstances.

      All of this assumes that the tests themselves are correctly implemented with respect to the program's written requirements, and that the written requirements are correct with respect to the customer's needs and expectations (which may not match). The need for testing is necessarily recursive.

      --
      "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
    17. Re:testing is a waste of time by Anonymous Coward · · Score: 0

      I don't know about your customers, but mine care about the requirements. And they require test cases that prove the requirements are met. They also care about and require unit tests, coverage tests, string tests, and integration tests (we usually create a suite that can serve all testing purposes--except requirements, they are tested by the Software Verification Group). Your customers may not care that they have thrown their money away on the crap you write, but mine do.

      So, since testing is hard and can never be complete, we should just not do any, huh? Don't come work here, please.

    18. Re:testing is a waste of time by obarel · · Score: 1

      As long as it ends with QED, I believe it!

    19. Re:testing is a waste of time by FearForWings · · Score: 1

      It appears that at lest one mod took your recommendation to heart and ignored the test case that you were being sarcastic. I guess the proof will be if you keep the troll moderation.

      --
      I don't know about angles, but it's fear that gives men wings. -Max Payne
    20. Re:testing is a waste of time by aldo.gs · · Score: 1

      Well, you can give a proof that your program "works", but that's still far from "works correctly" :P.

    21. Re:testing is a waste of time by Surt · · Score: 1

      If you can define correctly, you can almost certainly prove it. :-)

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    22. Re:testing is a waste of time by aldo.gs · · Score: 1

      Heh, and that's the thing, isn't it? Trying to abstract real world situations into some conditions for a given program to satisfy can be very challenging; for example you have to meet some presentation guidelines and what not. For academic purposes maybe it's not so complicated (it's not in many cases :P), but other applications are hard to work with.

      But yeah, I think that if some situation (real world or not) can be abstracted enough for analysis using a computer, then creating a set of axioms should be not so difficult.

      Now the proof, that's another thing...

    23. Re:testing is a waste of time by jeremyp · · Score: 1

      And when you're done proving Linux correct, you need to prove the tool chain used to build your program is correct, and the tool chain used to build Linux and the tool chains used to build your toolchains and the tool chains used to build those tool chains and the operating systems all those tool chains ran on etc ad infinitum and the processors it all runs on.

      --
      All I want is a secure system where it's easy to do anything I want. Is that too much to ask ~~ Randall Munroe
  6. I Got Your Legacy System Right Here by cbowland · · Score: 4, Insightful

    A legacy system is anything that is in production RIGHT NOW. My coding philosophy has always been "building tomorrow's legacy systems today."

    --

    Give a man a fish and he will eat for a day.
    Teach him to eat and he will fish forever.

    1. Re:I Got Your Legacy System Right Here by Kjella · · Score: 1

      A legacy system is anything that is in production RIGHT NOW.

      Wait, so an application goes right from beta to legacy? (Or worse still, it's beta and legacy at the same time?)

      --
      Live today, because you never know what tomorrow brings
    2. Re:I Got Your Legacy System Right Here by cbowland · · Score: 1

      A legacy system is anything that is in production RIGHT NOW.

      Wait, so an application goes right from beta to legacy? (Or worse still, it's beta and legacy at the same time?)

      Sound like gmail.

      --

      Give a man a fish and he will eat for a day.
      Teach him to eat and he will fish forever.

    3. Re:I Got Your Legacy System Right Here by JesseMcDonald · · Score: 1

      Close, but not quite. Legacy software is software which has entered into the "Long-Term Support" phase of development. In other words, software which is no longer targeted at new installations, but which remains in use and must be supported and maintained.

      Software generally enters the "legacy" phase once a newer version of it has been released for general use.

      --
      "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
    4. Re:I Got Your Legacy System Right Here by Anonymous Coward · · Score: 1, Insightful

      Code is legacy the moment it is checked in. As soon as it's in source control, there is a cost to maintain it, continue testing it, and writing new code needs to take that existing code into account.

  7. Fixed story by Anonymous Coward · · Score: 0

    ...and the tests will tell automatically you if you broke anything covered by the test cases.

    Story submitter missed a few words out.

  8. If it compiles... by blindd0t · · Score: 4, Funny

    ...release it. ;-)

    1. Re:If it compiles... by morgan_greywolf · · Score: 3, Funny

      Damn it! I told you not to go around giving out our release process! That's company-proprietary information! *throws chair* You're fired! I'm gonna fscking KILL blindd0t!

      -- Steve Ballmer

    2. Re:If it compiles... by gmletzkojr · · Score: 1

      I know you are joking, but I worked with a guy that would do this. After he sent the executable to a customer, he would test the feature. Then, he would frantically call the customer, and tell them not to put the software in use, because it didn't work. He would repeat the process 3 or 4 times before getting the feature to work.

      --
      I for one welcome our new [insert main topic] overlords.
  9. lol by JeanBaptiste · · Score: 1

    I'm 2 months into my current job of re-writing stuff someone else did. That's spot on.

  10. Unit testing in Web programming by Parker+Lewis · · Score: 0

    How about unit testing in web systems? I never see other kind of test than test the ActiveRecord classes. Even on JSP/Servlets world is hard to do unit testing in web. Anyone has some tips?

    1. Re:Unit testing in Web programming by Surt · · Score: 2, Insightful

      Try rendering out enough hidden information in your html such that a programmatic test can drive the UI in a meaningful way (ie unique, tree-based ids for every user manipulateable element). Then testing is just a matter of recording the path of interest through the application. A script where I work might look something like:

      startpage = login
      AdminPage = startpage.clickAdminTab
      selectedUserRow = AdminPage.UsersList.SelectRandomUser
      selectedUserRow .ClickRevokePrivileges
      assertFalse(selectedUserRow.hasPriviliges)

      You can imagine how each of those things maps to the relevant html.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    2. Re:Unit testing in Web programming by mweather · · Score: 1

      Django has a unit testing system built in. I've never used it, though. My Django apps are always too simple to worry about it.

    3. Re:Unit testing in Web programming by Parker+Lewis · · Score: 1, Insightful

      Thank you for your reply, but you are describing an automated system test, not a unit testing.

    4. Re:Unit testing in Web programming by Surt · · Score: 2, Insightful

      I'm describing a UI level unit test (a test which covers a minimal unit of UI).

      If you just want to test your widgets on an individual basis, just use selenium and test pages.

      That's the only two facets to web testing I can think of, so if it isn't one of those please explain what you mean. Are you thinking of load testing?

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
  11. Re:Not Object Oriented. How Do I Make Safe Changes by Anonymous Coward · · Score: 0

    Pedantic (but this is Slashdot): "int main()" is not one of the valid forms for "main" allowed by the C standard (another the standard does allow for extensions). It is, however, a valid form for C++.

  12. what can tests really do... by drDugan · · Score: 5, Insightful

    I push back on this mentality each time I see it from the agile crowd: (FTA/review)

    "When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything."

    No. (testing FTW and all, but lets get real)

    Tests are *helpful*. Multi-user development beyond 2 people accelerates with good tests. Maintenance long term is easier with tests. Changes happen faster and are more robust with good tests. However, tests are extremely difficult to write well and almost impossible that cover all the possibilities for future changes while also telling future programmers automatically when something doesn't work. I think that the best one could say is this:

    When a comprehensive set of great unit tests are in place, then code can be changed at will and the tests will help the programmer understand if they broke anything. Test will often tell you automatically about things that are obvious, and usually would be seen with the most basic release testing. The art of writing good tests is understanding the subtle points of how your code functions and the pitfalls future developers may trip over when they extend what you did.

    1. Re:what can tests really do... by DiegoBravo · · Score: 1

      >>>When a comprehensive set of great unit tests are in place, then code can be changed at will and the tests will help the programmer understand if they broke anything

      Sadly, writing tests is boring... and writing the "setup" code of mock objects, dummy/semi-random data, feeding the database with it, etc... is more boring.. but this all is needed for any real-world project. Yet most people assume that trivial junit tests in small non-coupled objects is the rule. Tipically this just avoids weird values in method parameters, but no good full system behavior.

    2. Re:what can tests really do... by Precipitous · · Score: 2, Insightful

      Your argument seems plausible, until you have actually seen the difference in products developed with test-driven / unit test first approaches. The benefits are not what you think they are. I would agree that unit tests are not a panacea, but disagree on

      1) The are essential, not just helpful, at least, if you intend to produce software that works.
      2) Unit tests do not need to be comprehensive to be useful. They don't need to be great, but great helps.

      I tend to agree with you on 1) unit tests are not integration tests, and also do not replace smart human testers. 2) No TDD or agile expert would include the word "anything" in this statement "When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything"

      Here is what does happen in initial development with TDD / Agile.
      First, you write tests first, based on clear user stories. Then you write code to pass to pass tests (one at a time). This saves massive amounts of time: you avoid unnecessary code, over-design, and unnecessary features.

      You see a side benefit quickly: In order to get code into true unit tests, each module has to do something meaningful on its own. You avoid the massive stink of excessive interdependency that paralyzes much OO code. (Much of Feather's book is about how to break those dependencies in order to test code).

      Now, 1 or 2 weeks later (agile development gives you something interesting to look at in a week or two, not a month or two), it's either time to clean up the code, or you found you really misunderstood the problem. With this test coverage, it is enormously easily to re-factor.

      But a warning: If you were writing integration tests (not unit tests), you'll find the tests are in the way. You make 1 change, and 10 tests fail. Done correctly, 1 change, 1 unit test fails. xUnit Test Patterns might be a good book, if you have this problem.

      Is the coverage helpful or essential? Most of the code I work on has complexity rated at mind-boggling. Not only is it helpful to have the coverage, it's essential. I don't want to attempt to remember all 200 rules and exceptions when each behavior is complex enough. And don't want to wait 2 weeks for QA to finish their test pass. Good coverage means I make a change, and know immediately. I can let QA know risks that can't be covered in unit tests, and they can do some valuable work in discovery. Essential!

      --
      My motto: "A cat is no trade for integrity."
    3. Re:what can tests really do... by Drogo007 · · Score: 2, Insightful

      As a long time Tester (10+ years) and Programmer, I'm going to go one step further:

      Writing GOOD tests is HARD.

      First you have to think through the use cases, business logic, etc etc etc

      Then once you have the tests written, stop and think: Who is going to test that the code you just wrote (unit tests) is actually doing what you think it's doing.

      I write test code for a living, and test code still scares the crap out of me for the simple reason that there's no verification happening on the test code itself apart from what the original author of the code does. Simple syntax errors in your tests may mean that what you think is being tested, is actually not being tested at all, or being verified to the wrong spec!

      Unit tests are a Very Good Thing (TM)! But they are NOT the end-all-be-all of testing.

    4. Re:what can tests really do... by artg · · Score: 1

      Tests are, indeed, useful. But the idea of using tests as anything other than confirmation of function would be seen as the dark ages in any other branch of engineering. The fact that it's seen as a new concept in software is illuminating ..

      In civil engineering, a failed test means major rework. Tests are performed either as research or as a confirmation of safety. In the latter case, they are not expected to fail.

      In production engineering, tests were once performed to filter the good builds from the bad. This was far too expensive, and largely explains the success of Japanese industry over British and American in the 70s and 80s. Reworking production because of errors costs a huge amount of effort by skilled personnel : building it correctly takes largely automatic effort by much cheaper employees. Worse still than reworking errors is reworking bad design, where production workers have to tease the required performance out of a marginal design. A small batch of components towards the edge of tolerance can shut down manufacturing.

      We like to think that a good software engineer designs and implements correctly and gets it 'right first time' and then the software can be duplicated indefinitely. In exceptional cases, this is true. In many cases, especially where a team is involved or the unit has to work in the context of other software, it isn't : the situation is much more like that of an assembly line. When we truly get to the point where we know how to make it right first time and only fail when we screw up, we'll really be Engineers. Until then, we'll be relying on testing to find basic errors, but it's a cop-out.

    5. Re:what can tests really do... by Anonymous+Brave+Guy · · Score: 2, Insightful

      1) The are essential, not just helpful, at least, if you intend to produce software that works.

      That clearly isn't true. Arguably the most robust software in the world is produced using the Cleanroom approach, which is almost the antithesis of TDD. Of course the typical constraints for the kind of development project that uses Cleanroom are rather extreme, but that doesn't make them any less valid a counter-example.

      I tend to agree with you on [...] 2) No TDD or agile expert would include the word "anything" in this statement "When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything"

      One of the problems I have with these "experts" is that while they may not actually say that, a lot of them certainly give that impression to people learning from them by not explicitly correcting the over-generalisation encouraged by their general presentation, and a lie of omission is still a lie. The very existence of that claim in the Slashdot summary here is a demonstration of the way a good probability can turn into an absolute in the mind of the impressionable student.

      First, you write tests first, based on clear user stories.

      Which is cute, except that a lot of real world software development doesn't fall into neat little boxes like that. You can test examples, but you can't test every possible document a user might type into your word processor, every possible data set you might collect with a scientific instrument, every possible configuration designed in a CAD application, or every possible state of a game world in a MMORPG. This matters, because a new "feature" might not make any sense in isolation, only in combination with other features to give it some context, so you can't just write a single, isolated test for its behaviour. The fact that dependencies between interacting features can be significant is why unit testing alone is insufficient as an approach to quality control.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    6. Re:what can tests really do... by JesseMcDonald · · Score: 1

      Writing software is akin to designing a process. It is 100% design; the implementation only occurs after the software has been written and released, when it runs in a production environment. Unit testing is similar to building models or prototypes of a component or subsystem to verify that things fit together as intended. Integration testing is like building a full-scale prototype to study its overall characteristics, with the results fed back into the design process.

      Only when the design is complete -- including any models and prototypes required along the way to show that the design is sound -- is the end result actually implemented in a production environment.

      The other thing to keep in mind is that computers make complex processes ridiculously cheap ... to implement. Software design doesn't scale the same way. The average piece of software is far more complex, in terms of component interdependencies, conditional behavior and time-variant signals, among other things, than most other kinds of engineering design.

      A computer can implement all this complexity without even breaking a sweat, so to speak, but designing a complex process to work in a wide range of environments, to accept invalid (or even malicious ) input without breaking down, to always conform to a dazzling array of human-written (conflicting, incomplete, misleading, etc.) requirements -- it's a bit amazing that non-trivial applications manage to function at all, much less that they work as well as they do. The insistence on abstraction, clean interfaces between components, and layered testing has a large part to play in that success.

      --
      "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
    7. Re:what can tests really do... by Precipitous · · Score: 1

      Cleanroom sounds interesting. Perhaps I hyperbolized if I indicated that TDD is the ONLY method of creating reliable software. It is, however, one of the cheapest and easiest.

      "Which is cute, except that a lot of real world software development doesn't fall into neat little boxes like that.."

      Not just cute, but very valid. Most real world, usable software can be broken down into neat little boxes, and should, for more reasons that just TDD support. Budgets change, financial systems crash and leave you without credit lines ... Breaking down features into small chunks is necessary to ensure that you produced some value before your product was unexpectedly canceled. That's a principle well beyond TDD. My company has several massive projects going forward rapidly, on budget, broken down into small pieces, just like this. We are less worried then others about change, precisely because, while we have much more to do and many months to do it in, we have we could sell right now. A lot of people believe you can't break this stuff down, don't ... and go out of business when vaporware v2 isn't done on time. We'd just ship 90% of the features as V2.

      Also remember TDD is mainly about about unit tests. Your combination argument applies to integration tests, and is the main reason to apply strict TDD (with unit tests). Some math ...

      I create components with clearly defined responsibility and few dependencies. It might have 3-4 methods and perhaps 10-100 test cases. In unit tests, this is possible. It's easy enough that you can easily dig into the edge cases for each component.

      If we start at integration testing or manual testing, combining 4 or 5 of these components, we have an unmanageable test matrix. You'll never cover the base cases, much less the edge cases.

      e.g Just last week, I headed off a subtle bug starting from an incorrect comparison leading to bad sort and on to total badness. After applying a refactoring recipe straight out of most TDD books, I discovered I could get to the edge cases of a sorter very rapidly. The integration test would have required an large and complex test data set. The bug would be lost in the details.

      The TDD hypothesis is that you achieve reliability faster by ensuring that each component is extremely reliable, and combining reliable components. Interesting integration cases are the domain of the quality assurance professional. If the components are reliable, QA will have time for interesting testing. If not, they will fill there days filing mindless functional bugs and miss massive problems.

      "One of the problems I have with these "experts" ... I won't get into an argument about authority. My point is, most any book or resource about TDD, unit testing, or the like, does not omit the role of manual testing. The back cover of the book might omit it. Most agile methodologies will also combine TDD with continuous integration and rapid, manual, QA cycles. Same idea: get results as fast as possible, fix as fast as possible, know that when you are done, you are really done.

      My experience strongly confirms the TDD hypothesis. However, there are dozens of ways to achieve quality. Regarding this book and review: TDD works for many people, for those who buy the TDD hypothesis, Feathers' book is great.

       

      --
      My motto: "A cat is no trade for integrity."
    8. Re:what can tests really do... by jgrahn · · Score: 1

      You see a side benefit quickly: In order to get code into true unit tests, each module has to do something meaningful on its own.

      How is this a benefit? Normally, noone cares what the module does except its intended work.

      You avoid the massive stink of excessive interdependency that paralyzes much OO code. (Much of Feather's book is about how to break those dependencies in order to test code).

      Excessive interdependency doesn't sound like much fun ... but neither does excessive independency. If the application has a hard dependency, I tend to want that to be explicit in my code. If circus clowns aren't in my application's target group, I happily let my Bikes have two Wheels, rather than zero-or-more virtual RollingDevices which are pulled out of a VirtualRollingDeviceAbstractFactory. The code's intention becomes clearer that way. I prefer understandable code to testable code, and I prefer to catch my errors with static type checking than with tests which may or may not exist.

      I do use unit tests and I often let them affect the design to some extent ... but I refuse to let them make my code less understandable.

    9. Re:what can tests really do... by stubob · · Score: 1

      That's why some code coverage tool needs to be run against the unit tests.

      Show me that most of the code logic is being tested against a number of different datasets, and then I might start to believe that the code may work. Then we can move on to system or integrated tests.

      --
      Planning to be moderated ± 1: Bad Pun.
    10. Re:what can tests really do... by Fulcrum+of+Evil · · Score: 1

      In production engineering, tests were once performed to filter the good builds from the bad. This was far too expensive, and largely explains the success of Japanese industry over British and American in the 70s and 80s.

      No, what explains the success of the Japanese was process improvement - the Deming management method made their stuff into works of art and reliable to the point where testing was redundant.

      Reworking production because of errors costs a huge amount of effort by skilled personnel

      Which is rather different from software development; reworking prod can mean recoding some stuff and compiling, depending on when it's found.

      We like to think that a good software engineer designs and implements correctly and gets it 'right first time' and then the software can be duplicated indefinitely. In exceptional cases, this is true. In many cases, especially where a team is involved or the unit has to work in the context of other software, it isn't : the situation is much more like that of an assembly line.

      A good software does get it right the first time, provided that specs are clear (they usually aren't). Software isn't really an assembly line, it's more of a conversation, and getting feedback quickly is a better driver of quality than most things.

      --
      "We returned the General to El Salvador, or maybe Guatemala, it's difficult to tell from 10,000 feet"
    11. Re:what can tests really do... by Anonymous+Brave+Guy · · Score: 1

      Please note that I'm not criticising the practice of unit testing. On the contrary, I completely agree that unit testing is a cost-effective way to improve code quality, and quite distinct from integration testing.

      However, it seems to me that all the benefits you ascribe to TDD in your posts here are actually benefits derived from unit testing. The rest of TDD doesn't particularly help with any of these things, other than to the extent that it encourages development of unit tests, which of course you can do just as well without adopting the rest of TDD if you wish.

      I guess we'll have to agree to disagree on your claim that "Most real world, usable software can be broken down into neat little boxes". Certainly some software can be developed entirely in this way, and modularity is in general a good thing. But I have seen plenty of examples, in plenty of different applications, where this simply isn't true, and the smallest independently meaningful, self-contained unit is quite large.

      In such cases, you can't just ship 50% of a project and get 50% of the value out of it. To give the Slashdot-obligatory dubious car analogy: a vehicle that's 95% finished still isn't going to get you somewhere if no-one produces wheels to go on it. Similarly, software projects tend to be greater than the sum of their parts, because meeting 90% of the requirements but failing on the last 10% can easily make the whole project completely worthless to your client. Most software is not the kind of thing that comes in off-the-shelf boxes or one-time downloads, where you compare one version with the next using some dubious feature table showing how much better it is than the opposition, and missing the odd bullet mark isn't the end of the world.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    12. Re:what can tests really do... by zuperduperman · · Score: 2, Informative

      I agree with your points, but I think everyone here is missing a huge benefit of writing tests: by necessity it forces good design in and of itself because it's near impossible to test anything with with complex behavior. The result is that just to make the unit tests feasible, developers stop writing enormous monster classes without interfaces and start fragmenting things down to small units that do just one or two things with well defined behaviors.

      You see a lot of people complaining that tests are "too hard" etc., and in most of these cases it is because the software they are testing is poorly written - huge monolithic chunks of behavior with large dependency sets.

      I disagree with you about integration tests: I think they are as essential as unit tests. In fact, I think automated tests all the way up the chain to UI driven end product tests are the best way to do things.

    13. Re:what can tests really do... by MadKeithV · · Score: 1

      First, you write tests first, based on clear user stories.

      Which is cute, except that a lot of real world software development doesn't fall into neat little boxes like that. You can test examples, but you can't test every possible document a user might type into your word processor, every possible data set you might collect with a scientific instrument, every possible configuration designed in a CAD application, or every possible state of a game world in a MMORPG.

      That's only partially true. Unit Tests are not black-box tests, they are written by the developers ideally before the actual code is written, and they ideally exercise most if not all of the special cases of the code. To use the document analogy: you won't test every document (QA can't do that either), but you will test all "classes" of documents that are actually different to the handling code.

      Depending on the complexity of the system that can still be impossible. TDD evangelists might claim that this means the system is badly designed and should be broken up into pieces that *are* testable. I personally do not have enough experience with TDD to subscribe to this point of view - it seems to me that sometimes you have to do something that's simply too hard to predict or test accurately (uncontrolled hardware, random input, multithreading..).

      Still, putting together a set of 100% covered and tested blocks of code will give rise to a whole new set of untested behaviours, and stuff will still break.

  13. As someone who hasn't worked with unit tests... by Spy+der+Mann · · Score: 2, Interesting

    what book can you recommend to me regarding unit tests? After reading the summary, I really got interested in this unit test stuff.

    1. Re:As someone who hasn't worked with unit tests... by tomhermann · · Score: 1

      Start by reading the developer documentation for the unit testing framework you are going to be using (junit for java, cppunit for c++, etc.)

      Once you've mastered the basics of getting the framework installed and a basic test passing (e.g. assertTrue(true); ) check out xUnit test patterns. This book covers a lot of basic unit testing topics along with a number of things not to do while unit testing.

    2. Re:As someone who hasn't worked with unit tests... by Anonymous Coward · · Score: 0

      I recommend that you realize if you could write a unit test for every method, which made sure that every function worked properly in every situation, you wouldn't need the original code - you would already have the inputs and outputs.

    3. Re:As someone who hasn't worked with unit tests... by fredrik70 · · Score: 1

      I quite liked Test Driven Development - a practical guide (http://www.amazon.co.uk/Test-Driven-Development-Practical-Guide/dp/0131016490/ref=sr_1_4?ie=UTF8&s=books&qid=1222725383&sr=8-4)
      It doesn't get into mock objects as much as I like but it's decent read in general when you start out with TDD

      --
      if (!signature) { throw std::runtime_error("No sig!"); }
  14. What if the legacy code doesn't work? by wandazulu · · Score: 2, Interesting

    I have some legacy code that straight-up doesn't work; it makes references to non-existent proprietary libraries, uses classes that aren't defined anywhere, and just to make things more interesting, a lot of methods with a lot of code, and variables carefully instantiated, that are never used.

    This is what is checked into source control; there is a binary that does, in fact, work, based on this code (or some better flavor of).

    What to do then? There is some pretty involved financial algorithms in there that were designed by a mathematician and both the original developer and the mathematician have long since left the building. Yet, here I am, with a bug report that one of the models is wrong, and have absolutely no way to fix it.

    An earlier comment suggested that the "real" way to was to decry the original author's skills, parentage, etc., and just re-write. Frankly, this seems to be my only option at this point.

    1. Re:What if the legacy code doesn't work? by Surt · · Score: 1

      Carefully instantiated variables that are never used are often changing global state. Having the variable makes debugging easier in some contexts. Not to say this is the explanation for your situation, but it is a reason you'll see that some times.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    2. Re:What if the legacy code doesn't work? by j-pimp · · Score: 1

      I have some legacy code that straight-up doesn't work; it makes references to non-existent proprietary libraries, uses classes that aren't defined anywhere, and just to make things more interesting, a lot of methods with a lot of code, and variables carefully instantiated, that are never used.

      This is what is checked into source control; there is a binary that does, in fact, work, based on this code (or some better flavor of).

      Look into reverse compiling. Depending on the source language, this might be feasible. If not, disassembling and linking the code in might work in a pinch, but you will need to get the code to compile or rewrite it.

      Suing the original developers might be an option. This is flat out negligence. By threating to do so, these developers might be willing "find" the missing source code.

      --
      --- Justin Dearing http://www.justaprogrammer.net/ We're just programmers.
    3. Re:What if the legacy code doesn't work? by Anonymous Coward · · Score: 0

      The thing is: does the checked in code compile?
      TO the same thing as the binary?
      If if doesn't, then make sure your boss knows.

      If it does, then there are hacks in the code somewhere to get around these problems. You need to find them.

    4. Re:What if the legacy code doesn't work? by nyabutid · · Score: 1

      Investigate whether there was a compiler dependency in generating the working binary. My experience has been that some setups don't result in a working binary right away. You have to fiddle and almost get t othe point to replicating the initial build environment where the code was run on.

      Look at design patterns when reverse engineering the code to somehow have a sandbox where the execution can be monitored.

      --
      -Dickens
    5. Re:What if the legacy code doesn't work? by Anonymous Coward · · Score: 0

      Hehe, they should've paid what I wanted to keep me on :-)

    6. Re:What if the legacy code doesn't work? by John+Hasler · · Score: 1

      > Suing the original developers might be an option.

      Not if they were employees of the company now trying to use the code. In the US an employer's only recourse against an imcompetent employee is to fire him.

      > This is flat out negligence.

      Yes, the company was negligent in allowing this to happen. Perhaps some managers need to be fired.

      > By threating to do so, these developers might be willing "find" the missing source
      > code.

      I saw nothing in the article about deliberate malicious sabotage. That's what you have to be prepared to prove.

      --
      Warning: this article may contain humor, sarcasm, parody, and perhaps even irony. Read at your own risk.
    7. Re:What if the legacy code doesn't work? by Fulcrum+of+Evil · · Score: 1

      I have some legacy code that straight-up doesn't work; it makes references to non-existent proprietary libraries, uses classes that aren't defined anywhere, and just to make things more interesting, a lot of methods with a lot of code, and variables carefully instantiated, that are never used.
      This is what is checked into source control; there is a binary that does, in fact, work, based on this code (or some better flavor of).

      Looks like you need to get some code that works to start with - the decompiler might be a good approach.

      There is some pretty involved financial algorithms in there that were designed by a mathematician and both the original developer and the mathematician have long since left the building. Yet, here I am, with a bug report that one of the models is wrong, and have absolutely no way to fix it.

      Tell your boss about the problem - it's going to take longer than it should for a bugfix and you want him on board to set expectations.

      --
      "We returned the General to El Salvador, or maybe Guatemala, it's difficult to tell from 10,000 feet"
    8. Re:What if the legacy code doesn't work? by toddestan · · Score: 1

      Yet, here I am, with a bug report that one of the models is wrong, and have absolutely no way to fix it.

      Have you looked in the code to see if you can find where this math is? If so, you might want to try to verify that these is, in fact, a bug in the code if you haven't done so. I often treat new bugs found in old code with a grain of salt, as the code has been around for a while which means that its behavior is more of a known. If this model is not a rarely used feature, and the software has been around for years and users are comfortable with the output, I would be very skeptical when someone claims it is "broken". Many times these reports are the result of a misunderstanding on the user's part, or they fed the software bad data, or something like that.

    9. Re:What if the legacy code doesn't work? by rubies · · Score: 1

      I've been in that position before - not sure whether the source code I had in source control was what was running in production (and you know what? it wasn't!).

      This app was thankfully relatively easy (conceptually) to verify. We took copies of the production databases and tore our hair out for 4 weeks making sure the version we could compile/bug fix at least was able to run and mostly replicate what was in production, then yanked the production version and substituted the new one. We had a few teething issues (turned out the source code was for a version with a couple of unfinished new features) but eventually it was sorted out and the pain was worth it just to have a debuggable/fixable version).

      so the short answer is: run parallel if you can but replace as soon as you can, because operating blind is sometimes worse than operating buggy.

      (financial application btw - written in C with a normal relational back end).

    10. Re:What if the legacy code doesn't work? by ebuck · · Score: 1

      Well, to start, can you reproduce the binary? If not, then you'll have to find those missing libraries, classes, and whatever else. In the event that simple searches don't turn up anything, reversing the binary might be your starting point. Remember, in your first pass you don't have to reverse for 100% comprehension, only for equivalent compilation.

      From there it's just a lot of refactoring till you have code that looks something like the algorithm described in the documentation. Hopefully by then you can identify where the code deviates from the documentation and identify if that deviation is due to the incorrect model, or other factors that failed to get "updated" in the documentation.

      Fixing by rewriting is almost always a doomed proposition for your case. It is rare that code follows the documentation 100% because life-learned lessons in the code don't get reflected in pre-existing documentation. It's easier to say "oh yeah, I forgot about that case, just fix it this way" then to pull out approved documents and go through another round of review to add a trivial (but critical) addendum.

      Sure, this technique seems slower, but every step forward is measurable, and there are no surprises (you can always reproduce the binary as it already works). Rewriting gets you 80% done much faster, but it's hard to say if you'll finish it more quickly: there will be lots of opportunity for surprises with no guarantee of "current functionality" at any point in the game.

    11. Re:What if the legacy code doesn't work? by j-pimp · · Score: 1

      I saw nothing in the article about deliberate malicious sabotage. That's what you have to be prepared to prove.

      Trying to scare the crap out of the employees with threats you can't back up is an option that can work. Sometime empty threats work. If you feel that its managements fault for allowing this to happen, you can hire them as consultants.

      --
      --- Justin Dearing http://www.justaprogrammer.net/ We're just programmers.
  15. Test this, test that :) by sw155kn1f3 · · Score: 1

    >> then code can be changed at will and the tests will tell automatically you if you broke anything

    *Old legacy dev's pessimistic evil smile*
    All right, young man, now please refer me to a book where they have a way to write tests to automatically correct my errors while I drink coffee!
    That'd be something. Return when you found one.

    --
    - Arwen, I'm your father, Agent Smith.
    - Well, you're just Smith, but my father is Aerosmith!
  16. Building the Legacy Systems of Tomorrow by dwheeler · · Score: 3, Insightful

    I have this bumpersticker posted on my office wall: "Building the Legacy Systems of Tomorrow". I'm not sure who created that phrasing - or the bumper sticker - but I like it.

    In short: if it runs, it's a legacy system.

    --
    - David A. Wheeler (see my Secure Programming HOWTO)
  17. Legacy code by metamatic · · Score: 1

    Feathers' definition is 'code without tests.'

    Funny, my definition of legacy code is "code without documentation". If I have documentation for what the code is supposed to do, I can write tests myself. If I don't have documentation, tests won't save me.

    --
    GCHQ Quantum Insert installed. If only our tongues were made of glass, how much more careful we would be when we speak
    1. Re:Legacy code by Anonymous Coward · · Score: 0

      Legacy code is code you're not allowed to redesign / refactor. In most shops, the mainline becomes "legacy code" as soon as you hit the first "freeze" milestone.

      Unfortunately the freeze usually happens before the test team has signed off, so you end up with dozens of "highest priority" bugs filed against the dev team. All of these have to be treated as fixes to legacy code, so you're usually not allowed to fix the root cause.

      What's that? ... Why yes, I do work at Microsoft. How did you guess?

    2. Re:Legacy code by Surt · · Score: 2, Insightful

      The really nice to have is where the tests and the documentation are unified, making it impossible for them to diverge. That's what we've built our process around, and it works amazingly well.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    3. Re:Legacy Code by serviscope_minor · · Score: 1

      Sometimes you have to call up a help desk of a vendor to get answers as well, but they docked me for long distance calls to Canada where Crystal Reports and Segate/Business Objects had their headquarters.

      You continued to work there after they docked you (presumably your pay) for doing your job? If you had any flexibility, you should have quit on the spot and sued them for the money they owed you.

      --
      SJW n. One who posts facts.
    4. Re:Legacy Code by Orion+Blastar · · Score: 1

      Yeah I guess I could have, but it is all in the past. I forgive them for doing that to me, but they did it out of ignorance because they didn't understand what I was doing for them or how valuable it made me.

      They suffered for firing me, and could not replace me with someone who could do the job. I am writing these hints and directions and habits to help other programmers be like I once was.

      I am getting my marbles back and will become a great programmer again. Maybe they will see I didn't sue them and hire me back as a contractor? :)

      I didn't quit because I have a wife and son that need to have a house, if I quit I'd lose my house as I had a lot of medical bills and owed a lot of money to credit card companies to buy the medicine my insurance wouldn't pay for and the books I needed to do my job that my employers would not buy for me.

      I had a small business but it only did tech support, as I had a "no compete" contract with them and so I didn't write programs but fixed computers instead to make sure it was a different line of work. But the local tech support businesses ran me out of business, caused my business partner to have a heart attack and I got really sick myself and closed the small business. Then I got fired for being sick on the job, and I was under a lot of stress for reasons I posted above. But I forgive them because they didn't know what they were doing or how valuable I was to them.

      I've moved on, and I dug myself into a deep hole I now only recently am starting to get out of.

      I've been in hell for like 7 or 8 years or a decade and I just got back to Earth. Now I am back and better than ever. :)

      --
      Remember, Slashdot does not have a -1 disagree moderation, and no, troll, flamebait, and overrated are not substitutes.
    5. Re:Legacy Code by Orion+Blastar · · Score: 1

      By the way I never mention any company by name. I post as Orion Blastar as a parody of myself with a sense of humor.

      Please don't take everything I say as serious. Jokes are protected from various laws and I was speaking hypothetically as something I thought happened and I might have been wrong about it, but I did a joke anyway. It did it to make others see that sometimes management doesn't understand what employees are doing. It was a parable parody.

      --
      Remember, Slashdot does not have a -1 disagree moderation, and no, troll, flamebait, and overrated are not substitutes.
    6. Re:Legacy code by Anonymous Coward · · Score: 0

      The really nice to have is where the tests and the documentation are unified, making it impossible for them to diverge. That's what we've built our process around, and it works amazingly well.

      Interesting. Can you expand on this?

    7. Re:Legacy code by tuomoks · · Score: 1

      Yes, it is really nice! I wonder, moving away from mainframes a long time ago, does such systems exist in smaller systems?

      In 70's and 80's we had a configuration management / source control system which kept all the requirements, source, test and production documentation synchronized. Every version in design, development, test and production was linked the way you could jump from bug report to source to requirements and look all the tests it had gone through with results, when, etc. Or vice versa, from requirement and to look the test results or any reports on production version including the performance reports, capacity estimates, etc.

      Our development, QA and production people loved it, you push the function key (no mouses then!) and spec was there, you changed a database, relevant structures, access statements, screen formats, list of applications, whatever showed up. You assigned the change to test (QA), relevant applications were compiled, databases built, tickets to QA and reports were created and submitted to relevant persons with a comment what and why you changed, was it because of a bug, a new requirement, a response to a QA report, whatever.

      Oh yes, and every code change and unit test was recorded to the system requiring an explanation. So a person left to a vacation, was fired, died, whatever - next one could pick up almost immediately, just a little reading.

      I created the first one in our company and have missed it a lot after moving mid size and small systems - not small by computing power but how they didn't (don't?) have real CM/SC systems (please, don't mention Clearcase, Testdirector, Remedy and such - not in same class!). Actually with correct authorization you were able to see the business decisions, budgets, timelines, who did what, where and when via application requirements - finding best person to contact when something happened in production was very easy. It cut of a lot management overhead - maybe that's why not all the managers liked it?

    8. Re:Legacy code by Surt · · Score: 1

      The really nice to have is where the tests and the documentation are unified, making it impossible for them to diverge. That's what we've built our process around, and it works amazingly well.

      Interesting. Can you expand on this?

      Since code and comprehensible english are difficult to converge, what you usually wind up with in such a system is the story/test model.

      The story describes the functionality in English (describes the user activity being modeled). The test then implements the story, preferably in a high level language where the story -> test translation is as trivial as possible. Here's a trivial story / test combination:

      Story:
      The user logs in and logs out. The user is at the logout page.

      Test:
      login
      logout
      assertTrue(currentPage == logoutPage)

      The key to such a system is that the story/test are either in the same system, or very tightly coupled. In our system, there are hyperlinks from story to test and back that understand how to navigate our source control / build / documentation system so that you can easily go from story to test to test result and back again.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
    9. Re:Legacy code by Surt · · Score: 1

      Such systems definitely exist. Our system uses a wiki to link cm, build, test, results, requirements. I've seen other places with similar infrastructure.

      --
      "Who is the Journal of Quantum Physics going to believe?" --Stephen Hawking
  18. Wait a second by Anonymous Coward · · Score: 3, Funny

    Did you just refactor his review? BRILLIANT!

  19. Re:Not Object Oriented. How Do I Make Safe Changes by siride · · Score: 1

    Uhh, yes it is. I can't find a single reference online that indicates otherwise. It most certainly is not the "void main()" travesty.

  20. encapsulation by Dan667 · · Score: 4, Informative

    The most successful strategy I have had for legacy code that I have inherited is encapsulation of the old code into a new framework. I first attempt to build a black box wrapper with an API for what ever the legacy code did (wrap 5000 line loops, etc). Then as I can or need to change it, I take the black box and break it into proper libraries or readable functions (or start over). Have been able to do this for some really large bases of code and have a working system while I re-factored the mess a little at a time.

    1. Re:encapsulation by bensch128 · · Score: 1

      How do you handle side effects?

    2. Re:encapsulation by mjmartin_uk · · Score: 1

      You handle the side effects on a case-by-case basis. The great things about doing it this way is you can break up huge controllers with hundreds of lines of code into smaller class methods whilst still keeping the original integrity of the class intact and compatible with old calls. The method's not 100% effective but at least this way you can get the code to correctly pass new tests piece by piece whilst still adhering to the inevitable looming deadlines. I use this system quite a lot when dealing with legacy code. It's not the be-all/end-all solution but it helps.

    3. Re:encapsulation by kymike · · Score: 1
      I agree with your approach, but I also combine it with one other step, which Feathers also suggests.

      one of the most useful ideas I got from the book was using automated refactoring tools for throw away refactorings in order to understand code. But he also makes the point that automated refactoring tools can be used to tame legacy code, without needing to write tests.

      Wrap the legacy code in an api as you describe. As much as possible create suitable tests for it.
      Then use the automated refactoring tools provided by your favourite IDE (blah blah blah vi, blah blah blah emacs) to make the changes. Feathers points out that automated refactoring tools are intended to leave behind functionally equivalent code. So in theory you do not need to worry about the refactored code - you can treat it as being the same as the legacy code.

      There are some caveats:
      - it's only worth doing this for code that you deal with frequently and the you know you are going to have to change at some point
      - it takes some time to trust the refactoring tools. Even now I still have a hard time believing that they changed _something_ but I haven't been bitten yet.
      - it also takes time and practice to do the automated refactoring. 90% of the time it's extract method or extract interface/class but there's a skill in picking suitable parts out.
      Practice! - Do NOT manually edit anything. Only provide method/class names when prompted. Again, this seems counter intuitive, but is necessary. Rely on the automated refactoring tool. Any intervention by you breaks the spell and introduces the risk of error.
      - once done, you do need to start looking at unit testing the refactored code, but at least you have something reasonable to work with that you also have some level of trust in.

  21. Anonymous Coward by Anonymous Coward · · Score: 0

    Can you say "Wag the Dog". Anyone can write a test that will pass. Back to Glenford Myers and the "Art of Software Testing".

  22. Re:Not Object Oriented. How Do I Make Safe Changes by Anonymous Coward · · Score: 0

    Every time you write void main(void), God crushes a kitten.

  23. So when someone asks me... by ivandavidoff · · Score: 2, Funny

    "Say, Ivan -- does your code have tests?" "Nope, it's Legacy Code". "Is it debugged?" "Nope -- legacy." "Does it work?" "Look, I already told you: IT'S LEGACY CODE. GET OFF MY BACK."

  24. Except that by Anonymous Coward · · Score: 1, Insightful

    Tests ARE documentation.

    With the bonus property that the computer can execute them.

    1. Re:Except that by metamatic · · Score: 1

      No, tests are not documentation. For example, tests don't tell you what the extent of the supported API is--they only give you some examples that are included in the scope of the API. If all you have is tests, you have to guess whether some observed behavior is supported and intentional, or likely to go away later.

      There are a lot of Ruby and Rails programmers who believe the "tests are documentation" crap, and I've seen a lot of breakage happen because of it.

      --
      GCHQ Quantum Insert installed. If only our tongues were made of glass, how much more careful we would be when we speak
  25. About how to move from bad design to good design by Precipitous · · Score: 1

    This book has been essential to me over the last 2 years: I've been keeping the "legacy" parts of a large web application running while others went on to develop cool new features. Let's just say this, there are two different challenges in software:

    Challenge 1) Create a good design from scratch. Lots of folks can do this.

    Challenge 2) Move from bad design or bad code to good design, while keeping the product running. Transforming a design in small re-factoring steps is vastly harder than rebuilding, but usually necessary.

    This book is about that second, harder challenge. It emphasizes testing and testability, because that is how you ensure the product continues to run while you make the necessary changes. It does tend to assume you know what the good design you aim for is.

    This is a very important book to have on your bookshelf, and will probably not become obsolete soon.

    --
    My motto: "A cat is no trade for integrity."
  26. Excuse me? by Anonymous Coward · · Score: 0

    the number of things you can do to introduce unit tests in procedural languages is pretty small

    It depends on how well the code is written. Good code is modular, and modules can be tested. If the code is so poorly written that it can't be broken down into testable units, that's the programmers fault not the language. Code like that should just be tossed away. If it can't be tossed away, you'll have to use a bigger definition of "unit", but it still works. I've seen code bad enough that the definition of "unit" was a CLI application in a shell pipeline. By testing the CLI applications we were, in a sense, testing units written in a nasty hodgepodge of shell and Perl scripts.

    Now, perhaps the author is referring to the lack of "unit testing frameworks". You don't need unit testing frameworks to write unit tests. I know that might come as a shock to some of the youngsters out there, but you can actually test functions in the same language the code is written in. You can even do things that are more sophisticated than assertions, which some of the unit testing frameworks I've seen seem to think are magic. Then have the test compile and build as part of the standard ``check" target in your makefile.

    1. Re:Excuse me? by Anonymous Coward · · Score: 0

      If the code is so poorly written that it can't be broken down into testable units, that's the programmers fault not the language.

      Fine, but blame is irrelevant. The original programmer is long gone and we have a job to do.

      Code like that should just be tossed away.

      Sometimes you can do that, and sometimes it's not expedient. I say, if you understand the code's purpose enough that you can test it, then your "legacy" is trivial. The ability to maintain someone else's inscrutable code, thus generating an even-more-twisted legacy, is the hallmark of the Master Programmer.

  27. Fie! by bperkins · · Score: 1

    When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything.

    Away vile Panacea!

    Keep thy sticky tentacles off management soft and pliable brain!

    Ye shall shall not destroy another project schedule with your false promises and soul sucking stupidity!

    Begone wretched creature!

    Live out your days off of the decaying pulp of so many piles of wasted trees and the scraps tossed to you by management consultants!

    1. Re:Fie! by TheGeneration · · Score: 1

      Seriously. TDD is all management masturbation.

      --


      The Generation
      I'd say something witty here, but I'm not that bright.
  28. Combinatorial Explosion by natoochtoniket · · Score: 3, Insightful

    Testing cannot detect errors with probability significantly greater than zero, unless the system under test is trivially small. For a system that has N interacting features, the number of test cases that are needed to "cover" all combinations of features is O(2^N). And, that is assuming the simplest possible features that are either used or not used in each case. If any features have complicated (more than one bit) inputs, the base of that exponential complexity function increases.

    While tests are helpful to detect implementation errors, test sets cannot be complete for nontrivial systems. And because testing cannot be complete, it can never provide sufficient verification. That is a basic fallacy of test-driven development, and of a-posteriori testing generally.

    The least-cost way to prevent bugs that will be noticed by users is to avoid making them in the first place. Requirements and designs can be documented, checked, reviewed, communicated, and (most importantly) read and referenced during subsequent phases and iterations of the development process. Test plans and test scripts can be part of that process, but cannot replace the requirements and design phases.

    Cost-driven managers don't like to hear that, though, because they think testing is cheap. Non-automated testing can often be done by cheap and easily-replaced labor. And automated testing is essentially free after the test software itself is developed and verified. (Notice, though, that developing the tests also involves requirements and designs, and increases the total amount of software that must be developed.)

    So, the least cost development process involves some reasonable amount of testing, but also involves requirements and designs, and reviews at every step. The only way to defeat the combinatorial explosion is by applying heavy doses of "thinking" and "understanding". Nothing else works as well.

    1. Re:Combinatorial Explosion by hondo77 · · Score: 2, Insightful

      And because testing cannot be complete, it can never provide sufficient verification.

      That's like saying that seat belts can't save your life in every car accident so they're not worth wearing at all. Unit testing is but one tool in a developer's toolbox. It is not an all-encompassing solution to all of a project's ills.

      --
      I live ze unknown. I love ze unknown. I am ze unknown.
    2. Re:Combinatorial Explosion by Anonymous+Brave+Guy · · Score: 1

      That's like saying that seat belts can't save your life in every car accident so they're not worth wearing at all.

      No, it's like saying that because seat belts won't save your life in every car accident, it's pretty dumb to drive around as if having an accident won't matter just because you're wearing a seat belt.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    3. Re:Combinatorial Explosion by hondo77 · · Score: 1

      That would be witty except that I had also written:

      Unit testing is but one tool in a developer's toolbox.

      --
      I live ze unknown. I love ze unknown. I am ze unknown.
    4. Re:Combinatorial Explosion by Anonymous Coward · · Score: 0

      > That's like saying that seat belts can't save your blah blah blah...

      You obviously didn't read the whole post.

      Slashdot CAPTCHA: dissent
      I'm beginning to agree with the guy claiming that slashdot has a lexical analyzer as CAPTCHA word generator...

    5. Re:Combinatorial Explosion by ebuck · · Score: 1

      I don't think you expressed yourself clearly, or perhaps you meant to write something other than what you wrote.

      "Testing cannot detect error with probability significantly greater than zero, unless the system under test is trivially small".

      First, when a function doesn't work, it's not "probably not working" for a specific set of inputs, it's 100% not working for a specific set of inputs. 100% is significantly greater than zero.

      Second, the whole concept of a unit test is to test something small, so even though your statement's first clause makes no sense, the second clause makes the first clause not applicable to unit testing.

      Third, unit testing tests a single class's behaviour. Testing combinations of classes better falls under integration testing. There's no combinatorial explosion of testing when you test only one item.

      Naturally to exploit this advance in software testing (and development) you have to buy into it's philosophy. If your code isn't very object-oriented (meaning that your classes don't have distinct and unshared responsibilities), then it will be nigh-useless to test if the unit (class) handles it's responsibilities.

      To test a class, you have to write code. Once you write the code, it makes no sense to run it manually every time you wish to verify the class still meets it's responsibilities. So you create a pass / fail framework, and volia! You have unit testing.

      It doesn't mean that other testing isn't important, and if you rearchitect the interfaces between your classes, you'll have to rearchitect the unit tests to match. But hey, there's no silver bullet that only shoots the work involved in changing the interfaces between classes except inaction.

      PS. The least cost gun wouldn't come with a safety either, which would be unnecessary in a world where accidental discharges never occur. In the real world, guns get dropped. In the real software development process, changes get made without perfect knowledge of all they ways the class is currently used (or abused).

      Don't advocate against rational low cost safety. The cost of unit tests get amortized over each regression test (which should be performed after each build), and are a lot less expensive than shipping buggy code to a client.

    6. Re:Combinatorial Explosion by The_reformant · · Score: 1

      Its more like saying its impractical to seatbelt everyone in world to stationary objects in order to prevent car crashes.

      --
      I have discovered a truly remarkable sig which this post is too small to contain.
    7. Re:Combinatorial Explosion by Anonymous Coward · · Score: 0

      >test sets cannot be complete for nontrivial systems

      This is true - but it is more a problem of inflated expectations than one of test coverage.

      For more complicated systems, you can test on different levels (unit, integration, system) minimizing cost-to-fix and increasing confidence when integrating the system components.

      Furthermore, based on requirements, specs, lessons learned, etc. you can make a risk based prioritization of features you test.

      This scopes down your test effort in function of the cost of failure * the estimated probability of defects.
      This can be scoped down further in function of available time and resources.

      You cannot test everything; so you might as well cherry-pick the most essential and risky features for your test effort.

  29. Without tests? Try working with legacy code ... by PolygamousRanchKid+ · · Score: 1

    ... without source!

    Believe me, this is not a singularity in the maintenance universe that I am familiar with.

    The best is the opening pitch that the customer gives:

    "Yes, this is a typical legacy code, blah, blah, blah."

    "Um, but we don't have the source."

    --
    Schroedinger's Brexit: The UK is both in and out of the EU at the same time!
  30. TDD is a waste of time and money. by TheGeneration · · Score: 3, Interesting

    Not once, EVER have I worked on code where the unit tests broke because of a bug or a mistake. Instead the unit tests break because the new code has something the test didn't anticipate. This is especialy the case in Easy Mock and TestNG.

    Maybe if you're working in a system with complex interdependence patterns, but generally it's a waste of time and money and just a management level masturbatory exercise foisted on engineering.
    ("I'm a super CTO of Cisco System! I'm going to force unit testing across the board, even where it doesn't makes sense! I'm going to be super ISO certified and John Chambers is going to lick my balls after his retirement when I become CEO!")

    --


    The Generation
    I'd say something witty here, but I'm not that bright.
    1. Re:TDD is a waste of time and money. by Anonymous Coward · · Score: 0

      What's the size of the projects you've worked on? Number of developers and experience across the team?

      How much does your code interface with other programs? Do you have direct control or does another team work have responsibility? Are they in-house or external?

      Also, don't you realize that catching issues with new code is a more than valid reason for unit tests? And at what point are you citing everything passing the tests? As the developer is coding or after they've checked-in the code to the source repository?

    2. Re:TDD is a waste of time and money. by ojustgiveitup · · Score: 1

      We use ruby, we use rails, and we unit test everything with rspec. After careful consideration, we have decided to update to the newest version of rails. The guy in charge of the upgrade started out by simply upgrading rails and running all the tests to see what breaks. Sure enough, lots of stuff breaks, one of them being in a piece of my code that is currently running, but which has not needed maintenance in ages. Easy fix once it was caught, but would have been a giant pain if it were not. There's no way I or anyone would have thought to update that portion of the code without a unit test. Unit tests do catch bugs, what gets you into trouble is thinking that they catch *all* bugs.

    3. Re:TDD is a waste of time and money. by swimmar132 · · Score: 1

      Huh, that's not my experience (working on Rails-driven web apps).

      My specs/tests help drive the design and catch bugs all the time.

    4. Re:TDD is a waste of time and money. by Anonymous Coward · · Score: 0

      Yup. TDD in concept is a great thing. In practice it is not that straightforward. A lot of ppl and advocates think its a silver bullet, but in reality writing good test cases is not easy. In the end we're shifting the problem from writing good code to writing good test cases; from headaches whether a code change broke something to whether a test case change broke the coverage to catch code that break something; from defects in code to defects in test code, etc.

      The only thing TDD provides is additional safety and that is only when it is done right. When done wrong, its more trouble than its worth.

    5. Re:TDD is a waste of time and money. by Anonymous Coward · · Score: 0

      How in the name of Fowler this got moderated at +4?

      The post is clearly a troll and goes against a number of serious studies, done by the Agile and TDD gurus.

      Can a good technique be applied in a wrong situation? Certainly, but that doesn't invalidate the approach. I can certify with absolute certainty, that TDD saved my time from small systems to big!

  31. If you CAN test it.. by Anonymous Coward · · Score: 0

    ..then it's not really legacy code. It's legacy code when you don't even know the intent of the code, and the behavior of the code itself is the list of requirements.

    And then you have to maintain it anyway.

    I currently do this, and I usually succeed (though there have been a few incidents), and I'm proud of that. :-)

  32. Re:Not Object Oriented. How Do I Make Safe Changes by Mr.+Slippery · · Score: 1

    use obscure variable names like xspatyc05 or funct123, always use static buffer sizes for any IO operations and under no circumstances should you add comments, it's a waste of time and no one besides you is ever going to have to understand it anyway.

    You used to work for my current employer, didn't you? And a couple (though, thank Goddess, not all) of my previous employers, too...

    --
    Tom Swiss | the infamous tms | my blog
    You cannot wash away blood with blood
  33. Yeah, right... by Locke2005 · · Score: 1
    When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything.

    Unless there is a bug in the unit test code, or some condition the unit test designer didn't anticipate... oh wait, you said "good unit tests" -- have any of these actually been observed in the wild? I have yet to see a unit test simulate what my 7-year old daughter does best -- clicking wildly all over the place until something crashes.

    --
    I've abandoned my search for truth; now I'm just looking for some useful delusions.
    1. Re:Yeah, right... by Blakey+Rat · · Score: 1

      I have yet to see a unit test simulate what my 7-year old daughter does best -- clicking wildly all over the place until something crashes.

      That's called Fuzz Testing, and yes, you should be doing it as well.

      http://en.wikipedia.org/wiki/Fuzz_testing

      When I worked in a Xbox 360 testing lab, we had a bank of 36 Xbox dev kits just sitting against the back wall doing nothing but running constant fuzz-tests and logging any errors that came up.

  34. Legacy Code by Orion+Blastar · · Score: 3, Informative

    I have had good luck with legacy code, here is what I do:

    #1 Figure out what the code does and document it with comments and write a document on it.

    #2 Identify variables and objects and what they are used for and any naming convention the code may use.

    #3 You need to stick to the original style of writing or rewrite parts of it into your style if it can give a performance boost or make it more stable.

    #4 Try to find programming errors and things that do not make sense and rewrite them so that they make sense. Do error trapping and check for nulls and letters entered into number variables and all other sorts of things most legacy programmers overlook.

    #5 Work to make the code stable and not crash and run faster before you start adding new features to it. Users don't want to wait 15 minutes to do a report and then have the program crash after their wait.

    #6 Work with the help desk to identify the most serious problems that users complain about the legacy code. Make it a "wish list" and then fix each complaint as you have time to do.

    #7 Get direction from your managers, tell them what you are trying to do and any problems you have. You need to work as a team with other developers, the help desk, managers, and users to work out the issues with legacy code. Explain to them when you need more time and cannot make the schedule they gave. Make a deal with them to release a stable version but lacking features that might take more time than they thought to do. Tell the users you had to no add in those features to meet a deadline or ask them if they want to wait until you figure out how to add in those features.

    #8 Play Sherlock Holmes and read books or Internet web sites on the language and technology used with the legacy code. Search knowledge bases and blogs and forums for answers to solutions, sometimes someone else figured out what you are trying to solve. If not ask on a forum or blog or web site and see who answers. Many of my answers got that way from the Internet on legacy code, but management didn't understand why I spent so much time on the Internet. It was because they wouldn't buy me the books I needed and I had no documentation or anything to work with except for pure code with no comments and all with serious problems. Sometimes I had to spend 5 hours a day researching on the Internet and 3 or 4 hours coding, but in doing so I saved months of work, but management didn't understand that each web site I went to was work related and I looked at the design of sample code even HTML code to get ideas on how to solve the legacy code problems. Sometimes you have to call up a help desk of a vendor to get answers as well, but they docked me for long distance calls to Canada where Crystal Reports and Segate/Business Objects had their headquarters. Fixing Crystal Report errors would make me spend 5 hours a day on the Internet just to figure out what caused double lines in a report and why only certain users got it and not others.

    #9 When in doubt ask for help. Sometimes another pair of eyes can spot errors and mistakes that you cannot see. Diversity is a good thing with team members. Form a dream team of programmers of different backgrounds for best results.

    #10 When in danger, when in doubt, don't run in circles and scream and shout. Take a walk, get something to drink and relax. Take a mental health break instead of getting angry at other people for not helping you or not doing their jobs properly, they might be suffering from stress like you are and you don't know it. Be positive, not negative.

    --
    Remember, Slashdot does not have a -1 disagree moderation, and no, troll, flamebait, and overrated are not substitutes.
  35. It is easy to test procedural code by lopgok · · Score: 1

    Though it is hard to test spaghetti code, it is hard no matter if the code is procedural or object-oriented. If you have reasonably well written procedural code it is easy to unit test. For C, there is http://cutest.sourceforge.net/ a very simple framework. Lets say you just wrote super_sort. You can write tests to test it with random input, sorted input, reverse sorted input, big input, small input, and the like. If you ever break super_sort, you will find out as soon as you run your unit tests. IMHO, linear algebra may be complex, but there is generally no state. Purely procedural code is fine for it (though C may not be). There are many simple as well as complex things that have no internal state, and will not benefit from object orientation.

    1. Re:It is easy to test procedural code by stephentyrone · · Score: 1

      If you ever break super_sort, you will find out as soon as you run your unit tests.

      Unless you break it in a way that the tests don't exercise. To be perfectly clear, let's suppose your "super_sort" only sorts two doubles. Even for this extremely limited sorting problem, there are 2^128 possible inputs. If you can test one input per cycle on a 3.2 ghz machine, it will take you only... 3371963459626879434053 years to completely test the input space.

      IF YOU'RE LUCKY, you will make really really obvious mistakes that break almost all inputs, and your tests will find them. You won't always be lucky.

      I'm not saying that you shouldn't test things. Just don't suffer from the misapprehension that tests passing is proof that the code works.

    2. Re:It is easy to test procedural code by lopgok · · Score: 1

      The fine book said it was hard to test procedural code. I was replying that that was false. Clearly you can't test for every possible input, but that isn't what I was addressing. Nor did I ever claim that you could test for every possible input, nor the desirability of doing so. If I did have a function that took in two doubles, I would try some typical double values, 0, and some corner cases. Only a mo-ron would think to test for every value. If I was doing white box testing, I would carefully look over the algorithm used, and try to find values to exercise all the conditions of the code.

    3. Re:It is easy to test procedural code by stephentyrone · · Score: 1

      I'm not arguing with the approach to testing you describe, I'm just pointing out that your statement

      If you ever break super_sort, you will find out as soon as you run your unit tests.

      is false (or wishful thinking, whichever you prefer).

  36. Legacy Code by devnullkac · · Score: 2, Insightful

    Feathers' definition is 'code without tests.'

    I'll do you one better: Legacy code is anything developed under a different process than you're using now. If all you'll ever do is TDD, then Feathers' definition is fine. But if, like me, you've seen a dozen major development philosophies come and go and be refined over the years, you know that TDD will eventually be supplanted. The only thing that remains constant in the recognition of difficult maintenance is this: "We didn't plan to maintain it the way we're maintaining it now."

    --
    What do you mean they cut the power? How can they cut the power, man? They're animals!
  37. Re:Not Object Oriented. How Do I Make Safe Changes by Anonymous Coward · · Score: 0

    Um, you're a moron. Online??? Yeah, that's authoritative! Check the STANDARD itself! See 5.1.2.2.1 "Program Startup." The only standard forms are "int main(void)" or "int main(int argc, char *argv[])" or equivalent, such as "int main(int argc, char **argv)"

  38. Where's the software? by Anonymous Coward · · Score: 0

    Feathers defines "Legacy Code" a bit different than you may expect. Feathers' definition is 'code without tests.' Agile programming seems to do this a lot, redefine things till they are happy.

    Your code doesn't work? Write Unit Tests. Code still doesn't work? It's because you didn't write "adequate" tests.

    In the end you've redefined everything, but you still haven't solved any problems.

    When I started out there were two books an structured programming: Constantine and Yourdon, and Page-Jones. There were a few other books on quality programming: Software Tools, Weinberg, etc. later there were other OO books, but still two main books: Booch and Rumbaugh. There were other OO methodology books (Bertrand Meyers, Wirfs-Brock etc ), but they were this diverse group throwing out different ideas.

    Now we have tons of Agile books all written by the same clique. But what software have these guys produced? Seems to me that the main purpose of "Agile programming" is to sell books and consultancy classes.

    Before you buy Feathers book, I suggest you ask yourself this. Has he been a major contributor to the linux kernel? To Emacs? Eclipse? Mozilla? What software has he written? What do coders whose work we see like Raymond and Stallman think of these guys?

    And if Agile is so great, why aren't they writing
    some the great software out there?

    1. Re:Where's the software? by Anonymous+Brave+Guy · · Score: 1

      You make good points, but your choice of comparative examples seems a little ironic. If you're going to have a dig at people who make their money from talking rather than writing code, aren't Raymond and Stallman exactly the kind of person you're criticising?

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  39. Definition of 'Legacy' by PPH · · Score: 1

    ...is anything you don't like.

    I've seen the term thrown around by VB programmers trying to make sense of COBOL or Fortran code. Or IT departments that were going 100% Windows using the term in reference to anything other than a Microsoft product.

    To be accurate, it should refer to code (or anything) developed under some other design and maintenance methodology or process than that currently used. That doesn't mean it is bad, old, or untested. In fact, it might be better that the crap you write today.

    I used to work for an outfit that did a lot of avionics testing. Back in the old days, the engineering department (the people who build the aircraft systems) designed and built a set of ATE equipment (redundancy noted). One component was a natural language to test code translator. We'd feed in the systems specs written in English (or more often Engrish) and the translator would spit out executable code. The module worked well, was easy to maintain and modify. I was brought in rather late in its life in the company and had no trouble understanding it. But then management mandated all software maintenance to be done by our information systems group (people from the finance department). Since they had no skills in natural language recognition, they just labeled that function 'legacy' and as a result unmaintainable. Their solution was to have the engineering department learn VB and code the ATE tests by hand.

    --
    Have gnu, will travel.
  40. Great book by IcyHando'Death · · Score: 4, Insightful

    I don't know how many of those leaving their pessimistic comments here have actually read this book, but I have. It's actually been on my to-do list to write a book review for Slashdot myself. Long overdue, I thought, given that the book was published in 2005. Now I'm sorry I didn't get around to it, because I think this reviewer, though positive about the book, considerably undersells it.

    To those of us stuck doing active development on old, ugly code, every day can feel like we are slogging deeper and deeper into a swamp. Each time we hack in a new change, it makes us feel unclean. We are ashamed of the ugliness of the patch work we are adding to. We know programming used to be fun, but only rarely do we feel the echoes of that now. Mostly we feel dejected. And we've lost our motivation because we are not putting out code we are proud of.

    If any of that rings a bell with you then grab Michael Feathers' book the next chance you get. A previous poster said something like "get Martin Fowler's Refactoring book instead", but he's entirely wrong. Not that it isn't a great book, but it won't save you. I've known about refactoring for years without being able to put any of it into practice. The prerequisite to aggressive refactoring is a good set of automated tests, and my projects have not only had no tests, but have seemed down-right untestable.

    WELC is your map out of the swamp. And it's a map drawn by someone who has clearly spent a lot of time guiding others out. Feathers knows how tangled your code base is. He knows it doesn't have useful documentation or comments. He knows you are under time pressure but afraid to break funtionality you don't even know about. He has seen it all and he knows how discouraging and hopeless it looks. But he knows the way out, and he'll patiently and calmly
    guide you as you break your first dependency, get your first class into a test harness or write your first test case. And before you know it, you are standing on a little patch of solid ground.

    Take my advice. Get this book, read it, and put it into practice. It can change your (work) life!

    1. Re:Great book by Lukiano · · Score: 1

      To those of us stuck doing active development on old, ugly code, every day can feel like we are slogging deeper and deeper into a swamp. Each time we hack in a new change, it makes us feel unclean. We are ashamed of the ugliness of the patch work we are adding to. We know programming used to be fun, but only rarely do we feel the echoes of that now. Mostly we feel dejected. And we've lost our motivation because we are not putting out code we are proud of.

      Gee! I'm feeling this way in my new job that I have now. I don't like it! I feel I'm wasting my time while I could be doing more interesting things. Right after I graduate I'll try as hard as I can to get a job where I don't have to do what you have described (And I'd like to say, no matter how well-paid it is).

      I'm still young I think (just turned 28) and I want (hope) to work in stuff I feel good about.

  41. Re:Not Object Oriented. How Do I Make Safe Changes by mrchaotica · · Score: 1, Informative

    Pedantic (but this is Slashdot): "int main()" is not one of the valid forms for "main" allowed by the C standard

    ...

    The only standard forms are "int main(void)"...

    "int main()" and "int main(void)" are the same thing, you idiot!

    If you're going to be pedantic, at least try not to fuck it up!

    --

    "[Regarding the 'cloud,'] ownership was what made America different than Russia." -- Woz

  42. Avoid the specialist books at first by Anonymous+Brave+Guy · · Score: 2, Insightful

    While I completely respect your desire to learn, I advise against rushing out to read a whole book on the subject straight away.

    The reason I say this is that unit testing is really a very simple idea: you should try to design your code so that you can test each module independently; implement simple, self-contained, automated tests for each part of the interface functionality; and then run your set of tests frequently, ideally between each change you make to the code. This certainly isn't foolproof, because it relies on having a good, comprehensive set of tests and usually it's impossible to cover everything. However, you can still help yourself to find most bugs quickly, and to identify very accurately and immediately where they come from, by using a good test suite. Of course there are some useful ideas and techniques that can help you to do these things more efficiently and reliably, but the basic principle is always the same.

    People write whole "frameworks" to deal with this stuff and some books discuss them, but IME these frameworks are in that category of libraries that everyone seems to write but no-one seems to use. It is often simpler and faster to write your own that fits exactly into your particular project than to learn someone else's, create a dependency on external code, and then adapt it to your specific needs anyway.

    Likewise, people write whole books on software development approaches like Test Driven Development, which are heavily based on unit tests. However, while there is plentiful objective evidence that quality can be improved by using unit tests, there is precious little beyond anecdotal evidence that anything other than consultants' incomes is improved by adopting TDD and the like. (If anyone disagrees with this, please spare us all the rant unless you can cite verifiable data to support what you're going to say.)

    There are some good comments on unit testing in general software development books such as Code Complete, which you might find interesting and useful. But I advise steering clear of the specialist books on frameworks and methodologies built around unit testing, at least until you have enough experience to separate the snake oil from the real oil.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    1. Re:Avoid the specialist books at first by Spy+der+Mann · · Score: 1

      Well, right now my knowledge of unit tests is practically ZERO (30 minutes ago I didn't even know what a unit test was - I just had the general idea of "test everything that you can"), so I need a book or html article written with good examples so I can say: "Hey, I can do that in my code!".

      Any links you can recommend? (besides wikipedia which expanded my knowledge a bit)

    2. Re:Avoid the specialist books at first by Anonymous Coward · · Score: 1, Informative

      TestDrivenDevelopment on the original wiki (Ward Cunningham's). And a lot of the stuff it links to, and so on....

  43. Throw away good CS concepts, why dont you ... by goose-incarnated · · Score: 2, Informative

    "... When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything."

    Wrong.

    --
    I'm a minority race. Save your vitriol for white people.
    1. Re:Throw away good CS concepts, why dont you ... by Todd+Knarr · · Score: 1

      Agreed. The tests will tell you if you broke anything they test in a way they test for. In any real-world application, though, you end up with untested and untestable interactions between components. Worse, you end up with errors that aren't bugs in the implementation, they're bugs in the component specification. The tests pass because the component's doing what it's supposed to do, but that causes the entire system to fail when you get to integration testing because what it's supposed to do isn't what it needs to do. That's why programmers have the term "broken as designed".

    2. Re:Throw away good CS concepts, why dont you ... by ebuck · · Score: 1

      Nice comment, care to back it up?

      Good tests are tests that verify the required functionality of the unit, bad tests are tests that verify things that cannot break or are the functional equivalent of the human appendix.

      Exactly how would you preform good unit testing in such a way that you could change the code in a critical way and not have it break? I know it seems like an easy cop-out to say it, but if you could do such a thing, then your unit tests are incomplete as they don't test the required functionality.

      That's not to say that you don't still have to do integration testing, acceptance testing, performance testing, usability testing, etc.

  44. Re:Not Object Oriented. How Do I Make Safe Changes by JesseMcDonald · · Score: 1

    "int main()" and "int main(void)" are the same thing

    In a function definition that is correct. In a C prototype, however, the former is "a function with an unspecified parameter list returning an int" and the latter is "a function with an empty parameter list returning an int", so they aren't the same thing in all circumstances.

    If "int main()" was a permitted signature (type) for main, any function which returned an int would be valid regardless of its parameter list.

    --
    "The state is that great fiction by which everyone tries to live at the expense of everyone else." - Bastiat
  45. Re:Not Object Oriented. How Do I Make Safe Changes by Anonymous Coward · · Score: 0

    WOW, where did you learn to program??? In C, "foo(void)" mean foo takes no arguments. "foo()" means foo take an unknown number of arguments of unknown types. The former is a prototype, the later is not. They are equivalent in C++, but no one was arguing that. If you're going call someone an idiot, at least check your facts first!

  46. And if you believe that.... by Anonymous Coward · · Score: 0

    "...then code can be changed at will and the tests will tell automatically you if you broke anything"

    And I have a bridge in Brooklyn I can sell you too.

    My favorite incident with unit tests was our company's first "agile" project. All the unit tests passed, and you still couldn't delete a named user account.

    Unit tests are fun to write, easier than other forms of testing, appealing to developers, and completely inadequate to test any target application.

    Sorry, but I've been testing for 15 years. Unit testing is good and has it's place, but I'm leaving the rest of the Kool-aid in the pitcher, thanks.

  47. You forgot the NAZIs... by Giant+Electronic+Bra · · Score: 1

    And you have to escalate properly, so it is like:

    11.)???
    12.)NAZIs
    13.)Cthulhu
    14.)D100 san loss

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
  48. That is exactly what TDD avoids by Giant+Electronic+Bra · · Score: 1

    You in fact made a perfect case for the argument that the code SHOULD have been developed test first, because then all the interdependencies you describe would not exist. Instead your application would be properly designed to be composed of a number of modules which operate independently of each other and only expose well defined interfaces which are ALL tested.

    It may well be that when a complex application is being developed you may find that there are several 'layers' of abstraction, and testing some of the higher layers MAY require mocking components to which they delegate functionality, but then the same thing should hold, the lower level code should be so modular and maintain so little state that it should be quite simple to mock. If it isn't then the fault is not TDD, it is the design of your code.

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
    1. Re:That is exactly what TDD avoids by Anonymous+Brave+Guy · · Score: 1

      You in fact made a perfect case for the argument that the code SHOULD have been developed test first, because then all the interdependencies you describe would not exist.

      That's lovely, but what if the dependencies are implied by the requirements, rather than introduced artificially through insufficiently modular design? It doesn't matter what development process you follow, you still don't get to rewrite the requirements when they are inconvenient.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    2. Re:That is exactly what TDD avoids by Giant+Electronic+Bra · · Score: 1

      In my long experience of writing complex applications I have yet to encounter a situation where the requirements forced me to write code which wasn't modular. I am not at all sure what the conditions would be where that is true.

      I can only surmise that the model/metaphor was poorly chosen or not well mapped onto the requirements. This kind of thing is one of the big issues with strict 'top down' waterfall style development, and one of the reasons it is slowly but surely being abandoned. The expectation is that some 'analysts' will have by some process nailed down EXACTLY how everything is going to work. That is at variance with reality, nobody really knows how a large piece of software is going to work at the outset. The system architect probably has a pretty good general idea in mind, and any number of constraints could be defined, use cases, etc. But these projects often fail simply because someone writes up some thing that says 'The foomazoo SHALL perform the calculation' and it turns out, that was a horrible way to structure the software. Thus things like agile development...

      Of course you may not be in the position to design an individual module when you're part of a larger team, or it may be legacy code, etc. Some code truly is not testable, but that is as I have said before a problem with the CODE not the concept of TDD.

      --
      "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
    3. Re:That is exactly what TDD avoids by Anonymous+Brave+Guy · · Score: 1

      I can only surmise that the model/metaphor was poorly chosen or not well mapped onto the requirements.

      Well, OK, perhaps you've never experienced it, but that doesn't mean it doesn't happen. What industries (in terms of application domains) have you worked in? The sort of thing I'm describing is not unusual when doing serious mathematical modelling and scientific data analysis, for example, where the underlying mathematics may be non-trivial, particularly once floating point and numerical analysis issues get into the picture.

      Of course you still try to make the code as modular as possible, but if your basic building blocks only have any significance when combined together into a more meaningful whole, the basic level of testing effectively becomes low-level integration testing (or, if you prefer, unit testing of the combined modules at the point that they become self-sufficient). You can still apply unit testing principles to the building blocks, and it can still help to prevent "silly" errors, but in this sort of context, low-level unit tests alone can't provide that level of confidence that is so valuable from unit testing a more fine-grained modular design.

      --
      If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
    4. Re:That is exactly what TDD avoids by Timothy+Brownawell · · Score: 1

      You in fact made a perfect case for the argument that the code SHOULD have been developed test first, because then all the interdependencies you describe would not exist. Instead your application would be properly designed to be composed of a number of modules which operate independently of each other and only expose well defined interfaces which are ALL tested.

      I thought "Big Design Up Front" was supposed to be bad?

    5. Re:That is exactly what TDD avoids by tuomoks · · Score: 1

      Actually it seems that people on this thread are saying the same thing put looking the solution from different directions. And of course there are different issues, not so much "code correctness" but forced by OS, subsystems, interfaces, etc. And also especially in numerical world - small differences which are under level you can catch in unit tests can through the whole system upside down. Seen that and sometimes very difficult to find the culprit. Seen that in some financial applications too - big ones, small are usually easy. Seen that in memory managers, protocol stacks, etc.

      Anyway - I agree that any system can be designed to be modular, the "core", be it OS or a subsystem can be tested and every "server". "process", whatever should be easily unit tested. Now - it is not the way people are educated, trained or even required to design today? Today the method is to create millions of APIs, methods, objects, etc instead of few, simple, well tested interfaces so testing requirements have grown exponentially - unit testing something which has one input / one output is easy to automate, try it with a huge number of combinations, objects, methods, etc which may or may not be depend and/or controlled by some other application, subsystem or even other OS in case of virtual systems!

      TDD is good but the whole system has to be designed for that and (just!) for example .NET (and other such!) makes it a little more complicated than it has to be. Too many intricacies in "subsystem" and you don't know where they are, how they work, what and how they try to "manage"! Real problem especially for performance and performance is a definitely a quality parameter - often very critical one. And of course, their behavior changes from version to version?

  49. Sure, except that by Anonymous+Brave+Guy · · Score: 1

    They're not, though, are they? We write documentation that is separate from code, because code is usually a poor place to provide overviews or describe the details of models and algorithms being implemented by that code. Automated tests are just more code in some form or another, and they have no special pass on this.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  50. I disagree by Giant+Electronic+Bra · · Score: 1

    Software is not like hardware. Software is much more plastic and it is very often not obvious what the best design is. TDD allows you to build your components one small step at a time, this is the heart and soul of agile development. It also has to integrate with other principles like having a good model/metaphore. If the model is well thought out, then small low level code modules can be developed to adhere to a fairly simple and straightforward set of tests. This feeds into the concept of short iterations where only a very specific set of functionality is built into the code during any one given iteration, thus allowing you to focus on that one thing.

    The code written in iteration one may not be capable of addressing the requirements of iteration two, but you CAN now refactor it because you can now test it, and you will find it will be MUCH MUCH easier to test because you were forced to build it to BE testable. Testability needs to be a fundamental attribute of all code, probably the single most critical attribute.

    Software is nothing like a product coming off an assembly line. You don't 'duplicate indefinitely'. You construct a module of code and if it is developed correctly according to an agile methodology it WILL be highly reusable, but you should never expect a particular piece of code to function correctly in any old environment. On the flip side every time your code is operating in the environment it IS designed and tested to operate properly in, it should function correctly, or fail gracefully.

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
  51. Re:About how to move from bad design to good desig by Anonymous+Brave+Guy · · Score: 1

    Challenge 1) Create a good design from scratch. Lots of folks can do this.

    I wish I worked in your world! In mine, lots of folks think they can do good design, but most haven't the first clue about what good design is.

    --
    If you disagree, post your argument. (-1, Overrated) isn't your personal censorship tool for views you don't like.
  52. You're still going too far by Xtifr · · Score: 1

    The tests will tell you if you broke anything they test in a way they test for.

    You're still going too far. The tests will tell you if you broke anything they test in a way they correctly test for.

    You can be confident in the knowledge that the tests do indeed test the changes you're trying to make, and discover (after much hair-pulling) that your changes now tickle an obscure bug in the tests. This may result in the tests claiming your code is broken when it's not (the good case) or that your code works properly when it doesn't (the evil case).

    Of course, we were supposed to assume that we're dealing with good tests. Heck, if we're going to assume impossible things, why not assume that the code works in the first place, so it doesn't need testing! :)

    I'm a big fan of testing, especially automated unit tests and regression tests, because they mean that you need to make two matching errors to actually let an error slip through. But I also don't assume that "pass the tests" == "working code". You still need to make readable, maintainable code so that when the whole thing blows up in your face, you still have a slight chance of being able to fix it.

    My biggest complaint about the whole TDD crowd is that they seem to think it doesn't matter of the code is maintainable--as long as it passes the tests, it's magically ok. Like a lot of movements, TDD/XP/Agile is a collection of good ideas being marketed as a silver bullet. TANSB. :)

  53. Re:Not Object Oriented. How Do I Make Safe Changes by Anonymous Coward · · Score: 0

    Imbecile!

    Mod parent down for not following convention. The convention in this tread is to call the parent a name and every other post should be AC.

    Noobs!

  54. tests make good code? by Uzik2 · · Score: 2, Insightful

    "in the TDD world, tests are what make code easy to maintain. When good unit tests are in place, then code can be changed at will and the tests will tell automatically you if you broke anything."

    Isn't this a rather ambitious claim? I've seen many systems with lots of tests with bugs not caught.

    --
    -- Programming with boost is like building a house with lego. It's a cool but I wouldn't want to live in it
  55. Yes, it is a great book. by ebuck · · Score: 1

    The only way a reader can read this book and not come away with a pocketful of gems is lack of experience or so much experience that the book bores him. Experience in this case isn't tied to years of programming, it's tied to having to fix truly horrid messes.

    This is one of the best introductions into managing a code base that is foreign, hairy, and incomprehensible. I've been doing maintenance programming on and off for years now, and while it's not as glamorous as clean slate design, it's much more difficult.

    Fowler's Refactoring gives you the transformation templates, just like Design Patterns gives you the code structure templates. This book gives you the instruction into code maintenance discipline. It's well worth a read, even if it leaves you wanting in a (very) few places. Don't think of it as "Refactoring for Dummies", it's more like "How to use Fowler's books in an enterprise and not go insane". Naturally there's a little duplication of information, but that's not the point of the message.

    There seems to be a bit of an anti-testing crowd reacting to passages in the book. While I understand their gripes, let me assure you that either you're going to test your code or the customer will. If the customer finds too many, then you've squandered your good will in exchange for not writing tests. Not a good exchange in my opinion.

    Another book along this line that I also highly recommend is "Software Exorcism" by Bill Blunden. Perhaps his quirky humour and old school usenet references will throw off a few acolytes, but there's plenty of treasure in there.

  56. "Topper" thread by Zoxed · · Score: 1

    (I browsed at -1 but could not find a Topper thread, so I have started one!)

    > One caveat is that most of the book is focused on working with object oriented programming languages.

    Hokum Pokum new fangled OO: we support various Mission Critical legacy systems with FORTRAN-77, K&R C; we've only just leapt from VAXes to Alphas, and are moving from Solaris 6 to Solaris 8 (all forced us by non-supportive suppliers). Having said that one of our systems does have one of those new-fangled Web interface thingies, but we try not to touch that :-) Oh, and some of our new hardware came with 2 (two) CPUs, so we switched one off in order to avoid a new class of bugs !!

    But I am sure other Slashdot Old Farts can do better than that ?

  57. There is a difference by Giant+Electronic+Bra · · Score: 1

    between 'no design at all' and what agile methodologies advocate. In XP methodology for example you would first develop your system requirements in the form of user stories. Those are used to prioritize features, then you engage in a series of iterations, each one adds certain features. Another tool you use is a system metaphor or model, which provides a way of reasoning about the overall system architecture.

    Any given iteration only deals with those requirements which are assigned to that one iteration. Code is written (tests first) to accomplish the requirements of that iteration, and the customer supplies a set of functional tests which verify that the software meets those specific requirements.

    During later iterations new tests will be written and either more code written or existing code refactored and extended to add the additional features. More functional tests are developed as well, and the added features plus the existing features are all tested for compliance to the new requirements.

    There is no single overall design 'phase'. There could be various points at which the large scale features of the system are fleshed out. In some cases a 'spike' might be used to explore different options. Spike code is considered throw away and simply allows you to determine which of several designs are likely to work best. Usually there will be some specific 'problematic' areas (say 'how can the system achieve the required latency requirements') which a spike would address.

    The whole philosophy of agile development essentially rests on the observation that even in what are supposedly more 'up front design' type methodologies that the real shape of the system ends up being determined over the process of development. It is like applying the 'Wu Wei' concept of Daoism to software, don't fight the way things REALLY flow. Waterfall style development is a myth, and pretending it isn't is just paddling upstream.

    --
    "Malo periculosam, libertatem quam quietam servitutem." -- Jefferson
  58. Definitions by lwriemen · · Score: 1

    Legacy code is any code that a software developer "inherits". i.e., the developer didn't write the code, but is in charge of maintaining it.

    TDD is also called analysis. It forces the developer to think about the requirements and how to verify the implementation meets the requirements. Unfortunately, this is bad testing, because the goal of software testing is to verify that the software is incorrect. This is why it has been well documented that someone other than the developer should write and execute the tests. It's hard for the developer to take off the white hat and put on the black hat.

  59. Unit Tests in procedural code by angel'o'sphere · · Score: 1

    But in the book he states that "the number of things you can do to introduce unit tests in procedural languages is pretty small." Unfortunately I would have to agree with him on this point.

    Sorry, but this makes no sense.

    In a procedural language it is easy to stub/mock away stuff that you like to be "outside" of your tested unit.

    E.G. if you have a "unit" that calls a function/procedure f() and the function f() returns an int ... it is very easy to provide a mock/stub function f() that returns the exact number you need/want in your test.

    In oo languages, you are usually call a method g() on an object "o" with type "t". But you don't know/can not determine/can not predict if the object is of type "t", or "t2" or "t3".

    So you can not "reliable" stub/mock g() ... so a unit test calling g() is very difficult to craft in oo languages. Unit testing is very simple in procedural languages. You know unit means: FILE. We only test one single f***cking source file. In C/Pascal etc. that is a piece of cake, in C++/Java etc. it is utter shit and hard to do.

    angel'o'sphere

    --
    Cost free eBook I read (by iBook/Kobo/Amazon/ObookO/Gutenberg etc.): "The Green Odyssey" by Philip Jose Farmer.
  60. Agreed, and summed up as... by aug24 · · Score: 1

    Modularise, modularise, modularise.

    If you can't describe what a function does in a reasonably short function name, then it needs to be broken up.

    Justin.

    --
    You're only jealous cos the little penguins are talking to me.
  61. Re:Not Object Oriented. How Do I Make Safe Changes by hesaigo999ca · · Score: 1

    If fixing code, just put it inside a REALLY BIG try catch and put an exception for all the types of errors that are presently bugging the system, this will be good enough for a promotion until you get to the next job and move up the ladder....let the guy after you figure out how to proceed.... :P

  62. I get it! I get it! by Anonymous Coward · · Score: 0

    I just comprehended test-driven development. Enlightenment after all this time of wondering feels GOOD. TDD is for developers who are unable to perform the task of analyzing code, period! This whole system is tons of overhead just to make sure the developer is working in a tiny little box where nothing can go wrong. Well, those of us WHO ARE COMPETENT no not need to spend hours building useless safety rails. I require of myself that I fully understand the ramifications of any code changes I make. This helps me understand the entire code base better and is the sole, I repeat sole, path to possessing guru level knowledge of the code.

    So go ahead and work in your TDD prison cell if you like it, fool. You'll never leave.