On The Shortness Of Functions

 

Last time we discovered the difficulties that come with long functions. Short functions do not suffer the same problems. 

Short functions, or methods if they belong to objects, are easier to read than their longer counterparts. They do little, but they do it well. They are simple. Short functions show their intent. Overall, they are more maintainable—they are easier and safer to modify.

Maintainability is paramount – this is where the real cost of software falls. It’s not in the original writing but in ongoing difficulties making code changes that dearly cost software development companies. 

OK, drum roll. How short should a function be?

Fewer than ten lines

Yes, that’s right.

A function, or method, should have a single-digit line count. [1]

I can already see the comments coming through: “WHAT? I can’t possibly make it that short! There is way too much logic.”, or “It would mean getting lost in a proliferation of small methods! No way, dude!”

Right. I understand your objections. I know that this sounds extreme; I used to think so too. I have changed my mind – it is not radical at all; in fact, it’s necessary.

A 500 line function is hard to read and maintain. One that has only five lines isn’t.

Maybe a couple of short method examples will help:

  public async Task<Customer> Register(CustomerRegistration registration)
  {
     await Validate(registration);
     var customer = registration.ToCustomer();
     await Repository.SaveCustomer(customer);
     return customer;
  }

The Validate() method definition is:

  private async Task Validate(CustomerRegistration registration)
  {
     if (registration == null)
        throw new MissingCustomerRegistration();
     registration.Validate();
     var existCust = await Repository.GetCustomer(registration.EmailAddress);
     if (existCust != null)
        throw new DuplicateCustomerEmailAddress(registration.EmailAddress);
  }

These methods from a RegisterCustomUseCase class are short, and they are clear in what they do. More functions should be like them. When reading the first method, Register(), was it confusing that the validation code was in Validate()? No, surely not. 

On the other hand, if we had left the detailed validation code in Register(), it would have represented a distraction from the high-level work Register() has to do. As careful and conscientious programmers, we want to get our abstraction level right—Register() manages the high-level workflow and Validate() handles the validation details.

 

I believe that if you give writing small, meaningfully-named functions a decent go, you’ll enjoy it.

How do we get such small functions? Next time, I’ll outline a technique that is easy to follow, generates the right level of abstraction, and helps you create beautifully short methods.

 

Footnote:

[1] For the sake of clarity, I do not mean aggressively moving the statements of a longer function into a single line or creating indecipherably terse code merely for the sake of fitting the fewer than ten lines requirement! That kind of cynical observance is more useless than having a large function.

0 replies

Leave a Reply

Want to join the discussion?
Feel free to contribute!

Leave a Reply