89

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
  • 12
    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 Mar 2 at 14:10
  • 6
    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 Mar 2 at 18:35
  • 7
    I would see it as bad code if same/ similar code was in more than one place – tgkprog Mar 2 at 18:56
  • 6
    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 Mar 3 at 1:59
  • 1
    Related: stackoverflow.com/questions/40996614/… – VGR Mar 3 at 13:05
97

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
  • 7
    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 Mar 2 at 20:02
  • 40
    That's a developer discipline problem, not a best practices problem. – Robert Harvey Mar 2 at 20:34
  • 4
    @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. – FrustratedWithFormsDesigner Mar 2 at 21:46
  • 11
    @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. – Captain Man Mar 2 at 22:05
  • 12
    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 Mar 3 at 3:37
37

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. – Robert Harvey Mar 2 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 Mar 4 at 21:52
31

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 Mar 3 at 4:35
  • 17
    @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. – Fred Stark Mar 3 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 Mar 3 at 15:06
  • 3
    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. – user3840170 Mar 4 at 9:01
  • 1
    @user3840170 That's a good comment, but it's also important to note that what the answer is saying is that sometimes a function should be called is_not_empty_string, not is_foo_compatible_string, because that is not the appropriate place to abstract the details of what makes a string foo-compatible, but the unfocused concept soup that is "utils" files makes it easy to end up in a situation where it's hard to even determine if the function should current be called that, or should have ever been called that. – mtraceur Mar 4 at 23:24
15

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
  • ConsoleUtils is a silly module, IMO. Just name it Console and be done with it. – Lie Ryan Mar 3 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.

8

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.

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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