Possible Duplicate:
I’ve inherited 200K lines of spaghetti code — what now?

Not long ago my company placed me in a team that deals with some of the most complex bugs that are in production. The thing is that almost all of these bugs are in legacy applications I am having a really difficult time understanding and debugging, and these are some of the reasons:

  • Bad software design

  • Lots of code duplication

  • Misleading comments

  • Bad names

  • No documentation at all

  • The creators of the software no longer work in the company

  • Really big classes and methods, very badly programmed

  • Bugs are very badly documented and the operations team makes very poorly documented reports on the issues that occur.

It is very time consuming and frustrating. As a TDD and ATDD developer, I try by starting writing tests to triangulate and pinpoint the problem, but there are so many things that need to be mocked that it is very difficult. Also the business analysts don't provide criteria for this software since they don't even know it themselves. The only thing they say is that it needs to be fixed.

I thought that maybe here I could find somebody with experience in legacy software that could give me some advice on how to deal with bugs in an environment like this. I feel I am doing software archeology when working with this. Also it is very stressful and this big amount of frustration makes me feel useless and unproductive since it takes weeks sometimes to fix bugs. I always worked green field development and this is the first time I am doing production support. I would really appreciate some advice.

  • 7
    Have you read Michael Feathers' Working Effectively With Legacy Code? It's specifically a TDD approach to big balls of Java and C++ mud like your legacy application. I didn't find the book all that useful myself, but that was because I had to deal with a monster C program that had to stay in C.
    – librik
    Dec 30 '12 at 23:35
  • What sort of bugs are they?
    – James
    Dec 31 '12 at 3:45
  • 1
    @ximiki thanks for your comment and also for the other comments. I completely forgot about this question, it was long ago. I only have 600 characters so I will try to say it in the most concise way. I have learned to try to stay away from companies that are not embracing the principles of Agile. Those that I describe were in a company where there as no a good culture of team work, everything was being thrown over the wall and managers tend to micro-manage. A bit later I will discover that not every IT company was like that. There are Agile companies...
    – sfrj
    Feb 5 '20 at 21:52
  • 1
    @ximiki What would I do differently if i started that project again? First try to get more involved in early stage and understand what is the minimum set of features the company needs. Develop a "walking esqueleton" of the app. Add ACC to each features. Agree with my colleagues on some coding conventions. Do more pair programming. Try to deliver frequently and follow the ticket all the way down to production rather than throwing it over to the QA's. Mandatory retrospectives and make sure that those are well facilitated so the team can make meaningful decisions...
    – sfrj
    Feb 5 '20 at 21:59
  • 1
    @ximiki ... I would avoid cluttering the app/s with tons of frameworks(I would try to find balance). I would avoid making shared libraries for the whole company that later are not maintained properly. I would like to have a well written READ.md file than a thousand documents in internal wikis and shared drives. I would make sure that all team members are trusted equally and that we don't have bottlenecks due to only some developer allowed to do certain tasks. I don't know if I am forgetting anything else. My view how a project should look are on the lines or respecting the Agile manifesto.
    – sfrj
    Feb 5 '20 at 22:04

You have hit the nail on the head - What you have complained about is the definition of "Legacy software". Working on this class of software requires a different mindset to Green-fields work. Your stress is a result of you measuring your progress against unrealistic measures.

Don't try to put todays ideology on yesterdays work. If it was not designed around TDD and UT, then retro-fitting Test driven methodology is a major, expensive and difficult undertaking. As you are finding - shoehorning todays silver bullets into yesterdays failed silver bullets is far from the ideal way to work. If carefully though through, with clear understanding of goals and benefits, it can be worth while. However, it quickly devolves into negative returns. Go for the "low hanging fruit" and develop tests only if it clear they will be used many times and find many defects.

The best approach is to remove unrealistic expectations. Productivity will be low, code hard to analyze and faults hard to fix. Unexpected side effects of changes are likely, and as you have found, regression testing non-existent- Maintaining Legacy code is slow and hard - thats why so many developers run off to Green Fields projects. I can be rewarding, but only if you reset your expectations.

When you start work on a defect, start by staying focused on three things - What the code does now, not introducing unexpected side effects and what it should do when fixed. You may find that "code duplication" is better than "unexpected side effects"..... Without decent tests and requirements, introducing regression is often the biggest sin of all.

Always strive to leave the code in a better state than you found it, but be careful not to change its behavior except where required.

  • I like this answer, thanks for sharing. So what I need is change my way of thinking, makes sense. Do you think TDD is not the way to solve the problems always? You just said it, we have no regression testing and the software is very vulnerable to brake when the changes. This is why I put big enphasis on trying to go TDD, but is really difficult. In what regards to leaving the things better than I found it, I completely agree, but TDD rule says that only refactor if you have code coverage, so making little changes involve big programming effort.
    – sfrj
    Dec 31 '12 at 10:19
  • Until a decade ago, coding for testability no common. If the code was not designed to be testable, the design is wrong for adding tests, making it hard - as you have found. In this case, TDD is the wrong approach. Without regression tests (TDD is just one way to achieve this), refactoring is very hard - there is no way to know that you have not broken things. With manual tests, it is expensive run a full regression test suit. It is therefore critical that you take it slow and methodical when making changes.
    – mattnz
    Dec 31 '12 at 20:38
  • Yeah, that is what I will do, I will take it easy do as much as I can and try to be precise. It would be great if management take the decision to re-write some of the legacy apps from the scratch, but I don't see that happening any soon :)
    – sfrj
    Jan 2 '13 at 1:24
  • ... re-write from scratch .... I really do hate to bust your boiler, but thats #1 on the things not to do - do a quick search on this Q/A on the topic
    – mattnz
    Jan 2 '13 at 4:54

This is always a frequent area of debate at user groups and conferences I attend. The best advice I've ever heard is this:

For new, well tested code, the tests are the source of all truth. For untested, legacy code, the codebase is the source of all truth. When adding a new feature, write solid unit tests. When addressing an existing module or fixing a defect, test as best you can, to avoid regression. Take your time, keep calm, and carry on.

That's clearly a paraphrase of a few well-honed perspectives, but the core is this: the codebase is clearly 'broken', but the functionality isn't and that's what users care about. But if it becomes completely unmaintainable, and you have an idea about how to re-implement functionality quickly and sanely, it might be time to bring up the possibility of the dreaded 'big rewrite'.

I admit that I'm in the camp that says the big rewrite is never a good idea, until it is. You, your team, and your customers will have to discuss and negotiate if or when that time has come. Best of luck, it's a terrible situation with no one correct solution. I should know, I've been there before a few times.

  • 1
    +1 for "the big rewrite is never a good idea, until it is." This is such a hard concept to get across to developers, new or old. And quite frankly, it is a decision that your technical manager should be a part of -- because it may represent an opportunity to go in a new direction, or it may go down a road that no longer is part of the company's real future. Dec 31 '12 at 5:22

This is slow work. Be patient. Your colleagues are probably the best source of information available. As you gain knowledge, add comments so the next guy won't have to relearn what you already know.

This work is not a lot of fun, and doesn't do much to advance a career, so you should be paid more than you would get for new development. I would probably not take on work of this type as a salaried employee. I would want to get contractor rates including overtime for the many "emergencies" that are sure to arise.

  • 1
    very good advice, I will keep that on mind :) I suppose now is late to negotiate. Hopefully I will be in this situation just a few months, but next time I will know.
    – sfrj
    Dec 31 '12 at 10:30

Learning how to read and understand other people's code is a huge part of being a programmer. Some of the code you read will be your own. It can be dangerous to modify code when you don't fully understand how it fits into the whole. Introducing unit tests and running them as part of some kind of automatic build system will help you keep the code they cover from changing behavior, but this means (especially with legacy code) that you have to understand how the code you're changing is used by the system.

It can be tempting to throw away code that seems to be too complex (or crufty, whatever that means) and rewrite it yourself. (Everyone wants to be the architect). The danger in throwing away old code and rewriting it from scratch is that you're also throwing away knowledge gained by time and hard experience that will usually be difficult to regain except by repeating the same mistakes and fixing the same bugs the original developers did over time.

Introducing TDD into (or on top of) a legacy system can be tricky. Be prepared to fix bugs in these tests as you will inevitably find inconsistencies in the code itself. Remember that your tests are not infallible. As you come to better understand the existing system, you will have to improve/fix them.


There is an approach that I found quite useful while working with situation similar to what you have described. Usually legacy code written in very monolithic and obscure way. But there's an interesting approach to start working with legacy code: approval tests. I'll recommend you to start with recording of golden copy and make sure that captured information contains values meaningful to your business. Next step, show that golden copy to business analyst. Usually, that are able not only to understand this representation, but also tell you what is wrong with those numbers, otherwise what are business analysts for? So now, you have both current result of program executing, commented by analyst, so you could safely start refactoring and bug fixing in your legacy code.

  • Thanks akim, this is interesting, this would be a BDD approach. Actually I am using this technique partially, using a framework called spock which is very similar to what you showed me in the link. The problem with this is that as I mention the business wrongly gives priorities and they don't know the value of the features of the legacy since they were not there when was first time created.
    – sfrj
    Dec 31 '12 at 10:27

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