Telescoping Methods

Containers

I think of this like a telescope. My methods are “telescoping” or collapsing down. I can go deeper into the call stack and also be working further and further towards low-level operations.


Robert C. Martin says something like, “Methods should be short. Then they should be shorter than that.” (In Clean Code.) But how do I make methods so short? Following the Single Responsibility Principle is one thing that can help. If methods do only one thing, how can they be long? (By the way, another great resource for learning about the SRP is the C2 wiki.)

Well, actually, sometimes methods do one thing but in order to do that one thing, they must do many little things. So they can still be long! This happens when there is one atomic operation, but there are many steps to complete that atomic operation. Think about how many things happen when you are saving a record to a database:

  • finding a connection
  • opening the connection
  • preparing a statement
  • executing the statement
  • handling errors
  • closing the connection
  • returning a response
  • etc.

The reason saving to a database is a good example is because in one regard, saving to a database is a pretty high-level operation. There are low-level disk and network operations going on in a database save. It’s pretty high level to be able to call a method like “saveToDatabase(someRecord)” and not have to think about all the little nuts and bolts interacting under the hood. Even if we’re skipping a framework like Spring and instead we are using a very hands-on library like JDBC that requires us to perform a bunch of steps during a database save, we are still at a pretty high-level.

But in another regard, saving to a database is a pretty low-level operation. That’s nice to have a “saveToDatabase(someRecord)” method, because in a real application, saving to a database needs to be the low-level aspect of what we are doing. We might be zoomed out on a whole other tier of thought. Someone might have just went to their profile page in a web application, for example, and changed their favorite color, and now we’re calling “updateProfile(newProfileData)” and the saveToDatabase(someRecord) that results somewhere down in the call stack is suddenly a pretty low-level operation. We might not even be aware of or thinking about the fact that a database is in play.

Now that brings up another interesting rule that can help us keep methods short, and also helps us adhere to the Single Responsibility Principle. Robert C. Martin mentions this rule in Clean Code. It doesn’t have a name, but he mentions it as a kind of corollary to the SRP. He says, “In order to make sure our functions are doing ‘one thing,’ we need to make sure that the statements within our function are all at the same level of abstraction.”

What this likely means is that if you want to do something at a high-level of abstraction, like the profile update, you have to have a number of high-level methods that are called within that method. And if you work your way down into these methods in turn, you will find that each of them also in turn utilizes a number of methods at their level of abstraction, and so on and so forth all the way down to the lowest levels of code.

If you don’t have all those levels of abstraction and the level-specific methods that comprise them, then doing anything at the top-level while keeping everything you are doing also at that level is going to be impossible.

The high-level “updateProfile(newProfileData)” method body could look like this:

{
  validate(newProfileData));
  backup(oldProfileData);
  store(newProfileData);
  recordTimeStampOfUpdate();
  displayConfirmationMessage();
}

Notice that the method does one thing–has a single responsibility–which is to update the profile, but it is one thing as defined at the level of abstraction we are working in. In reality, looking at this method body, it is doing five things. These are the five steps that comprise the one coarser-grained step of updating the profile.

The method isn’t named “validateThenBackupThenStoreAndRecordTimeStampOfUpdateAndFinallyDisplayConfirmationMessage()” That would be exposing the implementation. It is named “updateProfile.” When the client code wants to update a profile, it calls this method. The client code doesn’t need to know that all this other stuff is happening. There is a level of abstraction placed over it.

Similarly, the implementation itself is made up of other methods. All the direct hands-on logic that forms the guts of validation of the new profile data isn’t just directly present in the updateProfile method. It has been moved out into a separate method, “validate.”

In turn, each of these internal implementation steps–validate, backup, store, record time stamp, display confirmation–all have their own set of sub-steps which comprise them. And they all have nice readable method names which tell you in the language of the domain what is happening. When you open the method, you don’t find that it is also doing other things than validation. This is called the Principle of Least Astonishment.

I think of this like a telescope. My methods are “telescoping” or collapsing down. I can go deeper into the call stack and also be working further and further towards low-level operations.

Thinking of methods this way is one of the skills a working developer can practice which will instantly result in more readable code. It is clear and follows a logical train of thought. It adheres to known principles like the SRP. Also, it is much more fun to maintain and expand. It is clean. If you can achieve this in your programs, you’ll have a pretty good time with them.

One thought on “Telescoping Methods

Leave a Reply

Your email address will not be published. Required fields are marked *