Skip to content

Latest commit

 

History

History
79 lines (64 loc) · 2.46 KB

asymmetrical-code.md

File metadata and controls

79 lines (64 loc) · 2.46 KB

Asymmetrical Code

Code accomplishes analogous tasks in different ways, at different times, in different orders, or at different levels of abstraction.

What It Looks Like

if https_url?(url) || url.start_with?("ftp://")
  Downloader.get(url)
elsif git_ssh_url?(url)
  Git.clone(url)
end

Here, we are detecting the protocol specified by a URL string using two different levels of abstraction. For https and git, we call a specialized method, but to detect an FTP URL, we parse the string directly.

Additionally, we are fetching the resource in asymmetrical ways. HTTPS and FTP are combined into a single Downloader.get method (which probably ends up parsing the URL again to figure out which protocol to use), while Git resources use a totally separate interface.

A more symmetrical implementation of the logic above might look like this:

downloader =
  if https_url?(url)
    HttpsDownloader
  elsif ftp_url?(url)
    FtpDownloader
  elsif git_url?(url)
    GitDownloader
  else
    raise ArgumentError.new("Unsupported protocol in URL: '#{url}'")
  end
downloader.download(url)

Why It Hurts

Asymmetrical code obscures similarities. By making things that are essentially similar appear different, we cast doubt on whether they are truly similar. For example: is there a reason there's no ftp_url? method in the first example above? Someone reading the code might spend time figuring it out, only to realize in the end that there is no reason, except an accident of history.

When we obscure similarity, we also obscure important differences. When similar things appear different, the things that are truly different don't stand out. Special cases don't look any more special than the "regular" cases. This makes it harder to tell when we can safely follow common patterns in the code and when we have to take special care to handle an edge case.

How To Fix It

Balance abstractions using Extract Method, or perhaps Inline Method. Bring divergent interfaces into alignment with Rename Method.

Asymmetrical code is often a form of duplication. When code appears asymmetrical, its pieces duplicate some underlying idea, but obscure the duplication behind divergent surface forms. We can remove duplication by following the Flocking Rules.

References