Is putting general-use functions in a “helpers” file an anti-pattern or code smell

anti-patternsclean codecode smellsemantics

Is it an anti-pattern or code smell to put "general use" functions (examples below) into a catch-all file named "helpers" or "utils"?

It's a pattern I've seen quite a lot in the JavaScript world, which I've also seen with other languages.

By "general use" functions, I mean functions which abstract away some common, shared functionality used in an application/library and make them available for use in a general way. Some examples I've seen include returning a copy of an object with some keys omitted, transforming all null-ish values in a JavaScript object (eg. "", null, {}, []) to undefined, constructing a URL from a struct of parameters, transforming strings in some fashion, etc, etc.

I often come across applications or libraries with one (or more!) util.js or helpers.ts files which just seem to be, in my opinion, a dumping ground for unrelated functions. In my opinion, code is more readable and discoverable if it's named semantically.

If working with the examples above, I'd place them all in their own files (omit.js, null-to-undefined.js, url-builder.ts, etc), or if they are related functionality, group them (eg, deepClone, withoutKeys, shallowClone, in clone.js or similar).

I struggle to articulate why this seems like a code smell or anti-pattern to me. I think there are various things at play: creating the wrong abstraction or abstracting at the wrong time (YAGNI) meaning code is just dumped "somewhere", lack of foresight for future maintainability.

On the other hand, I've seen proponents of this pattern argue that it's a well-used pattern, and thus it has merit simply because it's well-used. Does this argument stand?

Interesting in anyone's thoughts on this, whether you think it's good or bad, and if you can explain the pros/cons better than I can!

Best Answer

Both Java and C# have the existence proof that this works: the Math class.

The danger is the "kitchen drawer" problem, where a class simply gathers new kitchen tools and implements, many of which never get used, or only get used once.

So as long as you can keep such classes tightly focused on a theme (like the Math class is), I don't see a problem. In fact, static methods in classes of this kind tend to be easier to write, maintain and test, so long as they're always "pure" methods (i.e. referentially transparent, and you don't store static state in them).

Related Topic