4 ms·
I went the opposite direction: I used to be in the linear code camp, and now I'm in the "more functions" camp. For me the biggest reason is state. The longer
by haberman 3y ago
I went the opposite direction: I used to be in the linear code camp, and now I'm in the "more functions" camp.
For me the biggest reason is state. The longer the function, the wider the scope of the local variables. Any code anywhere in the function can mutate any of the variables, and it's not immediately clear what the data flow is. More functions help scopes stay small, and data flow is more explicit.
A side benefit is that "more functions" helps keep indentation down.
At the same time, I don't like functions that are too small, otherwise it's hard to find out where any actual work gets done.
- _dain_ 3y agoThe better solution to this is to use nested functions that are immediately called, rather than top level functions. That lets you cordon off chunks of state while still keeping a linear order of definition and execution. And you don't have to worry about inadvertently increasing your API maintenance burden because people started to depend on those top level functions later.
- jonahx 3y agoHa, I started writing my reply before seeing yours, and suggested almost the same thing.
- jonahx 3y agoSome important context re: my style... > Any code anywhere in the function can mutate any of the variables Regardless of the language I'm using, I never mutate values. Counters in loops or some other hyper-local variables (for performance) might be the inconsequential exceptions to this rule. > More functions help scopes stay small, and data flow is more explicit. Just write your big function with local scope sections, if needed (another local exception to the rule above). Eg, in JS: let sectionReturnVal { // stuff that sets sectionReturnVal } or even use IIFE to return the value and then you can use a const. "A function, you're cheating!" you might say, but my goal is not to avoid a particular language construct, but to maintain locality, and avoid unnecessary names and jumping around. > A side benefit is that "more functions" helps keep indentation down. This is important and I maintain it. See "Align the happy path to the left" (https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea88 https://medium.com/@matryer/line-of-sight-in-code-186dd7cdea...) It is also worth noting that solving this problem with function extraction can often be a merely aesthetic improvement. That is, you will still need to keep hold the surrounding context (if not the state) in your head when reading the function to understand the whole picture, and the extraction makes that harder. Using early returns correctly, by contrast, can actually alleviate working memory issues, since you can dismiss everything above as "handling validation and errors". That is, even though technically, no matter what you do, you are spidering down the branches of control flow, and therefore in some very specific context, the code organization can affect how much attention you need to pay to that context. > I don't like functions that are too small, otherwise it's hard to find out where any actual work gets done. Precisely, just take this thinking to its logical conclusion. You can (mostly) have your cake and eat it too.