Stuff with the Perl Foundation. A couple of patches in the Perl core. A few CPAN modules. That about sums it up.
A few weeks ago, we implemented a reporting system. Since we're huge believers in agile methodologies, we threw things together fairly quickly, using TDD. This exposed two problems. First, the "class" we implemented was a sloppy mess of procedural code with a OO wrapper. Second, the tests were a similarly sloppy mess of procedural code.
The last few days, I've had to extend this and I found it very hard to do. I've rewritten the tests to be data driven and I now iterate over a list of known states. They're much easier to work with and understand, but they also make it clear that some of our code has needless duplication.
The big win, though, was rewriting the "class" to actually be a class. Instead of huge methods with a bunch of if/else statements, I relied on proper method dispatching. The resulting code is shorter (278 lines of code are now 101 lines of code), easier to read, and exposed some confusion in the underlying thinking. The big issue, though, was that I was left with a single "if" statement:
if ( 'yesterday' eq $time_period ) {
$date->subtract( days => 1 );
}
I went from eight "if" statements to only one. The previous "if" statements were all failures of our code to take advantage of the dispatching capabilities of OO. The final "if" statement, however, was bugging the heck out of me. I realize now that it means we've hobbled ourselves. What if we want three days ago? Nine days ago? It turns out that we really can't do that. Fixing this is easy but it does require a change in the API. Once again, conditional checks in OO code prove themselves to be code smells.
Legitimate conditional checks should (I'm not a purist) generally be on pure booleans, not calculated ones. The condition above is faulty, but the following condition is reasonable:
if ( $debug ) {
$self->log($message);
}
That's a pure boolean and is the sort of thing I don't really have an issue with. Calculated booleans in OO code always give me pause.
Code smell heuristic (Score:2)
Thanks for the heuristic! I never realized that before! I think this will help improve my coding.
(If there's a larger source where you picked that up, I'd be benefitted by a pointer.)
J. David works really hard, has a passion for writing good software, and knows many of the world's best Perl programmers
Re: (Score:2)
Thought I've later found that others point this out, I doubt how I learned this [perl.org] will help you :)
Re: (Score:2)
I figured a concrete example would help. Imagine this awful method from some Catalyst code I was working on:
Re: (Score:1)
Re: (Score:2)
In this case, it's done via a customer selecting a URL, so it's up to the customer to decide what they want and we don't have to.
A better example would be with Java:
In regular Perl (no modules), it sometimes gets mistakenly rewritten as this:
Re: (Score:1)
Look at the method names. Do they really focus on what the methods do? Where is the axis of duplication? (hint: group by)
Re: (Score:2)
This was a tiny example and merely a first-pass refactor. If you look at the actual code I checked in, you'll see it's much cleaner.
Re: (Score:1)
Re: (Score:1)
Too much work (Score:2)
Re: (Score:2)
The conditional is a point I make in my OO guidelines writeup [perlmonks.org] on PM. It's bad practice. I make the same point here, too [perl.org]. So yes, I do agree with you, but I plead mea culpa of posting a bad example to explain good code ;)
Re: (Score:1)