tags:

views:

589

answers:

13

Where a new system concept or new technology is used, one has to build a system to throw away, for even the best planning is not so omniscient as to get it right the first time. Hence plan to throw one away; you will, anyhow.

-- Fred Brooks, The Mythical Man-Month [Emphasis mine]

Build one to throw away. That's what they told me. Then they told me that we're all agile now, so we should Refactor Mercilessly. What gives?

Is it always better to refactor my way out of trouble? If not, can anyone suggest a rule-of-thumb to help me decide when to stick with it, and when to give up and start over?

+3  A: 

If you're merciless enough, the end result of refactoring will be pretty close to what you'd have gotten if you rebuilt from scratch, but you won't have been stuck with a non-working system during the process.

Chris Upchurch
+1  A: 

I'll prototype when I'm trying to work out a new problem or functionality. After than, I'll rebuild it based on what I learned. Actually, that sounds a lot like refactoring... what? Maybe it's the same thing? Hmmm...

scubabbl
+7  A: 

If you're doing test-driven development, you can refactor your way out of almost any trouble. I've changed major design decisions without much trouble, and rescued decade-old codebases.

The only exception is when you've discovered that your architecture is completely wrong from beginning to end. For example, if you wrote your app using threads, but you discovered that you wanted a bunch of asynchronous state machines. At that point, go ahead and throw away the first draft.

emk
+2  A: 

There comes a point where refactoring is a waste of time. You just have to start again from scratch. If you keep your design fairly flexible, and you recognise that you don't know everything just yet, you won't have to throw anything away. A class might become redundant, of course, but you wont throw away a whole system.

Having a flexible design is necessary to be able to refactor properly. Having no design or a rigid design means you WILL end up throwing something away - either because you cannot refactor, or because the constant refactoring degrades the maintainability of your code base. Few humans are meticulous and disciplined enough to be able to complete a long sequence of minor refactorings to maintain integrity. Unless you have an all-star team, this degradation will happen!

TL;DR: You can refactor your way out of most trouble. Occasionally, though, you won't be able to refactor past some design elements. When that happens, it is time to start again - although hopefully you can re-use some of the components you have in place.

metao
+1  A: 

I think that throwing one away is sometimes the best way to go, but it can hurt. One thing that I've found that works well is to throw one away, but choose your technology well.

For example, I've written a large codebase in Ruby on Rails, and over the past 2-3 years, RoR has advanced a lot. I also made some decisions in architecture that needed to be fixed. So, I'm throwing one away, and building a new one from scratch. However, I'm still able to use 70-80% or so of my old code as I'm still writing in Ruby and Rails.

The major factor that has helped with that is that Rails forces you to write well structured code with separation of business logic and presentation layers. I didn't get it perfect the first time around, but since everything is fairly well separated and DRY, porting the code to Rails v2.1, re-architecting the problem areas, and re-writing some "problem" features has been a fairly pain free experience.

So, by choosing a great technology from the start, I've been able to throw one away, but still take with me 70-80% of the old stuff that still works.

Dan Harper - Leopard CRM
+1  A: 

In a later essay in The Mythical Man Month, Brooks warns that he's found that if you do indeed plan to throw 1 away, you'll end up throwing 2 away!

I personally saw this happen in real life; we assigned a version 1 of the project as a quick throw-away to a mediocre programmer, because "we plan to throw it away later -- we will anyhow." We ended up having to rewrite it for version 2, but that one got thrown away too. I never saw version 3 - the company went out of business.

I think when Brooks says "plan to throw one away, you will anyway" it's more like the statement "the number of bugs remaining to be found is 'n+1'." That is, it's a ha-ha-only-serious statement about Murphy's law, rather than practical advice. The lessons to take away from it is that prototypes are valuable, good writing is rewriting, and don't be afraid to abandon something that isn't working.

However, it has to come down to a judgement call because as Joel Spolsky has talked about in several essays, the option to throw away and start over is tempting because code is easier to write than to read, and more fun to write than to maintain, so your natural inclination will always be to start over even when that isn't really the best thing to do.

+5  A: 

Throw away early, refactor later

Throwing away is OK for small systems, but if the size of the system is huge, you simply do not have the resources to do so.

You could, however, create a small pilot project that implements only the very essential features of the actual project. After some trial and error and learning and throwing away stuff, you end up with a solid core and a better understanding for the actual project. Then you let the size of the project grow, by adding all the features needed. But once you get there, no way you can throw away the core. Only refactoring.

Lahur
+1  A: 

Different situations require different approaches. Personally I perfer refactoring to a better design whenever possible. Refactoring leads to less bugs than a rewrite.

But, even if you plan to throw one away, its still a good idea to write a bunch of acceptance tests to make sure your 2nd version is on the right track. Then you can migrate towards the next version piece by piece while ensuring your functionality isnt changing from the user's perspective. Sounds a bit like refactoring, just a little sloppier I guess.

Jeff Heigl
+2  A: 

One of the central points of The Mythical Man Month was that the hard part of software development is figuring out what to say, not how to say it.

The way I've interpreted this recently is that the most value you get out of the first draft is the requirements you've gathered and preserved in the form of tests. If you're careful not to test things that aren't actually requirements of the system, you can refactor your way out of any mess.

So long as you don't code yourself into a trap where you have to start throwing out tests, you are OK to throw out as much code as you want without losing a significant amount of real work.

kbaribeau
+2  A: 

When talking about Agile, you could do both, but in a general way, you will do spikes (prototypes) only to try specific issues, learn about them and be able to do better estimates. Throw away when you are doing a simple spike and refactoring when you are really coding the application.

Kind Regards

marcospereira
+2  A: 

My general advice here is to refactor an existing system away from its bad designs to a system with better designs. This maintains the system and allows it to be deployed at all times. If you start from scratch it may be a while before you can deploy, or never.

If you are talking about just writing some brand new code where there is no existing system, then quite often its a good idea to write a little bit of code, however you want, then throw that away since it was never deployed and start again (using TDD).

quamrana
A: 

I think that your version control system plays a large role here. If you run a distributed version control system with easy branching (git, mercurial, these days), then you'll be able to prototype easier, and refactor easier, all while still having a valid working copy. Anything else requires so much more discipline.

Tchalvak
A: 

As a development manager in this organisation, I'm "not allowed" to write production code.

I (ab)use that rule to knock out quick, dirty proof-of-concept code that addresses one or other sticking point, then I check it in to source control and point a "proper" dev at it and say "Here's how it's done, now do it properly."

That's as close as we get to "one to throw away" here, and it's probably taken me a couple of hours max to knock together. Spending time putting in things like error handling, boundary-checking and all the other bits that make good code would be a waste of time for this sort of work, yet it means that the guys who are getting paid to write production code can spend their time writing production code and don't have excuses like "it's only a prototype" when it comes to code-review time.

Building one to throw away is too often used as an excuse for not doing the job properly. That means that you don't actually encounter enough of the issues in the process to learn enough to make it a good use of anyone's time. And doing it properly, only to throw it away, is even more wasteful.

As several people have previously said, the most important feature in any software is that it ships. With that in mind, I'd build "one to get people to pay me for" any day, and my mercilessness in terms of refactoring is to allow only enough of it to get a product that works and can be reasonably maintained.

Xav