Home > Articles > Programming > Ruby

Robert C. Martin’s Clean Code Tip of the Week #1: An Accidental Doppelgänger in Ruby

Robert C. Martin
  • PrintPrint
  • Share ThisShare This
  • DiscussDiscuss
Close WindowRobert C. Martin

Robert C. Martin

Learn more…

Sorry, this author hasn't posted any blogs.

Robert C. Martin investigates an interesting dilemma: if the implementation of two functions is identical, yet their intent is completely different, is it still duplicate code?

While working on RubySlim I came across an interesting dilemma. Consider the following two ruby functions:

def slim_to_ruby_method(method_name)

  value = method_name[0..0].downcase + method_name[1..-1]

  value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }

end
def to_file_name(module_name)

  value = module_name[0..0].downcase + module_name[1..-1]

  value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }

end

The first takes a method name in the SLIM syntax (which is equivalent to the Java syntax), and converts it to a method name in the Ruby syntax. The second translate the SLIM package name syntax into the Ruby file name syntax. The best way to explain this is to show you the specs (in RSpec form).

it "should translate slim method names to ruby method names" do

  @statement.slim_to_ruby_method("myMethod").should == "my_method"

end
it "should convert module names to file names" do

  @executor.to_file_name("MyModuleName").should == "my_module_name"

end

Notice that the implementation of these two functions is identical, yet their intent is completely different. So the question is: Is this duplicate code?

But the situation above gave me pause. The fact that these two functions do the same thing is an accident. One transforms function names, and the other transforms package names. It would be an ugly form of coupling to eliminate this duplication by deleting one of the functions and just using the other. We don't want the caller of slim_to_ruby_method to know anything about package names; and we don't want the caller of to_file_namem to know anything about function names.

We could rename the remaining function to camel_to_underscore, but we don't want either of the two callers to know anything about the implementation of the syntax transformation.

So perhaps this isn't duplication. . .

Of course it is! And the solution is simple enough. We create a function named camel_to_underscore with the same implementation as the others. Then we have the two other functions call it. This keeps the callers of the original functions from getting coupled to the implementation, while getting rid of the duplication.

def camel_to_underscore(camel_namme)

  value = camel_name[0..0].downcase + camel_name[1..-1]

  value.gsub(/[A-Z]/) { |cap| "_#{cap.downcase}" }

end
def slim_to_ruby_method(method_name)

  camel_to_underscore(method_name)

end
def to_file_name(module_name)

  camel_to_underscore(module_name)

end

This is really an example of maintaining a single level of abstraction per function. Duplicate code always represents a missing abstraction. But having the original callers invoke camel_to_underscore would have caused them to do more than one thing by mixing high level concepts with the low level notions of camel case and underscores. By creating the two delegating functions, we manage to keep the level of abstraction consistent with the callers, while getting rid of the low level duplication.

  • Share ThisShare This
  • Your Account

Discussions

Make a New Comment

You must log in in order to post a comment.

Related Resources

Jennifer  BortelWin FREE iPhone Developer Books and Videos- Introducing @InformIT Giveaways
By Jennifer Bortel on February 5, 2010 No Comments

Apples’s recent iPad announcement made our hearts flutter so we couldn’t resist making an announcement of our own!

Today marks the first ever @InformIT Giveaway!

We’ll regularly post a video like this one profiling spectacular prizes we’re giving away—from books and videos to T-shirts and other exciting stuff. Check out the video below to see the giveaways for today, and then scroll down for more prize details and instructions on how to win them!

Dustin Sullivan"Every OSX developer should have this book on their desk."
By Dustin Sullivan on February 1, 2010 No Comments

That was the sentence Mike Riley ended his recent Dr Dobb's CodeTalk review of Cocoa Programming Developer's Handbook with.

David ChisnallCocoa Tip of the Day, 1/29/10
By David Chisnall on January 29, 2010 No Comments

Don't ignore old versions of OS X.

See All Related Blogs

Informit Network