Without ongoing attention to design hygiene, design integrity is bound to deteriorate over time. My latest IEEE design column, Enabling Change, briefly examines what it takes to keep a code base ready to absorb new design changes.
At the very least you should leave code as clean as it was before you made a change (if not better). One credo that Scott Bain extols in his new book, Emergent Design, is whenever you touch the code “do no harm”. Do what you know to be best at the time (given the constraints you are under). Scott is a realist, but I like his stance on when to fight for one particular design approach over another, too. When you think it will be really difficult to refactor/cleanup the design later due to a poor design decision that is on the verge of being made now, argue for what you think now is a better solution.
But even with good intentions and experience, we need to refactor and rework our code as we refine our design ideas--and learn from the code. Yep, we should refactor. Continually. But we don't always do so. Emerson Murphy-Hill, a Ph.D. student at Portland State and Andrew Black, a professor at Portland State wrote an intriguing paper, Refactoring Tools: Fitness for Purpose, that also appears in the upcoming issue of IEEE Software. They explain why in practice refactoring tools aren't used as much as they should be and propose some principles that characterize successful regularly used refactoring tools. They also distinguish between “floss refactorings”—those which should be done a regular ongoing basis during programming in order to avoid more pain later on—from “root canal” refactorings. They found that refactoring tools could be better designed and point out some that are better designed for daily use than others.