views:

1050

answers:

21

Setup

Have you ever had the experience of going into a piece of code to make a seemingly simple change and then realizing that you've just stepped into a wasteland that deserves some serious attention? This usually gets followed up with an official FREAK OUT moment, where the overwhelming feeling of rewriting everything in sight starts to creep up.

It's important to note that this bad code does not necessarily come from others as it may indeed be something we've written or contributed to in the past.

Problem

It's obvious that there is some serious code rot, horrible architecture, etc. that needs to be dealt with. The real problem, as it relates to this question, is that it's not the right time to rewrite the code. There could be many reasons for this:

  • Currently in the middle of a release cycle, therefore any changes should be minimal.
  • It's 2:00 AM in the morning, and the brain is starting to shut down.
  • It could have seemingly adverse affects on the schedule.
  • The rabbit hole could go much deeper than our eyes are able to see at this time.
  • etc...

Question

So how should we balance the duty of continuously improving the code, while also being a responsible developer? How do we refrain from contributing to the broken window theory, while also being aware of actions and the potential recklessness they may cause?


Update

Great answers! For the most part, there seems to be two schools of thought:

  1. Don't resist the urge as it's a good one to have.
  2. Don't give in to the temptation as it will burn you to the ground.

It would be interesting to know if more people feel any balance exists.

+1  A: 

Bad code is not something that can be avoided totally, but it can be isolated by proper abstraction. If it is indeed wasteland, which means, there is no landfills around, focusing design process is much more effective than trying to make people write perfect code.

M. Utku ALTINKAYA
+8  A: 

The impulse to rewrite is righteous, provided that:

  • you "freeze" the existing code (with a label)
  • you start the rewrite attempt in a separate branch
  • you prepare first some unit-test in order to ascertain the current behavior and make sure you reproduce the existing features...

That said, you have to balance the rewriting process with the measure stability of the legacy code.
"If it is not broken, do not fix it" ;)

VonC
+4  A: 

Just don't - The rabbit hole always goes too deep. Make any small local changes that leave the place cleaner than you found it, but leave big refactoring for when you're alert and have plenty of time to burn.

A nice starter on tackling big refactorings in small stages at sourcemaking.com :

you have to make like Hansel and Gretel and nibble around the edges, a little today, a little more tomorrow

Ken
+15  A: 

I've found that spending two months fixing bugs caused by my "harmless" re-write was enough to cure me of the urge to do these sorts of things without a clear mandate/project plan to do so.

Paul Tomblin
+17  A: 

I'm a big fan of making lists!

As soon as the urge takes you to re-write something - spend 10 minutes making a list of the things that need re-writing. Follow all of the alleys that take you further into the code that needs attention and list those, too.

Hopefully within a relatively short space of time you'll have one of two things:

  • A really long list that completely puts you off wanting to rewrite anything ever again.
  • A list which actually isn't that long, so why not indulge yourself and go for a re-write?!
Chris Roberts
The list can also be a useful in deciding what to rewrite and in what order, say if you decide to rewrite the application in multiple steps (i.e. refactoring).
Anders Sandvig
+3  A: 

As far as I am concerned, if you have nothing better to do than to rewrite the code then you should make everyone else aware and just do it. Obviously, if it's going to take days to get any sort of result and the changes would mean excessive downtime then it's not a good idea, but eventually that code will become a problem. Make others aware that the code is awful and try to get some sort of movement to rewrite it.

The problem with the above statement is that as a programmer/developer you will ALWAYS have other things to keep yourself busy. Just leave it on the low-priority list of things-to-do, so when you're struggling with some work you can always keep your rhythm going with the rewrite.

EnderMB
+4  A: 
  1. reread "Refactoring".
  2. Take a piece of paper and itemize the "Bad Smells" list.
    (for each smell in BadSmells() {
    print smell.name;
    }
  3. Add comments to the code including item(s) from the list.
    while( odorPersists() ) {
  4. Work through the list, laser-focused on one smell at a time.
    }
le dorfier
A slightly eccentric take on the problem, but I whole-heartedly agree. Essentially what is being said here is analyse the problems, and address one at a time so that you fix them and can reliably measure your impact rather than end up in a bigger mess than where you started.
Kurucu
+13  A: 

The most memorable project of this kind for me occured some 4 years ago when I was called in to a remote office to "help" with a project that was due in 1 week for major presentation to the client and was not working yet at all. The project had been primarily off-shored to India, and IMO, a project management failure resulted in a ton of spaghetti code that was too fragmented to ever work properly in its current form.

After a full day's review, I presented my opinion to the management that the project simply needed wholesale refactoring and reorganization or it would never work properly. The result of this discussion was 6 days of 20 hours work / 4 hours sleep, 2 of which I actually spent sleeping on the couch in the company lobby due to the wasted time when driving back to the hotel.

The major improvements to the code included:

  • Application of naming standards
  • Moved into source control
  • Development of a build process
  • Documentation of the individual components

Most of the original code was left in place, but simply moved and reorganized / refactored to make it sustainable in the long term. Was it hell week? Sure. Did it make the project more successful? Yep.

I can't live with spaghetti code, and I'll often donate my own personal time to address it.

Chris
You sir, are my hero of the day!
javamonkey79
Were you yourself doing the rewrite, or were you supervising others doing the rewrite?
BubbaT
+1  A: 

IDon't think you SHOULD stop yourself from this. Mostly if you FEEL for the big rewrite it's mostly correct to do. I insanely disagree with Joel Spolsky on this thing...

Though it's one of few places where I disagree with him ... ;)

Thomas Hansen
Only safe if you have the unit tests in place to demonstrate that your rewrite is safe. Emphasize "ONLY".
Jonathan Leffler
+6  A: 

You're absolutely right that there's a right time and a wrong time to rewrite (and destabilize) the code.

Reminds me of an engineer I knew who had a habit of diving in and doing major rewriting whenever he felt like it. This drove the QA staff for his product up the wall -- if he report a bug about something trivial, the bug would get fixed, but the engineer's major rewrite of stuff he noticed while fixing the one bug would introduce fifty other new bugs, which then the QA staff needed to track down.

So one way to cure yourself of the temptation to do rewrites is to walk a mile in the shoes of the QA engineer who has to test, diagnose, and report all those new bugs. Maybe even lend yourself to the QA department for a few months to get a personal feel for the type of work they do (if you've never done that).

Another suggestion would be to make a rule for yourself to write up notes to describe any change. Perhaps post these notes when you check in code changes to source code control. You may be motivated to make the changes as minor as possible this way.

Bill Karwin
"while fixing the one bug would introduce fifty other new bugs" at which point I'd expect the QA people to reject the fix, revert it in source control, and reopen the original bug. Otherwise you end up chasing lumps all over the carpet until the end of time...
Steve Jessop
Typically, you don't discover the fifty new bugs immediately.
Bill Karwin
I guess the longer it takes to realise that the fix is worse than the original code, the less likely it is to be possible to revert, since there will be further changes built on top of that change.
Steve Jessop
+3  A: 

I've never worked anywhere particularly agile, so what I do is:

1) Figure out whether there's a reasonable fix that doesn't involve major rewrite. If not, then clear some time (perhaps by explaining to others how difficult the fix is) and do the rewrite.

2) There is a reasonable fix without major rewrite. Apply the fix, run the tests, check it in, mark the bug as fixed.

3) Now, raise a new bug/issue (enhancement request), outlining the proposed rewrite and how it would improve the code (simpler? more maintainable? reduces coupling? affects performance or resource use?). Assign it to myself, CC anyone interested in that bit of code.

4) Give people a chance to comment, then prioritise that new bug within my existing tasks. This usually means don't do it now, because most of the time if I have one "proper" bug to fix, then I have at least two. Do it once the critical list is cleared, or next time I need to do something that isn't boring. Or maybe after a couple of days it won't seem worth doing any more, and it won't get done, and I've saved the time I would have spent doing it.

The important thing, I think, is to avoid shaving a yak every time you make a small bugfix.

The trade-off is that if the code you want to rewrite is really bad, then it's easy to under-prioritise the rewrite, and you end up spending so much time maintaining it that you don't have time to replace it with something that would require less maintenance. That needs to be borne in mind. But no matter what priority the rewrite should be, or how your organisation assigns those priorities, fixing bad design in the same area of code is not the same thing as correcting the out-by-one error that caused the crash you originally went in to deal with. This has to be considered at step 1: if the design means there are probably a whole bunch of other out-by-one errors lurking in the code, then just fixing this one is probably not "reasonable". If it really was a typo, but you happened to spot a refactor opportunity because you had the file open, then correcting it and touching nothing else is "reasonable".

Obviously the more agile your shop, the more significant a refactor you can do without it being so disruptive / time-consuming / political as to require a separate task.

Steve Jessop
+7  A: 

It's not quite an answer, but reading the beautiful article The Narcissism of Small Code Differences might help.

ShreevatsaR
Great article - thanks
seanb
+2  A: 

Joel has an article about this:

There's a subtle reason that programmers always want to throw away the code and start over. The reason is that they think the old code is a mess. And here is the interesting observation: they are probably wrong.

Dan Dyer
+1  A: 

Stop rewriting when it is good enough. For this you need to know what good program is for you not only for your employer. After all you do programming for life not for good impression. Develop sound criteria which really would tell you that you are good and result is descent and it is time to go to next task. You should like your programs not less then your boss likes them.

Din
+4  A: 

Personally, this is where bug tracking software such as JIRA or Bugzilla come in to place with me.

I have a hard time NOT fixing all the broken windows when I see them, but if the situation is bad enough (and time permits) I will open a ticket and either assign it to me or assign it to the group responsible, that way I don't go off on a tangent.

-- I do only what needs to be done right them, but yet the issue is documented and will be fixed in time.

-- This is not to say that small broken windows should be handled this way; small issues should always be fixed on contact IMHO.

javamonkey79
+7  A: 

How to restrain one’s self from the overwhelming urge to rewrite everything?

Become old*

As this has happened to me, I've gradually lost the urge to rewrite everything. Why?

  • Once you've done it a few times, you realise that you often end up worse off than you started.
  • Even if you're god's gift to programming and your brilliant rewrite introduces no new bugs, you'll simply fail to notice or implement about 30% of the small edge-case features/bugs which things rely on. This will cost you months in fixing
  • Nothing wears down your irrational exuberance like time. Often this is a sad loss, but in this case, it's a win.

*(more experience may also be a suitable substitute if you lack the free time to become old)

Orion Edwards
+1 because I am about to turn 40 soon ;-)
Treb
+1 Old? I'm like a half a decade older than you and still have these urges. What gives man? ;)
Scott Saad
@Scott Saad: You're 90 years old?
Esteban Araya
Esteban: decade, not century. Also, Orion: 28 is not old. Unless you smoke 2 packs a day. Or you're a Bison.
Sam Pearson
lol. I'm well aware that 28 is not old, but in comparison to a lot of newbie programmers (university/high school students), it's positively ancient.@Scott Saad: Of course everyone still gets the urge, but at least you'll have a better idea when to act on it :-)
Orion Edwards
+2  A: 

If it's some code you've inherited, start making the code your own. Write unit-tests, then refactor.

David Nehme
+1  A: 

Write more unit tests just to find out that the code is running perfectly fine.

If you still have the urge to rewrite it, you will have some tests to find out that your rewriten code is now failing ;)

Drejc
A: 

Chris Roberts started with great answer, but then he ruined it starting at the 3rd paragraph. ;-)

javamonkey79's answer was very good... This is definitely something bug trackers are for.

My approach, gleaned from my limited understanding of Stephen Covey's excellent, The 7 Habits of Highly Effective People:

  1. I have a start-time, a stop-time, and a goal for every task.

  2. When spotting a "broken window" and it's not an emergency:

    1. Make an immediate note on my personal todo list.
    2. Make only the change I originally set out to do.
    3. Compile, test, and snapshot the code. Lather, rinse, and repeat until the original goal is complete.
  3. If I have time left on the original task, I look at my todo changes and enter them into the bug tracker. This really helps me get a clearer notion of the priority and scope of the issue.

  4. If I don't have time, the issue is shelved until the next day, when I revisit my short-term todo list and incorporate anything outstanding into my master todo list. Things always look different the next day.

    If I hadn't already entered the "problem" into the bug tracker, I schedule a time to do that, and just that.

  5. Bugs are always tackled in priority order. Except: if a lot of bugs are related to really bad code, A complete rewrite might be more cost-effective. I always sleep on such judgments -- even if I don't have to convince a team or management.

Brock Adams
A: 

Refactor only if your boss/company actually encourages it, otherwise you'll end up doing frequent extra time to bring up code to perfection... Until someone less dedicated touches it again.

ASalazar
A: 

Starting assumption: you already "commit early, commit often".

Then there's never a bad time to start a refactoring, because you can easily back out at any point. I find that at the beginning, it always feels like it's going to be easy, but after making a few changes and seeing the effects, I start to realise quite how big a job it's going to be. That is the time to ask whether there is really time to make the changes, or whether living with it until next time you come to this code is the better course.

The willingness to stop, throw away a half-refactored branch, and do it the nasty but quick way where appropriate, is key.

That's for refactoring, where the changes are incremental, and running (or nearly-running) software keeps you well grounded. Rewriting is different, because the time until you figure out it's going to take longer than you thought is so much greater. I may be taking the question too literally, but there's almost never a good time to throw it away and start again.

Andy Mortimer