Why I both hate and love fat arrow functions

When fat arrow functions were first added to JavaScript, I rejoiced.

For a language where you often end up writing small functions is place as an argument passed to something, having a concise way to define an anonymous function was really handy.

A great example would be the following 

<Button onClick={function () { console.log('clicked'); }} />

vs

<Button onClick={() => console.log('clicked'); } />

That small example is a perfect example of where arrow functions shine: small anonymous functions where the syntax for the function definition itself would almost be longer than the body body of the function.

So for a while everything was fine with arrow functions.

Then came the linting rules.

Then came everyone thinking all functions should be arrow functions.

Then… then came my hatred.

First there’s the lint rule to only allow arrow functions. We can’t use function declarations any more. Although I would prefer to choose my own style of defining a function based on what I think is suitable in the given situation, I can live with this.

Next comes the linting rule that arrow functions where the body is just a return statement must omit the function body all of the time. 

Sounds innocent. Sounds reasonable. I disagree. I think it leads to worse code. This is especially true when using this with React components. You end up with things like this:

const MyComponent = ({
  prop1,
  prop2,
  prop3,
  prop4,
  prop5,
}) => (
	<div>
          <h1>{prop1}</h1>
           <p>{prop2}</p>
           <ul>{prop3.map(x => (
             <li>
                <a href={a.href}>{a.text}</a>
             </li>
           ))}</ul>
           <div>
            <ul>{prop4.map(x => (
             <li>
                <a href={a.href}>{a.text}</a>
             </li>
           ))}</ul>
           <p>
             {prop5}
           </p>
         </div>
);

This is actually a fairly tame example. I’ve seen React components that are multi hundred line single expressions. They’re really hard to read, and therefore maintain. In addition to this, if you want to do any debugging you have to alter the function to add a body so you can use console.log or debugger on the first line. Not a huge amount of work, but still a pain in the ass.

So why do I blame things like this on arrow functions, that seems a tad unfair, no?

I blame them because the sequence which leads to code like this usually goes:

  1. Linting for only using arrow functions
  2. Component starts out small, with just a return statement and small amount of JSX
  3. Linting forces that the arrow function omits the body
  4. The component grows
  5. There’s logic added that should be put outside the return, like complex expressions to calculate props. Instead it’s done in place so the dev doesn’t have to change the function to add a body.
  6. Return expression grows and becomes hard to maintain.

Overall arrow functions represent something I’ve seen from JavaScript dev far more than developers of other languages: concise code over easy to read code. Something I say many times is that code is read many more times than it’s written, therefore devs should optimise for readability over writability.

In summary, I’m not against arrow functions per say, rather their enforced overuse. Want a simple click handler in place, or a function that is basically just a small expression of the arguments? Sure, arrow function away. Want a bigger function? Why not just use, you know… a function?

Leave a Reply

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