I like the idea of the Grep Test, but this is not a great illustration of it. These refactorings are bad not because they hide names from the developer but because they use the wrong abstractions.<p>The point of DRY isn't to mindlessly remove code duplication. It's to remind us to look for code duplication and keep us mindful of coupling between the various parts of our code.<p>Where two identical chunks of code that represent the same kind of work are used in multiple places we introduce "algorithmic coupling." That is, whenever the work being done in one location changes, we have to make sure to change the work being done in the other location. Anyone reading this code -- whether the author, the author's future self, or teammates -- has to remember this extra fact, increasing the surface area for bugs.<p>There's also "name coupling," viz., for every vector _foo_ associated with the Ray we want methods like foo_is_zero?, negative_foo, etc. Here it's important that the naming convention be consistent, so there's coupling there, too. If the names aren't consistent anyone else reading the code would then have to remember <i>that</i> fact, and anyone changing the names would have to remember to update all the other names, too.<p>The irony of his example is that style of metaprogramming is a great way to get rid of name coupling, but he did nothing to get rid of the much worse algorithmic coupling. Indeed, algorithmic coupling screams for DRY whereas name coupling requires it on a more case-by-case basis.<p>That is, when all the names are highly localized, e.g., three short methods that share some naming pattern are all defined in succession, it's much less important to remove the duplication. Anyone reading or editing that code will quickly see what the pattern is and why it exists.<p>Here's a comment I left on the blog:<p>Hmm. I don't think the lesson here is about to-DRY-or-not-to-DRY your code. Instead, it's about using the appropriate abstractions.<p>Using the Ray example, both position and direction are vectors, not points. Make them vectors! Then you'd be able to say things like<p><pre><code> ray.position.zero?
# We'd usually say "the inverse of" not "the negative of"
ray.position.inverse
</code></pre>
Furthermore, if you wanted to define the same methods, well...<p><pre><code> class Ray
def position_is_zero?
position.zero?
end
def direction_is_zero?
direction.zero?
end
end
</code></pre>
There's less repetition, now, because you're only repeating names, not logic. This means the code will only break when the names change, i.e., zero? becomes is_zero? or something.<p>In a world where all of your logic is also duplicated in the Ray class, the code would break when either the names or the logic changed.