105

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!

9
  • 15
    I think when you are first starting out I see no harm in this. As your project grows, you might see the need for more organization which would mean multiple files and folders. At that time a refactor may be necessary if the helpers file grows to a point of not being manageable.
    – Jon Raynor
    Commented Mar 2, 2021 at 14:10
  • 7
    Do not just make a file called utils.ext or utilities.ext and stick it in your main folder with all your other files. Segregate the utilities by "kind" and give the file a proper name. Alternatively, perhaps better, do call it "utils" but stick it in a subdirectory with a proper name. You will figure out why the second someone else (or you, 2 months from now) wants a different "utils" file ...
    – davidbak
    Commented Mar 2, 2021 at 18:35
  • 9
    I would see it as bad code if same/ similar code was in more than one place
    – tgkprog
    Commented Mar 2, 2021 at 18:56
  • 11
    I personally use a util folder instead of a util file. Not every module need every util. So for example I have util/formatters.js and util/strings.js
    – slebetman
    Commented Mar 3, 2021 at 1:59
  • 2
    Related: stackoverflow.com/questions/40996614/…
    – VGR
    Commented Mar 3, 2021 at 13:05

11 Answers 11

102

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).

8
  • 8
    Thanks for the comment! I agree that classes like Math which contain related functionality are useful, however I think the problem I am working against is a bit different. My problem is that arbitrary, unrelated code is just "dumped" into a helpers.js file because the author couldn't think of a better than or more logical place for the code to live.
    – old greg
    Commented Mar 2, 2021 at 20:02
  • 43
    That's a developer discipline problem, not a best practices problem. Commented Mar 2, 2021 at 20:34
  • 5
    @jimmysumshugar You could try a refactoring exercise of trying to create 3 (or some other number that you think is better) categories for the functions in the "helpers" file, and then see how many functions can be moved to more specific "helper" files. Commented Mar 2, 2021 at 21:46
  • 12
    @RobertHarvey I read the question differently and I think this is what OP's comment is getting at -- Java/C#'s Math class is what OP believes is better. They're suggesting (or asking rather) that files of unrelated functions are bad. I.e., if all of Java's classes that have only static methods were in a single class called Utils or something. Commented Mar 2, 2021 at 22:05
  • 13
    This answer gives an impression like "this is good, so long as you keep it properly focused and give it descriptive name like 'math' for math helpers", but the question is asking about catch-all (not focused on a theme) files with names like "utils" or "helpers" which give only the loosest of hints about what's going on inside them. (Maybe this answer is next-level human-chess plays? Reel in the kind of people who put stuff in a "utils" file with affirmation, and then inject them with some actual wisdom about what they should be doing while they're receptive?)
    – mtraceur
    Commented Mar 3, 2021 at 3:37
42

My criterion is: If you needed a function from the "helpers" file, would you find it? Or would you write your own version, use it, and put it into the "helpers" file together with two other almost identical functions?

So this needs to be organised, and should be done in such a way that your development tools can help you. For example, with Xcode / Swift you can add extensions to existing classes, and methods in these extensions will be used as code suggestions and are reasonably easy to find. On the other hand, if you add a standalone function, there are so many standalone function, you have no chance to find it unless it is named really well. Other development systems might want different approaches.

2
  • 5
    C# also has "Extension Methods." They are essentially syntactic sugar over ordinary static methods, although they do associate the methods with the type they operate on and work well with Intellisense in Visual Studio. Commented Mar 2, 2021 at 23:03
  • Kotlin has extension methods, too, with (what sound like) the same advantages.  In my experience converting Java apps to Kotlin, most helper methods fit very naturally as extension methods, with very few stand-alone functions needed.  — This suggests that in other languages, stand-alone functions could be organised according to the type they deal with: StringUtils, CharUtils, CollectionUtils, ArrayUtils,… to keep them focussed and easy to locate.
    – gidds
    Commented Mar 4, 2021 at 21:52
36

Putting commonly used functions into a single file is not on its own an antipattern. But there are many antipatterns associated with this:

  • Grouping functions whose only common property is reuse is not very maintainable. Usually grouping should be based on some stronger relatedness criteria. For example, the API part of an application might have utility methods for returning common responses, which is completely fine.
  • Overly generic names, like an isEmpty which only really checks whether a string value is empty.
  • Overly specific names, where nobody would guess that isFooCompatibleString really should be isNotEmptyString.
  • Lack of testing, spreading subtle bugs until some code inevitably starts relying on the buggy behaviour.
  • "Utility" functions which are only used in one place should not be moved into a utility file - YAGNI.
  • In interpreted languages like JavaScript I believe importing a single function from a file results in the whole file being loaded into memory (somebody will be able to correct me on this). When writing an application where performance or size is paramount this could be a problem.
13
  • 2
    For the last point, JavaScript is client-side, so by definition it MUST load the whole file before the browser even tries to parse it. By extension, this means that every tiny little thing included in JS will have to all be loaded before it runs. If any of them returns a 404 or some other network error, your page stops loading from that point onward. If it happens early enough you get an entirely blank page (e.g. a failed jQuery include in the header section.
    – Nelson
    Commented Mar 3, 2021 at 4:35
  • 20
    @Nelson JS hasn't been purely client side for over a decade. It's also false to say that a webpage immediately stops loading once the first linked script or resource 404s.
    – coagmano
    Commented Mar 3, 2021 at 6:34
  • 1
    In JavaScript, loading a module will parse everything, but I think the objects that aren't imported or referenced from the objects you import will quickly become garbage. The same with using from module import ... in Python.
    – Barmar
    Commented Mar 3, 2021 at 15:06
  • 4
    isFooCompatibleString is different from isNotEmptyString, as the definition of ‘foo-compatible’ may potentially change over time (depending on what foo is), while non-empty strings will always be the same thing until the end of time. Commented Mar 4, 2021 at 9:01
  • 2
    @user3840170 and @mtraceur are both correct. isFooCompatibleString doesn't belong in a general utils file/class, but it should be abstracted somewhere adjacent to Foo, even if it (currently) only calls out to isNotEmptyString.
    – Mikkel
    Commented Mar 5, 2021 at 16:50
17

It's all about the balance and good taste in scope.

It's perfectly fine to have a ConsoleUtils module that contains all Utilities that are helpful when working in console. Those can range from displaying tables, through creating users, to statistics code.

On the other hand, on one side lies the Kitchen Sink, on the other lies Functional Decomposition (Litter is my pet name for it) - thousands of modules each containing 1-2 methods, essentially re-creating procedural programming, but with lots of namespaces.

Having said above - reason why you run into this anti-pattern a lot in JavaScript - is because it's a scripting language that was not designed and is not meant to be used for programming anything else but simple forms. Language that until recently didn't even have iterators, classes, or anything really that modern programming languages have.

It's standard lib was (and still is really) also incredibly poor, hence the rise of "JavaScript frameworks" and having libraries to pad a string (something that's a part of stdlib even in C). Lots of those issues are still present in Node.js too.

1
  • 1
    ConsoleUtils is a silly module, IMO. Just name it Console and be done with it.
    – Lie Ryan
    Commented Mar 3, 2021 at 11:09
12

It's not a terrible thing, but if you can group them a little tighter than just "util"/"helpers", that's better. For example, shallowClone and clone and other related functionality sound like they should be in a clone-utils.js file.

11

Its definitely a code smell, just because its such a common thing to collect together random unrelated code into a single "helper" library which everything then depends on and becomes a blocker to refactoring.

ie. you cant change helper.isNull() to return true for some new case, say a blank string because its so widely used you can't tell what it might break.

Also with a large collection of functions, other projects which use the library tend not to bother upgrading unless the function they use changes. Thus you end up with many projects using old very old versions which can't be updated due to cumulative changes resulting in large breaking changes to the library's use.

Vaguely related 'official' libraries such as Math avoid this problem because the functions in them are so rigorously defined that they never change.

But even in these cases we have issues, such as when cryptography specifications change or are interpreted differently on different platforms.

10

It is not necessarily an anti-pattern per se. But it quickly devolves into one if care is not taken.

First things first: Going the complete opposite isn't good, either. If you have a folder util/ and put every function in its own file, like deepClone.ts, shallowClone.ts, then that is not any better. Instead of a file, your dumping ground becomes a directory. A directory has the added disadvantage that it blows up your import statement significantly.

So basically, that leaves us with the middle ground: Put some stuff together, and some stuff apart. Again, you could do this with one file per function, like util/clone/deep.ts, util/clone/shallow.ts. That way, you get to group semantically similar functions together. But you still blow up imports. So putting it into a single util/clone.ts file seems appropriate.

But... that is not what a single helpers.ts file is, is it? A single helpers.ts file often is a kitchen sink gobbling up completely unrelated functions. Its a mess, and nobody really knows what goes in there and what doesn't.

So, my answer would be: Utility files that group together static functions aren't bad. Java's Math class has already been given as an example. Apache Commons has IOUtils. But notice something? Both have a clearly defined theme/topic around which functions are grouped. They precisely aren't kitchen sink collections of completely unrelated stuff.

With the examples you have given, I would probably organize it like this:

.
├── util
│   ├── url.ts
│   ├── clone.ts
│   │   ├── shallowClone
│   │   └── deepClone
│   └── string.ts

I've only added a couple of actual functions, but you get the gist.

1
  • Love how you give actual examples - very helpful for beginners.
    – hokwanhung
    Commented Dec 14, 2023 at 2:51
4

No, they're not an anti pattern.

However, if this file grows bigger than what you're comfortable with and there are actually big sets of functions with related functionalities, then it does become a smell.

By itself though, there's nothing wrong with having a random utility tool belt, if it's useful and it works, then don't let anyone else tells you that it's not fine.

However, you should regularly refactor the file and move functions that have outgrown the file into their own proper modules, otherwise there's a tendency that you'll just leave the functions there growing related functions without ever graduating into a proper module.

Putting single functions into dozens of files just to avoid having to have utilities file would've been maintenance nightmare. It'll just make it much harder to find what you need, adding additional complexity with very little benefit.

Utility functions often start out as utilities because you weren't sure what kind of related utilities you're going to be needing in the future. In such case, putting the function into their own files too early may mean the you'll end up with module names that may not make sense with whatever future functions that you end up creating. So putting it in the toolbelt is actually the less bad.

However, there's a couple additional considerations for certain scenario's.

First consideration is in front-end languages, such util files will eventually end up in a file that the user needs to download and will use up memory. If your util file ends up containing large number of functions that some large sections that your users never need to use, that's a practical problem you'll also need to address. You may opt for a compiler that can automatically remove unused functions, or you may want to do the reorganization manually, but either way any functions that the user have to download and execute should be either something that the user needs either now or they need it very soon.

Second consideration is if you're writing a library and you package and publish it for large number of other people to use, having such utilities would be more problematic because people will depend on them. Avoid having public functions in a util file/module. If a utility becomes so useful in your library that many people are seeking to use it, put it into a proper module.

4

Indeed "util.js" or "helper.js" tells you very little about what you can expect to find.

Will it help you compute a Fourier transform? Who knows?

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).

One the other hand, a directory with a file for every function is bit unnavigable.

The answer is Hierarchy.

Code should be arrange in a hierarchical manner (directories, files, namespaces, classes, functions) so that someone looking for something can navigate there, making educated guesses about where the code would lie, if it existed.


Some examples I've seen

Were this my project, I'd put these in three files.

include returning a copy of an object with some keys omitted

transforming all null-ish values in a JavaScript object (eg. "", null, {}, []) to undefined

object.js

constructing a URL from a struct of parameters

url.js

transforming strings in some fashion, etc, etc.

string.js


But again, the key is organize with a non-extreme amount of content at each level.

Should I have a 5000-line or 50-function object.js file, I'd think about whether there are any sensible subdivisions of that.


EDIT: And there may be other considerations. For example, JavaScript bundlers may have a tough time tree-shaking unused code from files. You may choose to divide code into more files if this is the case.

1

While util and helpers libraries tend to attract flies, they reflect a fundamentally unsolvable problem of organization.

I can group math-related utility functions into a Math library if (and only if) I have more than just one math-related function. And therein lies the flawed assumption that every rule and recommendation fails to consider.

Say I have a SquaredDistance function duplicated throughout my code, I could factor that function out into a library and reference it throughout my project; that's what libraries are for, after all. I could create a Math library containing only SquaredDistance. A bit grandiose to call the library Math since it doesn't really do Math, it just does that one thing. I could just as well call it Geometry or PointCalculations, but those aren't better. Calling it Math makes sense if (and only if) there's the slightest chance I'd add more math functions down the line. I might as well call it SquaredDistance.lib and stop pretending it's anything more than that. Though... that feels wrong for some dumb reason.

... And now say I also have a InvokeWithRetry function that repeats HTTP calls on failure with exponential backoff. Moving it to a library reduces copy-paste duplication -- so do I call that library Http or perhaps Net or maybe just InvokeHttp or Retry. If I don't have another function fitting any of those categorizations, it doesn't really matter, does it?

So eventually I end up with a dozen different one-off libraries:

  • Math containing only SquaredDistance
  • Net containing only InvokeWithRetry
  • Strings containing only NormalizeUnicodeHomographs
  • Reflection containing only GetStructureOffset

...and so on.

Is it better that I refuse to put these into a single shared Util library? In terms of runtime efficiency, assuming these functions are all used, it's measurably worse. In terms of code quality? What exactly am I gaining by not grouping them together?

It's hard to say. Probably nothing.

0

Technically speaking it is a "code smell or anti-patern", it isn't scalable.

Knowing the context it might not seem that much of a "code smell or anti-patern". When going to add a new feature, a new feature implies there is nothing implemented related to the feature, not knowing the existing code it might end-up with duplicate implementation of common use cases since it is counter-intuitive to first go over the existing code base to verify whether the feature to be developed it really is new or it is just an addition to something already existing. Having everything in a helper/util/commons file facilitates getting familiar with existing util implementations and avoid duplications. Sure there are automated tools helping with this type of concern that in companies developing commercial software they could be an option just complying with the legal frame those tools are distributed. From this stand point it might be efficient to go with general-use code in a helper/util/common file, otherwise it is moving the "code smell or anti-pattern" from the code encapsulations to legal frame or reconsidering what a "code smell or anti-pattern" is.

Not the answer you're looking for? Browse other questions tagged or ask your own question.