in reply to Re: Re: Cannot read in multiple lines
in thread Cannot read in multiple lines
Making cosmetic changes to code is not "refactoring."
I beg to differ :-)
Making cosmetic changes to code is almost the essence of refactoring. According to Fowler (my emphasis):
Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing it's external observable behaviour.
People sometimes only consider structural refactorings like Replace Type Code with State/Strategy and ignore the smaller refactorings like Inline Temp that can be just as important.
Obviously 'easier to understand' is a subjective term (people can argue forever about Inline Temp vs Introduce Explaining Variable) - so take all the 'increases clarity' that follow as 'increases clarity for me'.
First off, the ones that I definitely consider to be refactorings:
Next a bad refactoring:
Finally bug-fixes gone wrong. I said:
We don't need the close - the filehandle will automatically be closed when it falls out of scope.
And you said.
that's terrible advice. The filehandle should absolutely be closed. It's a global (package) variable and probably won't go out of scope until the program ends. Leaving it open is an undocumented and probably undesired side-effect.
Quite correct. I'm stupid. It was late. Foolish Adrian.
It's instructive that I made this error because of a classic mistake. Let's look at the original code again:
sub get_schoolname( $ ) { my $id = $_[0]; my $schoolname; #get groupname from current database open(SCHOOLDATA,"school_data.pdt") or die "Can't open school data +file: $!"; while ( <SCHOOLDATA> ) { chomp($_); @split_record = split( /\|/ , $_ ); print $split_record[0]; if( $split_record[0] eq $id ) { $schoolname = $split_record[1]; } } close( SCHOOLDATA ); return( $schoolname ); };
Now, when I looked at this I actually did notice that it stomped all over the global SCHOOLDATA :-)
What I should have done at this point is write a failing test.
However, due to a little too much hubris some variant of "The code is so simple! Who needs a test to demonstrate the bug" went through my head. Bad Adrian.
Later on I coding an extra close into the loop so that the file handle would be closed after the early exit in my version. As soon as I'd finished I thought - "Well that's pointless. Once you've localised SCHOOLDATA it will be closed when it falls out of scope" and removed both close statements.
I then wrote up my nice little decision to remove the close - and promptly forgot to go add the local that would make it valid!
So, instead of removing one bug I added a new one. Very bad Adrian.
Now, if I'd been a good little developer and written some failing tests:
use Test::More tests => 4; { local *SCHOOLDATA; open(SCHOOLDATA, "school_data.pdt") or die; is(get_schoolname(2), 'bunny werks', 'existing id found'); is(tell(*SCHOOLDATA{IO}), 0, 'filehandle still open'); }; { local *SCHOOLDATA; open(SCHOOLDATA, "school_data.pdt") or die; is(get_schoolname(-1), undef, 'bad id rejected'); is(tell(*SCHOOLDATA{IO}), 0, 'filehandle still open'); };
I wouldn't have humiliated myself in front of my peers like this :-)
So the moral of the story is:
By the way, IMHO, his variable names were just fine for the task at hand. I would have chosen them differently and probably closer to the names you picked but that's largely a matter of style. Style is something we all develop for ourselves. It takes time and we find ourselves making niggling little decisions like whether to use $id_to_fetch or $fetch_id as you seem to have struggled with. Personally, I would have stuck with $fetch_id because I think prepositions in variable names are ugly and cumbersome but it's still a style decision.
Didn't have to struggle with the name change. Took longer to type than it did to think about.
While I agree that it is a style decision I think the fact that both of us would have chosen something other than '$id' is a pointer to the fact that the original choice wasn't as clear as it could be. Not wrong - just not as descriptive as it could be.
Rewriting code just because you can is rarely a good idea. You should always have a good reason for rewriting something.
For me increasing the clarity of the code (for some definition of clarity) is a good enough reason.
Even with good reason, you should be careful to keep the functionality equivalent unless you're sure it doesn't work.
Quite correct. Fouled up with the close & chomp changes.
In other words, if it ain't broke...
I tend to disagree. This approach can turn the code base of a large project into a Big Ball Of Mud in a surprisingly small period of time. Over the years I'm spending more and more time Refactoring Mercilessly and finding it works very well.
<Adrian wanders off to write out 'always write a failing test for a bug' 1000 times>
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
What is refactoring? (was: Refactoring gone wrong)
by sauoq (Abbot) on Nov 07, 2002 at 23:24 UTC | |
by adrianh (Chancellor) on Nov 10, 2002 at 00:23 UTC | |
by Aristotle (Chancellor) on Nov 10, 2002 at 15:21 UTC | |
by adrianh (Chancellor) on Nov 10, 2002 at 15:59 UTC |