Refactor for Equal Levels of Abstraction

This post is a few years old now, so some details (or my opinions) might be out of date.
I would still love to hear your feedback in the comments below. Enjoy!

Refactoring is great. I’m all for coding some tests and refactoring code one small step at a time until it’s perfect. However, sometimes it’s difficult to know when to stop. For example, consider the following snippet:

class Foo(object):
    ...

def foo(self, config_file, raw_data, output_path):
	self.set_config_data(config_file)
	self.parse_raw_data(raw_data)
	with open(output_path, 'wt') as outfile:
		result = self.calculate()
		outfile.write(result)

	...  

should we refactor out the last three lines of foo? I recently got a very nice tip for deciding whether to refactor out a method. The rule of thumb is make sure each unit of code maintains an equal level of abstraction. What does this mean? The first two lines of foo are pretty high-level. They specify a part of the algorithm in near-pseudo-code. It’s pretty much in English: First, set configuration data by using the configuration file. Then, parse the raw data into the class. They don’t specify implementation.

The last three lines, however, are in a lower level of abstraction (as much as Python, which is pretty much executable pseudo-code, can be low-level). Opening a file, specifying access mode, writing results - those are implementation details. They don’t belong with the rest of the method. Therefore, the rule of thumb is to refactor those out, replacing them with a call like self.write_results_to_file(output_path) or something of this nature.

Using this rule of thumb make it easy to determine whether a piece of code needs to be extracted and makes the code easier to read, since we don’t have to change mindsets while reading a unit of code.

Discuss this post at the comment section below.
Follow me on Twitter and Facebook

Similar Posts