This week's book giveaway is in the Android forum.
We're giving away four copies of Head First Android and have David & Dawn Griffiths on-line!
See this thread for details.
Win a copy of Head First Android this week in the Android forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Tim Cooke
  • Campbell Ritchie
  • Paul Clapham
  • Ron McLeod
  • Liutauras Vilda
Sheriffs:
  • Jeanne Boyarsky
  • Rob Spoor
  • Bear Bibeault
Saloon Keepers:
  • Jesse Silverman
  • Tim Moores
  • Stephan van Hulst
  • Tim Holloway
  • Carey Brown
Bartenders:
  • Piet Souris
  • Al Hobbs
  • salvin francis

Refactoring complete

 
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When refactoring, how do you know when your code is complete?
I don't just mean compiled and tested code.
When is enough, enough? C'mon, there should be some control to hold refactorings in check.
regards
[ July 20, 2003: Message edited by: HS Thomas ]
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Generally, I am complete refactoring when I don't know how to improve the code anymore. The best way I know to not slow down is not to allow cruft to accumulate.
This is a little bit different when working on bad factored legacy code, of course - doing all the necessary refactorings in one big step would just cost too much time. What is important here is that you always leave the code in a better state when you need to touch it, so still improving quality over time.
Did that help?
 
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by HS Thomas:
I don't just mean compiled and tested code.


When you feel the need to refactor, it's usually because of code smells. I'd say you've refactored enough when those smells are gone (or perhaps even just tolerable).
For example, you've added a new feature and your code passes the unit tests. Along the way you may have committed certain "sins". Before you can say you're done, you have to refactor the "sinful" parts: eliminate duplication, etc. While you're refactoring, you notice that some part of the code could be refactored to make maintenance easier. Do you refactor that too? I would tend not to since I don't know for sure if it will be needed. I might, as a courtesy, leave a quick comment (I know this might be against XP rules, but it's often said that they're meant to be broken ) to try to point the next programmer in the right direction.
So I guess in summary I'd say "clean up after yourself but don't spend time rolling out the red carpet for the next guy." (I see the comment I mentioned earlier more as a trail marker).
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Junilu Lacar:
While you're refactoring, you notice that some part of the code could be refactored to make maintenance easier. Do you refactor that too? I would tend not to since I don't know for sure if it will be needed. I might, as a courtesy, leave a quick comment [...]


Can you please give an example of code you could refactor for better maintenance but possibly wouldn't? What kind of comment would you write? Thanks!
 
Junilu Lacar
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well, for example, I might have some static finals that might look like candidates for refactoring to the typesafe enum pattern. I don't usually refactor them right away. If I can live with that "sin", I'll usually wait until later when I know it would definitely benefit the design. The comment I'd leave would be something like:
/* Note: if necessary, consider refactoring these to typesafe enums later */
public static final int ...
public static final int ...
IIRC, one of the books in the XP series has a discussion related to this question and "museum quality" code. I'll have to check what was said but I think the gist of it was that it is not in the interest of speed to spend too much time bringing your code up to "museum quality." Isn't this an example of how one practice balances another: YAGNI vs. merciless refactoring?
I'm reviewing "Secure Coding" right now and they use a phrase I think applies to the approach I take:
How secure should your application be? Answer: "Just secure enough."
In the case of refactoring, I stop when the code is "just smell-free enough."
[ July 20, 2003: Message edited by: Junilu Lacar ]
 
Ranch Hand
Posts: 89
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Using your Intuition. Me I stop refactoring
when there is no more "bad smell"(Martin Fowler and Kent Beck term) in my code.
 
HS Thomas
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks, all.
These responses indicate that refactoring is the "cure" for badly evolved systems.
This "badness" may be due to :
1. Bad Coding Style
2. Bad Design -assumptions are made that don't suit or not communicated well ; hence classes not used as they should and instead overridden heavily
... and other factors.
I just wondered whether it better to take the stance that Prevention is better than cure .
If good Coding Styles, good Design practises (this one is the difficult one ) are communicated early enough, there would be less need to refactor. Testing / QA controls would be one way to ensure good practices. Not to mention education on good practices.
Refactoring , without really knowing how , could do more damage than good.
Seems to me , refactoring belongs to the Design and Test planning stage rather than after the code has been written. Or, rather it should be emphasised more at these stages. Oh , I don't know, perhaps there should be a split - Design Refactorings and Coding refactoring.
I can't imagine a good designer is required to know what a typesafe enum is.
regards
[ July 23, 2003: Message edited by: HS Thomas ]
 
author
Posts: 11962
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

If good Coding Styles, good Design practises (this one is the difficult one ) are communicated early enough, there would be less need to refactor.


True, there would be "less" need but the magnitude of "less" would be something very small, I would say. Most refactorings are done because of smells that are discovered during development and I believe these smells could not have been predicted much earlier nor prevented by best practices.

Refactoring , without really knowing how , could do more damage than good.


Do you mean stuff like refactoring from better to worse? Can you think of an example of these anti-refactorings?

Seems to me , refactoring belongs to the Design and Test planning stage rather than after the code has been written. Or, rather it should be emphasised more at these stages. Oh , I don't know, perhaps there should be a split - Design Refactorings and Coding refactoring.


Those concepts (design refactorings, code refactorings) are already in place. Design models can be refactored as well as code (as well as pretty much anything from shopping list to hair style) and this should be a continuous effort.
Thinking in stages is helpful for structuring stuff in your mind but refactoring and other best practices should be thought of as ubiquitous habits, not as tasks.

I can't imagine a good designer is required to know what a typesafe enum is.


And I can't imagine a good software designer who doesn't know how to code. Maybe he doesn't have to know typesafe enum per se, but I do think a good designer has to have several years of commercial development experience in order to have gained the necessary tacit knowledge and insight into what's possible in the "real world". Then again, I considering having designers that don't code to be a bad thing in the first place (similar to ArchitectsDontCode).
 
Junilu Lacar
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Remember also that the need to refactor is not always due to bad design. Requirements will change and so the context in which the design works also changes. If the current design does not work well in the new context, you'll want to refactor it so that it does.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Junilu Lacar:
Well, for example, I might have some static finals that might look like candidates for refactoring to the typesafe enum pattern. I don't usually refactor them right away. If I can live with that "sin", I'll usually wait until later when I know it would definitely benefit the design.


Well, this is a refactoring I would do instantly. But that's because I don't like int-enums at all - they don't communicate well and I can't move behaviour into them. In my experience, refactoring to typesafe enums pays back almost immediately. Your mileage may vary, of course...
There are times when I don't refactor immediately, though. Most often this is because I do see the smell, but don't yet see what the code really wants to look like, so I wait until the smell gets "more expressive". Sometimes it's just because I am lazy...

IIRC, one of the books in the XP series has a discussion related to this question and "museum quality" code. I'll have to check what was said but I think the gist of it was that it is not in the interest of speed to spend too much time bringing your code up to "museum quality."


I would be interested in knowing exactly which book that is and what it said...
Of course I am not interested in writing code "for the museum". I want to produce code that gives me maximum development velocity over a long period of time. Until now I didn't find that I am able to produce code that is too good for that goal...

Isn't this an example of how one practice balances another: YAGNI vs. merciless refactoring?


No - that's a common misunderstanding, but YAGNI doesn't apply to refactoring.
YAGNI is about not implementing unnecessary *functionality*. Merciless refactoring is about doing *the best* design for the currently implemented functionality. They are complementary, not conflicting at all!

I'm reviewing "Secure Coding" right now and they use a phrase I think applies to the approach I take:
How secure should your application be? Answer: "Just secure enough."


Yes, here YAGNI comes into play. Security is a feature. By implementing more security than you currently need, you are wasting time (and money). By refactoring mercilessly you make sure that you are able to add more security later, if you needed to.

In the case of refactoring, I stop when the code is "just smell-free enough."


There is an interesting analogy: that of "Design Debt".
Every time you don't refactor your code as mercilessly as possible, you are taking a "Design Loan". Every time you need to work on that code, you are paying interest - in the form of more time needed to understand and/or do things.
Your general strategy should be to hold your loan as small as possible, so that you don't need to pay additional interest. There are circumstances where taking a bigger loan might be reasonable (for example shortly before an important release), but you might also want to pay it back as early as possible (by additional refactorings).
Does that compute?
 
Junilu Lacar
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by HS Thomas:
Seems to me, refactoring belongs to the Design and Test planning stage rather than after the code has been written. Or, rather it should be emphasised more at these stages.[ July 23, 2003: Message edited by: HS Thomas ]


It certainly is. After all, refactoring is "improving the design" and unit tests are an important part of the process. And yes, it is more effective to refactor throughout rather than just once at the end and I didn't mean to imply otherwise in my other post.
The rhythm of development is to write a test...write some code...see that test fails...write code to make test pass and not minding about committing "sins"...test passes...refactor to atone for "sins"...make sure that tests still pass... repeat.
Still, like I said, there may be some sins that I can live with for now and be willing to take the risk of maybe, just maybe, paying for it later.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by HS Thomas:
These responses indicate that refactoring is the "cure" for badly evolved systems.


More importantly, it is a way to evolve a system in highly dynamic way, so that it doesn't get bad.
The best way to use refactoring is to not see it as a separate action, but incorporated in your minute-by-minute coding activity. If you can tell how much of your time you spend refactoring, you are not doing enough of it...

This "badness" may be due to :
1. Bad Coding Style
2. Bad Design -assumptions are made that don't suit or not communicated well ; hence classes not used as they should and instead overridden heavily
... and other factors.


*Mostly* other factors, such as: we learned something about the design while coding it.


I just wondered whether it better to take the stance that Prevention is better than cure .


If on your trip to the quarry pond, your car ends up in the ditch - what would you concentrate on:
- to learn on how to plan your trip, or
- to learn on how to stear the car?

If good Coding Styles, good Design practises (this one is the difficult one ) are communicated early enough, there would be less need to refactor.


Good practices aren't the problem. Applying the right ones in the right amount is. Knowing which design your system needs before coding it is the problem.

Refactoring, without really knowing how , could do more damage than good.


*Any* practice applied without knowledge is dangerous - *especially* big up front design!

Seems to me, refactoring belongs to the Design and Test planning stage rather than after the code has been written.


Separating design from coding is the biggest problem, because it delays feedback. Only by coding the design it gets validated.
Refactoring is a very powerfull technique for designing while coding.

I can't imagine a good designer is required to know what a typesafe enum is.


Knowing what a typesafe enum is - and when to apply it - is part of what *makes* a good designer. Granted, a very small part, but a part nevertheless.
 
Junilu Lacar
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
The analogy of a loan has its merits but you could also look at it as taking out an insurance policy. The less coverage/protection you buy, the less premium you have to pay. If it is unlikely that you'll get hit by flood waters, why take out flood insurance? Or if I increase my deductible from $100 to $500, I can save hundreds or thousands of dollars in premium payments if I never have an incident. I guess it works both ways...just depends on how much you are willing to lose/save now/later.
In the case of software design, a better factored design buys you better protection against the pain of changes. So, you either buy more coverage by refactoring more or you do less refactoring and increase your deductible and risk the pain of having to change some parts that will not likely to change anyway.
[ July 23, 2003: Message edited by: Junilu Lacar ]
 
HS Thomas
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
OKay, I am convinced refactoring is a good habit to acquire.
BTW , is this a group design effort ? No I'll answer that. Depends on the scope of the design smell.
Any guidance on how to decide if there is a smell ?


If it stinks , change it ...
-- Grandma Beck, discussing child-rearing philosophy


Answering Lasse's question on examples of refactoring anti-patterns, I guess they'd be where refactorings are made resulting in the following undesirable solutions:
1: the Blob, where one object does most of the work in a project
2: Continuous Obsolescence, where technology changes so quickly that developers can't keep up.
3: The Poltergeist (where do-nothing classes add unnecessary overhead)
These examples were taken from
Development Anti-Patterns.
We've had analogies from loan and interest,
sins and atonement, insurance and premiums.
Why not also a medical analogy ?
Symptoms / Consequences and cures.
The contexts in which these anti-patterns may have occurred means there could be little you can do about it, or there is such a huge chunk of impending change that no one knows to tackle it.
Some refactorings may lead to devastating ripple effects that they'd require some management (of the non-coding variety) or put the project at risk. This latter may belong to Anti-Architectural Patterns rather than Development Anti-Patterns.
In fact, here is a whole list of them I didn't know about :
AntiPatternsCatalog
regards
[ July 23, 2003: Message edited by: HS Thomas ]
 
Junilu Lacar
Sheriff
Posts: 16647
278
Mac Android IntelliJ IDE Eclipse IDE Spring Debian Java Ubuntu Linux
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ilja Preuss:
"museum quality" ... I would be interested in knowing exactly which book that is and what it said...


Must not have been in one of the books...found the discussion in the forum:
http://groups.yahoo.com/group/extremeprogramming/message/2638
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
There are a lot of design principles you could evaluate code against.
One useful one is to think about what will cause a class to change and how often. If there are two answers - regular addition of new features and rare change to the architecture - the class is surely doing two things amd should be two classes.
Another good check is: Can you describe a class in one sentence with no AND or OR clauses? How about each method? How about the package?
 
HS Thomas
Ranch Hand
Posts: 3404
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In life, I find we refactor all the time.
e.g. Writing a note , when adding a link I had to change some text "these two links" to "these links" , the context of the note being *what links are there for a subject*. With some thought I could have avoided the need for refactoring.
Most actions need adjustments. But the adjustments would depend on the mood / personality type.
e.g. Cooking
The perfectionist would restock the cupboards at the same time.
The romantic individualist would light some candles.
The achiever would .......
The pleasure planner would .....
Th minimalist would slap a burger on a plate and leave it at that.
Can the same be said of refactoring software ?
Avoiding "code smell" seems to be the guiding principle. But each personality type would add their own flavour.The analogies given for refactoring, i.e. loan , insurance , cures for symptoms would indicate this.
Constant testing would be a very necessary restraint.
And updating the tests , a necessary quality control check to get through for acceptance of deviating behaviour.
I must say that mercilessly introducing deviating behaviour was a worrying factor and hence my assertion that

Refactoring , without really knowing how , could do more damage than good.

.
regards
[ July 27, 2003: Message edited by: HS Thomas ]
 
Consider Paul's rocket mass heater.
reply
    Bookmark Topic Watch Topic
  • New Topic