DEV Community

Cover image for Why limit function size?
Winston Puckett
Winston Puckett Subscriber

Posted on

Why limit function size?

I've always thought this was stupid. Not that long functions are good, but an arbitrary, artificial limit misses the point of smaller functions and encourages "procedural program page 2" type functions. That is, until I was talked with a developer I really respect about it. He said that in the 80's his limit was 24 lines. Today, it's more.

He explained that his limit to function size is the number of lines that fit on a screen. The argument being that one developer can only hold one screen's worth of information in their head at one time.

Line limits as a complimentary philosophy

I realized through our conversation that I was hoping that a line limit would teach problem decomposition. I now believe that decomposition and line limits must be taught in parallel.

Without decomposition techniques, line limits do devolve into "page 2" type functions - functions which don't abstract anything, but are simply continued on "page 2." This doesn't mean that line limits are bad. Test driven development is the same way.

TDD must be paired with understanding about how to support refactoring and how to design from the outside in. Experience with the rigid structure of TDD without true regard for its purpose builds strong resentment for the paradigm.

As a guide for abstraction

Every line of code adds one point of complexity and every level of abstraction adds 10. It's not that abstraction shouldn't happen, but consider whether you are hiding things you'll care about when you go back and read your code. Line limits give us some idea for how far to abstract things. You don't need to jump to a new method every line, but you should only care about what's happening in your code at a level that fits on one screen. Then if you need to know how a certain portion of your routine works in a more fine grained way, you're free to drill into that area of code.

Where to go from here

  1. Find out what your line limit is. Go to your IDE and check how many lines fit on a screen.
  2. Research "computational thinking." I mentioned program decomposition and abstraction in this post. These are two of the four principles of computational thinking.

Top comments (4)

Collapse
 
anders profile image
Anders

I don't have a line limit at all, it doesn't make any sense. A better limit is a complexity limit IMHO.

I think Carmack has some interesting reflections on this, its a long read but a good one: number-none.com/blow/john_carmack_...

Collapse
 
winstonpuckett profile image
Winston Puckett

This reply is getting long, and the thing I am really curious about is, how would you go about enforcing a complexity limit? I'm super curious and hope to learn something here.

I have more thoughts ... But again, I realize they're kinda long lol.
About the post:
I think the point I was attempting to make above is that line limits can point to problem decomposition and abstraction problems if they're taught alongside each other.

When you comment large your code instead of moving it to a separate function, I think that sudo-subfunction becomes the place where line limits could be enforced :)

Thoughts on the link:
That was an interesting read. I think the claim that "style c," as John puts it, makes code cleaner is false. The code base I live in right now uses style c and still has lots of duplicated code and unnecessary complexity. For instance, there's a variable called "isPoChanged" on line 3 and a variable called "isPOChanged" on line 500 that is entirely different. They're in the same scope and get used throughout the rest of the function.

I like what he said here:

"If something is going to be done once per frame, there is some value to having it happen in the outermost part of the frame loop, rather than buried deep inside some chain of functions that may wind up getting skipped for some reason."

Collapse
 
anders profile image
Anders

I think your variable example there certainly would qualify as a place where you would benefit from splitting it into multiple functions =)

But it doesn't really relate to the LENGTH of the function, it's more about what it does, the number of variables and concepts that are in the function.

At the core code should do two things:

  1. Work
  2. Be easily understood.

We have functions that are 100:s of lines long, and that is fine because the flow is simple to follow. We do use comments for “sections of code” that could be moved into sub functions, this is to make it more easily parsed by a human.

Some cases where you definitely want sub functions:

  • There is a lot of “local state”, especially if there is very little shared state with the “root” function.
  • There are multi level nested conditions and or loops
  • A non trivial part of the code is repeated multiple times, ex: you need to format a date a certain way, that happens 12 times, sub function that. If it happens twice, and the code to do it is very simple, probably inline it.

Imagine a simple case where we have a function that renders a simple view in a web app, it creates a list of three different types of things, each of these is rendered entirely differently from each of the others, but it is the same view, and the output is very simple. For each collection we have 20 lines of presentation logic. Applying an arbitrary “max 40 lines per function” forces this to be split into 3 functions (or a real weird set of 2 ; ). Forcing the person who modifies the view to handle 4 functions (root and sub functions). And provides no actual benefit compared the “C” style as outlined by Carmack.

But as always, it's always about trade offs. And I don’t think there are any “hard rules”. You and your team need to find what is reasonable for you.

Thread Thread
 
winstonpuckett profile image
Winston Puckett

Thanks for explaining :). It's funny, the other day I was playing with a nav menu in Blazor and ran into that situation.

I definitely agree that "do what makes sense" is more important than an arbitrary rule.