Should one refactor while writing?

Started by
18 comments, last by mrbastard 11 years, 6 months ago
I usually start out with a pretty clean design which gets messy as its accumulating new features, which I refactor out whenever it feels to cumbersome or inflexible to use. In this sense I'm refactoring while writing, but not while actually implementing a feature. Often I also try to refactor before implementing a feature as this might save me work later on. I also get more joy from working in a clean environment and I love the moment when I realize that I designed/refactored something in such a way that the addition of new functionality doesn't require a lot of work at all.

I found "Refactoring: Improving the Design of Exisiting Code" By Martin Fowler et. al. a good book about how and when to refactor. It not just covers some technical aspects but also a lot about increasing productivity and code-stability from refactoring.
Advertisement
I have found that the "quick and dirty way" is an illusion, and isn't really quick at all, it just means you put off work until later, and produce less useful code with more bugs that haunt you later.
Sure, for some prototyping it can be motivated, but it should be cleaned up before commit to the trunk.
For longer prototyping, a branch might be motivated.

That doesn't have to mean you have to do a _refactor_ every time, if your design is sensible to begin with, it shouldn't be very hard to add functionality in a graceful manner, no matter what this functionality might be.

Though, of course your design is never perfect, and sometimes needs a slight refactor.
As others have pointed out, these should be done on a stable code base, so you can verify it works as it should both before and after.

My first question is, do you guys often do the quick and dirty thing, and then go back to fix it later; or do you get a hold of yourself and make sure you get the job done well, first and foremost?

Do it right the first time. If you can’t figure out exactly how it should be done, don’t do it. Keep planning. Writing algorithms you are not sure how to implement is the best way to create bugs.


Do you refactor while coding, or do you refactor after everything's done?

The only reason to ever refactor is if you simply made a mistake (but you had put enough thought into it that you believed you were doing it correctly originally), or you gained experience and realized a new way to organize code and have the time to do so.
So the general answer is that I refactor on my own projects as soon as I realize a need for it, and in professional settings I refactor based on the weighted sums of the need for refactoring vs. how much time is available for it.
In no cases is refactoring done after everything else is done. Not only do most projects have no end (for example, will there ever be a day when there is not a new feature I could add to my game engine?), but those projects that do have an end…end. They get shipped and you move on. You never think, “I could put this amazing app on the App Store right now! But naw I better spend another week just moving code around, even though the resulting product will be the same.” It doesn’t happen.


When it comes to my own projects, however, I allow myself one exception specifically to accommodate a personality “flaw” of mine.
Sometimes I am in the mood to do nothing but simple and mundane tasks, and if there aren’t any I simply won’t code anything. I will watch a cartoon or something and wast time.
But if there are some to do, I will start doing them, and once I get started I get in the mood to do more and more, and end up adding or at least starting new features.

When I get excited about the end result, sometimes I intentionally copy-paste code instead of moving it into a function (for example) specifically to give me a mundane task that will ultimately end up making me more productive.

Obviously, if you are a normal human being this will not apply to you, and I recommend being strict on the structure of your code at all times.


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

There are two typical scenarios I find myself in frequently. The first is when I find I do something again I already did elsewhere. Maybe not exactly the same, but with a commonality that depends on each other. Then I usually refactor the design into using common code. The simplest example is using a constant, which is so simple to fix that I make an alias (#define/enum/const) even if it is only used once (avoiding naked constants). When a few lines of algorithm is "copied" first time, it is a sign to make a common subroutine. Etc, up to class inheritance.

The second scenario I frequently find myself in, is when a class gets too big (with a fat interface), or a subroutine gets too big. That is usually a sign that some refactoring is needed. This case can be harder, however.

Doing a refactoring mostly leaves me with a very pleasant feeling. I can stare at the source code and feel pride. If I show it to my friends, they say "of course, how else could it be done?". Lots of effort has been used to find the obvious solution. But I know it is far from easy to find the obvious solution the first time you try. A good refactoring opens up new possibilities and opportunities that were not foreseen.

I like the advice above from mrbastard, to separate the commits from refactoring from commits that add functionality. The change should have no effects on validation. That way, when you find something is broken, it is easy to go back afterwards and test the refactoring to see if it was the root cause.


Do you refactor while coding, or do you refactor after everything's done?


That never happens. Unless someone pays your explicitly for it. The curse of having a limited budget or deadline is the usual thing, unfortunately. I think it is common that the "next project/budget" will have to take the consequences of imperfect design. And as this is a limited budget also, it is not unusual to end up in a patch work. If this goes too far, the solution will eventually to start from scratch. Kind of an ultimate refactoring.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/
For me it is just a part of development, not a separate step. After all the years of "red-green-refactor-submit", it has become completely automatic.

You write code. You consolidate, clarify, and clean up. Then you submit.

It should be included as a part of the estimates, and in practice is just a very small amount of time. When you see something that needs to be cleaned up, you simply do it. You also tidy up after yourself as you make changes and before you submit.

Much like a woodworker must clean up scraps as part of the task, so do programmers also need to clean up as they go along. They don't need to allocate extra time "sweep up the scraps and sawdust", it is just a known automatic task that must get done both during development.

If the wood shop doesn't get swept frequently it becomes dangerous for both injury to the workers and also for disasters like fires. Similarly if code is not regularly cleaned up during development it becomes more difficult to maintain and at risk for disastrous problems.
As I'm a major perfectionist in programming (though oddly not always in other things) I always try to make everything "perfect" from jump-street. My brain simply will not even let me write code if I dont have a nicely formatted file with code separation blocks (made of comment lines) to separate constructors, fields/properties, methods, event system, etc. I've turned this into a Visual Studio template so every new class file I create in C#, C or C++ is properly formatted for work. Here's my format for C# class files:

[source lang="csharp"]
#region Description
/*
*
*
*
*
*
*/
#endregion

#region Using Statements
/* System References :: */
using System;

/* Internal References :: */

#endregion

namespace MyNamespace
{
public class AClass1
{
/*-----------------------------------------------------------------------------
* CONSTRUCTORS & INITIALIZATION ::
*-----------------------------------------------------------------------------*/

public AClass1() { }

/*-----------------------------------------------------------------------------
* FIELDS & PROPERTIES ::
*-----------------------------------------------------------------------------*/



/*-----------------------------------------------------------------------------
* METHODS & IMPLEMENTATIONS ::
*-----------------------------------------------------------------------------*/



/*-----------------------------------------------------------------------------*
*******************************************************************************
*-----------------------------------------------------------------------------*/

} // <-- End of class...
} // <------ End of namespace...
[/source]

You probably either love it or hate it... For some reason I've never liked the convention of putting fields/properties first in a class, followed by constructors followed by methods. Since constructors are the first part of a class to run it only seems logical that they should appear first in the file (to me at least). That's why I do it this way. Every single file in my engine's code base follows this formatting conventions. The only exception is really small types (small classes and structures, enums and "helper" types/files). For me, this just makes things very, very organized and highly readable. I also typically refuse to save and close a file with properly documenting everything of any importance (every publicly exposed member) with XML documentation.

As for the actual code I try to do things right from the beginning. I try to avoid any sloppy/ugly code. In my opinion, poorly written and sloppy code is not a timer saver...it's a time-waster. Something major is going to break and you're going to have hell sorting it out. If your sloppiness gets too out of control you might end up with a situation where you're better off starting an entirely new solutions and copying over only the good bits of working code and rewriting everything else. And I HATE doing that because it takes forever on a project as large as my engine.
_______________________________________________________________________________
CEO & Lead Developer at ATCWARE™
"Project X-1"; a 100% managed, platform-agnostic game & simulation engine

Please visit our new forums and help us test them and break the ice!
___________________________________________________________________________________
There's a popular misconception being perpetuated in this thread - that refactoring is 'tidying up code'. It's not. It's a specific term, related to the term 'factor' from mathematics.

Most of the above advice is arguably correct when talking about 'tidying up code' but very little of it is about refactoring.


I like the advice above from mrbastard, to separate the commits from refactoring from commits that add functionality. The change should have no effects on validation. That way, when you find something is broken, it is easy to go back afterwards and test the refactoring to see if it was the root cause.

Actually, I meant that if your refactoring is behaviour-preserving, you can discount it during regression. If the behaviour really didn't change, the bug didn't originate here. Of course, for that to be the case you have to have automated refactoring tools (to ensure the change is a reversible transformation, not just moving code around) and enough test coverage to detect behavioural changes that sneak in through leaky abstractions or under-specified invariants.

Seriously, look into refactoring as a rigorous systematic process. It's worth it.
[size="1"]

There's a popular misconception being perpetuated in this thread - that refactoring is 'tidying up code'. It's not. It's a specific term, related to the term 'factor' from mathematics.

Most of the above advice is arguably correct when talking about 'tidying up code' but very little of it is about refactoring.

Depends on your definition of "tidying up".

For me that includes all the major steps; removing duplicate code to functions, pushing up to base classes, generalizing code, extracting classes and methods for clarity, etc. To me, that is simply tidying up. All of these are refactorings that don't modify the behavior, but that dramatically clean up the code for future use.

My first question is, do you guys often do the quick and dirty thing, and then go back to fix it later; or do you get a hold of yourself and make sure you get the job done well, first and foremost?


I often do the thing right the first time. Or essentially right. Sometimes doing all the nitty gritty details is counter-productive because of unknowns, risk of change, etc.


My second question is, what is your attitude about refactoring?
[/quote]

It is an essential practice to limit code rot.


Do you refactor while coding, or do you refactor after everything's done?


  • If I'm coding and encounter something that sucks, I'll occasionally take a tangent to refactor it.
  • If I'm coding and encounter something I want to re-use, but it's not quite abstract enough, I'll usually refactor it to handle the new case as well.
  • If I'm fixing a bug, and encounter some root cause that would cause a similar bug to be caused in the future, I'll refactor to fix the root cause rather than just the line that caused the bug.
  • Rarely, I'll go back and clean up something I wrote that isn't related to new development or bugfixing. If it works, leave it be.
  • I will frequently go through and refactor something other people wrote that will assuredly cause bugs in the future, is untestable, or otherwise needs it.

removing duplicate code to functions, pushing up to base classes, generalizing code, extracting classes and methods for clarity, etc. To me, that is simply tidying up.


You can use refactorings to tidy up, sure. But you can also tidy up in ways that are not refactorings, and do refactorings that are nothing to do with tidying up. So I think having a separate specific term is quite useful :)

For example: requirements change and you decide to parameterise a function or class further - that's not tidying up, it's preparing the ground for a new feature without changing external behaviour.

I was prompted to respond to L Spiro's comment that "The only reason to ever refactor is if you simply made a mistake". That's absolutely not true - requirements change. Of course it is perfectly reasonably to argue that the only reason to need to tidy up is if you made a mess. But not all refactoring is tidying up!

Not just being pedantic, I hope!
[size="1"]

This topic is closed to new replies.

Advertisement