44

I know there have been many questions regarding legacy code here; however I want to broach the human side of the issue. How do you deal with being made to work on a very messy codebase with tight deadlines and an absolute opposition to refactoring? Personally I find it incredibly difficult and that difficulty impacts on my productivity very badly indeed, and I get so incredibly depressed it is actually frightening (what a geek I am!).

How do people:

  • Remain productive?
  • Avoid getting horribly depressed?
  • Find a way to write decent quality code in a project absolutely toxic with awful spaghetti code?
  • Work around a terrible architecture that you are not being allowed to fix?
29 accepted

There is a definitive book on the topic.

Working Effectively with Legacy Code by Michael Feathers

which will give you techniques you can use to dull the pain, and slowly feel you are making things better. always good for the soul :)

22
  1. Start with a formatter. Format the code that you need to work in. Make sure that you check out the code first, format, check it in, then make modifications.

  2. Build trust. Fix small problems first (the low hanging fruit). Do small refactorings. Constantly remind people to fix potholes. Apply good engineering practices. Over time, people should start recognizing that good code produces better results in less time.

  3. Find out why the code/architecture is the way it is. If you know the original reasons for the design, people will be more willing to listen if they see that the new design better fits the old and new requirements.

  4. Realize that people don't want to change and will usually be offended if you think something they did was wrong.

16

I've been on the other side of this - as the evil manager who wouldn't let his team rewrite the legacy code. I can think of at least a couple of developers working for me who had the same issue as you, and got quite frustrated with the code. At the time I probably didn't appreciate how demoralising it was, though I can relate to it a bit better now.

Of course there is a reason why you are told not to work on refactoring, and I assume that it is because of a commercial/scheduling goal. So my advice is:

  • understand why the manager would think like this, and make sure s/he knows you understand
  • don't be too militant about it - make suggestions but don't insist
  • suggest a compromise - e.g. "if we hit this milestone deadline can I spend a few days over the following week refactoring such-and-such module?"
  • get some articles on the idea of technical debt (Steve McConnell's work is probably the best on this) and sit down with your manager - be clear that technical debt is NOT necessarily a bad thing, it's just that a balance has to be maintained. Discuss with your boss where the right balance is.

If you have a clear plan to deal with the ugliness and have confidence that it is going to happen, I bet you will be a lot less depressed. And if you and your manager each understand the (valid) reasons for the other's concerns, you will work together a lot better.

14

Unfortunately you have a single option. Resign and work somewhere else.

I realize it's a bit simplistic. However if the whole business model of your company puts speed to market and lowest cost, over quality, it's just the wrong sort of company for someone who takes pride in the quality of their work.

It's just not worth it if it doing your job well is important to you but you find yourself working on such poor legacy code that you are not even allowed to try to improve.

Psychologists say one of the most common causes of stress and anxiety is when we feel we do not have control over our environment or situation. I'm talking from experience.

On the more practical side, Working Effectively with Legacy Code would provide a good "action plan" for bringing the monster under control. Some of the approaches it describes are also things that you can implement "quietly" regardless of whether the company know or not. When improvements start to appear, who is going to complain about the process used to acheieve them?

14

The single most important thing when you're dealing with old, nasty code is a comprehensive test suite. If you have that, you can confidently start shifting code around, and refactoring even scary parts safe in the knowledge that your test suite will kick you in the pants if you break anything you didn't intend to.

Unfortunately, you don't always get a comprehensive test suite when you're presented with code like this. What can you do? Well, write one.

It may sound like a hell of a lot of work, but, trust me, it's worth every second you spend doing it.

You know when you write something, and decide you want to start again, the second iteration goes much faster than the first? Well that's what will happen when you've written your test suite. You've learnt the entire codebase (or, the section you're working on) bit by bit, simply by the act of writing the tests, and you'll find that the more comprehensive your test suite, the better you know the code, the faster you can identify problems, rewrite parts, etc.

Of course, you may not be in a position to do this, but if you can, I strongly recommend it.

9

I worked at a few places like that, and here's my take on what to do:

Remain productive: take each task as it comes, don't build more than what you absolutely need in order to complete the task, and try not to add more dung to the pile of dung that is already there. If your code is good, then at least there will be some good code instead of "none". Don't waste a minute worrying about how dumb the what they're asking for is, just build it the best way you know how, and move on to the next task. If you build up enough steam, you may get extra time at the end that you can use to pitch the idea of refactoring over and over until someone lets you do at least a little refactoring.

Avoid getting depressed: consider how many jobs are so much worse than programming. If you can get a job somewhere better, I'd go for it, but remember that a gross codebase is just one of many things that can make a job annoying. If it were all sunshine and roses, they wouldn't need to pay someone to do it. Again, take lots of notes to help yourself decide if the pros/cons are really as bad as they seem. On a good day, the notes may look different to you than on a bad day, that's why it's useful to realize what frame-of-mind can do to warp the perception of how bad things are.

Write decent code when the rest of the code is crappy/terrible architecture: One thing that makes crappy code look that way is the scattering of related functions. Try to keep everything together, so at least no one is hunting for needles in your code "haystack".

Just don't introduce more problems in your own code, and keep a log of when the existing codebase causes problems and how long they took to fix. That can be used to help promote the case for refactoring.

Note: sometimes code looks bad because it really is bad, and other times there are mitigating factors in why the code looks bad.

  1. The other programmers might not have been that stupid; instead they may have been forced to build something a certain way to achieve a certain effect.

  2. The code probably works, so in a sense it's "good enough" for the company.

When new developments come along, use the opportunity to fix anything from the old system that has to interface with the new component using the following reason: "the new version has features that just aren't 100% compatible, we just need to 'change a few things' in the old version to make it work right.' That should allow you a bit of wiggle room to at least refactor the output and input to the big ball of mud.

The more code you see in your life, the less any of it looks "all that bad", so hang in there.

8

Having confidence in understanding what the code is actually doing will go a long way in helping reduce stress.

Anyway, have a read of Diomidis Spinellis's excellent book "Code Reading" (link to web site) for lots of info about approaches and tools. This book won the 2004 Jolt Software Development Productivity Award.

I can imagine your pain, I once inherited 150kSLOC of code written in Ada that was truly horrendous, namely:

  • no formatting - at all!
  • indentation all over the place like a mad woman's breakfast,
  • full of variables with such fantastic names as X1, XX1, X_1, and XX_1, and
  • the single person who had written it was going back to the States and was uncontactable!

It had single functions that consisted of 30,000 SLOC and was so bad that the code formatter couldn't handle it and would core dump when attempting to pretty up the code. The pretty printer would crash out as well!

But over a period of two years, as I grew to understand the various pieces of functionality, I gradually:

  • renamed variables from the stupid meaningless ones, e.g. X1, to more meaningful names such as button_label,
  • tidied up the code layout,
  • created tests for pieces of functionality, and
  • refactored the pieces of the code I was touching arguing that I needed to do this to increase the ability to "test the code more thoroughly".

Unfortunately, I did this so well I later inherited another program which was written by someone who'd died three weeks after being told he had cancer.

This program was:

  • undocumented,
  • written in APL, and
  • only known as a black box to other staff members, i.e. we give it data in this form as a batch job and it is then transformed into the data that this bit of the system uses.

But I managed to rewrite it in Ada and the agency was very happy about it.

Oh. And both of these were components of a mission critical system for a major on-route air traffic control centre!

No pressure there, eh? (-:

4

A few simple (though not easy) steps:

  1. use the ghetto pattern: put all the ugly legacy code into a separate tree and import it.
  2. run Crap4J or an implementation in your language of choice; make sure the CRAP index is run every time your full test suite is run (at least every check-in).
  3. little by little, take pieces out of the ghetto and re-implement them in the main tree; your CRAP index will go down, and your tests will make sure you're not changing anything
2

The question you should first ask:

  • Is the deadline reasonable
  • Is your time constraint being low something that could have been avoided by management ( if you have a client whom has a contract payment set on your bosses head )
  • Is this the first time this has happened.

If this problem with the time constraint has been caused by miss-management, and management refuse repeatedly to adopt anything to actually make it possible to meet the deadline or define a reasonable deadline, then quit.

Some managers just do not learn, and repeatedly blame you the developer, for all the failings. You can provide thousands upon thousands of solutions to make your life easier, and get the job in on time. But some are just completely unwilling to learn, and just bitch-slap you when they get egg on their face because a client dropped the project on them.

Failing the above, there is not a lot you can do.

  • Making everyone else suffer because your suffering
  • Escaping the problem ( Quit )
  • Overcomming the problem, by:
    • Working harder
    • Working smarter

However, if you're not permitted to re-write code just so you fix the problem, this becomes not much of an option. If management refuse to give an inch so you can actually meet their demands, you're being their slave.

Don't be a victim.

2

I suppose it depends upon your co-workers to some extent.

If you're lucky enough to be working with people who also have to deal with an application that contains spagetti code and/or code that you can't even see (for example: ColdFusion files), then the best way to keep the depression away is to laugh it off.

If you're not that lucky, or even if you do, take it as a learning experience.

I personally have the pleasure to work with both types of code.

For legacy code that I can touch:

1) I make a game out of cleaning the code that I can code.

2) When cleaning code, I do before and after comparisions (even if I'm busy, file size and line count is enough) to see just how much I've trimed it down (assuming there's a lot of fluff code).

3) Do speed comparisons before and after.

For legacy code that I can not touch:

1) I stay as far away from it as possible :D

2) Again, take it as a learning experience. If you think about it, it's nice to know just how much you actually know.

Ultimately, you've got to stay positive. Maybe you're the only one that cares about how bad the code is, but that's a good thing to hold onto (pride in your work).

1

Become a freelancer!

Very messy code = loads of work = loads of billable hours! Oh and at least you won't be out of a job any time soon. Messy code usually means buggy software and each fix means you make someone happy. And if you deliver happiness on time you are reliable and people would like to keep you around.

If you're looking for an excuse to tell your boss to get real about the deadlines, turn it into a positive for yourself or quit!

1

One byte at a time?

Seriously, it will take a while, but by fixing every piece you touch (formatting in the very least) and providing software metrics around the before and after. Play up cost reduction in software maintenance and play down the term refactoring since it already has a bad reputation in your organization. Have a care to increase design documentation and point out complexities and areas for 'simplification'.

I have found it possible to win management over to restructuring releases after developing a track record of success making minor architectural changes reduce defects or improve performance. Pick your initial fights with care and think about presenting management with a fait accompli.

1

I agree with devinmoore's post but will add one more thing.

Spend some time everyday reading The Daily WTF (I like to check out the random articles myself) and you'll soon realize you don't have it all that bad. If you do, however, come to the conclusion that you are worst off, submit the code to Alex and feel better knowing you're helping some other poor sod laugh if off.

Start here: http://thedailywtf.com/Articles/The_Brillant_Paula_Bean.aspx

0

I echo the suggestion in here

Sam

0

Best way is to look at it as an intellectual challenge or adventure game and refactor where you can when you are working on a bug fix or enhancement. Also, it can be an area where job security is enhanced as in the old UK phrase "Where there's muck there's brass".

0

You'll get better understanding/maintaining skill over the time.

The first time you're thrown the spaghetti is probably the most frustrating times but after you begin to understand the underlying architecture, even how messy, your depression will lessen greatly.

The way I do it would be to mark a section of code that I write with certain symbols and work on those section of codes as if I'm writing an add-on to another program. And from there i know what part I can keep DRY and what doesn't belong.

I, however, doesn't believe that you wouldn't be allowed the fix the architecture, because I believe that you'll soon find a feature request/bugfix that would require changing the architecture itself.

If you still aren't allowed the change even when the fix requires it, then find a new job would be the best solution IMO.

0

I take a deep breath, remember a particular spiritual practice, and take the code as it is. If I'm truly not allowed to refactor, okay, but it takes extra time to grok what's there.

You just have to go in with a sense of cooperating with what's there instead of resisting it--not arguing in your head with the past developers. When you smell something wrong, make a note of it. Just say to yourself, "Wow, this could be a generic class, I'm feeling sort of annoyed at all the cut-n-paste," and maybe write it down.

The key thing that developers forget to do in these situations is to note their own emotional reactions (not stuff them) and deal with them in a detached way (not get upset about them).

0

One good way to deal with legacy code is to add unit tests to any code portion you've touched (bugfixes, etc). Turn that into some mini-refactoring to make the whole thing more testable, and over time you will get some test coverage of your legacy project that will enable you to do bigger changes if needed.

0

As an older engineer trying to make sense of some of the horrible situations I have been in, I will agree with Ash : resign and seek other work.

If you have been handed messy, poorly designed, and undocumented code with a deadline to get it working, you have been set up for failure and scapegoating.

If you are in a long-term situation with a company and leaving is not your best option, you must defend yourself on this. If they say "we had it working", demand proof or demonstration. If they try to pressure you to fix bizarre, killer bugs resulting from sloppy, asynchronous design (or, I should say, non-design), understand how you are being setup for blame.

The possible situations and variables on this are too numerous to discuss here now, but you must maintain yourself financially and psychologically to be able to just walk away fro this kind of scenario.

Imagine if you had a plumbing leak in a complex builing such as a sckscraper. You have no architectural plans, no plumbing or electrical schematics, no wire or pipe lables, no access to the leak, ec. etc. Now consider calling a plumber and saying : "We need this fixed asap, this has high managment visibility, you're ging to have to work nights and weekends with no extra pay while we scream at you and loudly abuse your name to management, and on and on and on while threatening to fire you and find someone else who can knows how to do your job."

What reaction would the plumber have? You need that attitude.

0

Old code may be messy, but it works. Or at least, it works well enough that nobody's found any bugs in it worthy of fixing.

Refactoring, or even reformatting, carries the risk of introducing bugs. Handle it like a precarious pile of fine china - don't mess around, particularly near the bottom. If you need to do something, do it with the utmost care.

Old crappy code is unlikely to have a comprehensive test suite, or indeed an easy way of making one, but if you're willing to spend the time to make a decent (or at least acceptable) testing system, that reduces the risk of any changes you do make.

DO:

  • Document the way it works, in a separate document
  • Work around it to avoid any changes which could affect the behaviour
  • Fix bugs IF they need fixing
  • Duplicate a routine if you can't figure out exactly what the old one is trying to do

DON'T:

  • Refactor needlessly. Something may be relying on existing bugs; you might not understand how it works well enough
  • Reformat, re-comment or make other "trivial" changes; they still carry risk, but add little or no benefit

    Mark

0

The most important thing to do for you and your team is to take emotional control. By default, you are in a position not of your making and you will have to fight the resentment that will naturally arise from being "stuck with this crap".

Identify what you can do, today, that will bring you the most benefit easily and assess the pain involved. Get it out on the table so that all understand what's at stake. Get the emotional commitment to endure the pain, and the commitment from the team to laugh, fight, cuss together while you keep control. Work that list your team creates, for the tiniest improvement will buy you a day that you're not under the thumb of the awful code base giant.

I know this sounds rah-rah cheerleaderish, but when you stuck with crap, you need to turn off the emotion of indignity and anger and focus on change. The small triumphs will lead to bigger ones. Soon people will take note and ask "why are we keeping the old code base when the team can crank out good stuff so easily now."

Let your management know what triumphs you have as you conquer the bad mess. When you say bad mess, be sure you wink and smile to let management know that you are the agent of change, are handling this for them, and that they can trust your strength and wisdom. Show strength of spirit for your team at work, and when you go home take up martial arts and kick the crap out of a sparring partner or run marathons. Seriously, divert the frustration to exercise and win at work. Good luck, it's not an easy position to be in, but you can get through it.

0

Lots of good advice in these answers! Let me add another technique, assuming you've suited up and decided to go in head first. Note that this often works with code, people, and entire departments:

Define the interfaces. Wherever one piece communicates with another, try to determine:

  • What the inputs are. Ranges, restrictions, pathological values and--especially--boundary conditions. This helps you put the piece into a proverbial box.

  • What the outputs are. Allowable values, likely values, correct responses to test data, responses to pathological conditions. This helps you quantify potential damage to other components.

  • Dependencies. Global variables, preconditions, assumptions. This helps you identify requirements and build resistance to disasters that result from external influences.

  • Side effects. How can this component initiate an insidious error that pops up later, in a seemingly unrelated area?

Once you've done this at appropriate levels, you'll be in a better position to identify candidates for refactoring, whether at the function, module, or department level. :-) You'll understand what goes in, what miracles occur inside, and what comes out.

Good luck!