16

I am often confrontated with helper or util classes in Java or whatever kind of language. So I was asking myself if this is some kind of Anti Pattern and the existence of these kind of classes is just a lack of missings in the design and architecture of a Software.

Often these classes are confined using just static methods, which do a lot of things. But mostly it is indeed context dependent and statefull.

My question is, what is your opinion about such kind of static helper/util classes because the advantage is of course the fast invocation using just the class name.

And at what kind of abstraction level you would avoid using these kind of classes?

In my opinion the keyword "static" should just be allowed within the declaration of a class (Java) and not for methods. In my opinion is that using it at this way, it could be a good alternative and middleway to be able to combine Procuedural- and OO-Paradigms in Java and avoid missuse of the keyword.

Additions due to the answers:

At first I think that it is completely legal to be able to combine different paradigms and even use runtime interpreted scripting languages within machine or vm compiled code.

My experience is that during the development process of a project such kind of helpers and utils or whatever the name is, are growing and growing and used within every forgotten corner of the codebase, which was originally designed to be modular and flexibel. And due to a lack of time to make refactorings or think about the design again you just make it much worse over the time.

I think static should be removed from Java. Especially now where it is possible to use even more sophisticated functional language elements.

  • 2
    Possible duplicate of What are the valid uses of static classes? – gnat Jul 18 '18 at 20:54
  • I think if the helper doesn't need to instantiate a class, it's fine. The problem is when the helper instantiates a concrete implementation of a class and then you are not able to mock that interface. If the helper gets passed an interface or an abstract class I think it's ok. – bobek Jul 18 '18 at 21:16
  • It's fine if you claim doing procedural programming. It's not if you claim doing object(-oriented) programming. – Spotted Jul 19 '18 at 11:58
  • 1
    @Spotted: and as there is no business value in claiming you do solely object oriented programming, just always do mixed paradigm programming and get shit done. – RemcoGerlich Jul 19 '18 at 12:03
  • @RemcoGerlich Exactly. My point was to note the that the answer is mainly "philosophical", related from which programming paradigm you consider it. – Spotted Jul 19 '18 at 12:06
19

Well, Java lacks free functions, thus you are forced to put them as static functions into some pro-forma class. A necessary work-around is never an anti-pattern, though it might lack elegance.

Next, there's nothing wrong with free functions. Actually, using free functions reduces coupling, as they only have access to the public interface instead of all the gory details.

Of course, using free/static functions does not in any way alleviate the dangers of mutable shared, especially global, state.

  • 2
    @TimothyTruckle Either they are static, or they have a superfluous this, and require something be instantiated appropriately – Caleth Jul 19 '18 at 8:18
  • 4
    @TimothyTruckle Because it's Java. Other languages can have free functions without the overhead of having to put them into a class only to declare it not being an instance method. And at some point, you have to have tight coupling. Whether that's good or not is entirely up to what the function in question does. – nvoigt Jul 19 '18 at 8:22
  • 5
    @TimothyTruckle Absolutely, maintaining state would be the prime reason for being "not good". – nvoigt Jul 19 '18 at 8:48
  • 2
    @nvoigt, I feel this answer would be greatly improved by explicitly stating that point. Stateful statics are bad; stateless ones are good. Really quite simple. – David Arno Jul 19 '18 at 10:54
  • 3
    @TimothyTruckle That's not tight coupling. You are describing loose coupling. Tight coupling in this context would imply some sort of inter-dependency. A one-way dependency does not meet that requirement. – JimmyJames Jul 19 '18 at 20:31
16

Static utility or helper functions are not an anti pattern if they adhere to some guidelines:

  1. They should be free from side effects

  2. They are used for application specific behavior that does not belong in the class or classes on which these functions operate

  3. They do not require any shared state

Common use cases:

  • Formatting dates in an application specific way
  • Functions that take one type as input and return a different type.

For example in an application I worked on users keep journal entries for their activities. They can specify a follow-up date and download an event reminder. We created a static utility class to take a journal entry and return the raw text for a .ics file.

It didn't require any shared state. It didn't mutate any state, and creating an iCal event certainly was application specific and didn't belong in the journal entry class.

If the static functions or utility classes have side effects or require shared state I would recommend reevaluating this code, as it does introduce coupling that can be difficult to mock for unit testing.

4

It will depend on your approach. Many applications are written with a more functional, as opposed to classical mindset (including much of the suite of sites you are on).

With this mindset, there will be many utility methods on worker classes that can be strung together as static methods. They are fed/use closer to plain objects that only hold data and get passed around.

It's a valid approach and can work very well, especially at scale.

  • "can work very well, especially at scale" No. The tight coupling cause by static access will soon stand in your way as the project grows. – Timothy Truckle Jul 18 '18 at 21:02
  • @TimothyTruckle Could you explain how Agent.Save(obj) is so much more tightly coupled than obj.Save() ? Agent is just as capable of getting a DI/IoC reference, even for static methods as a a class instance. For reference Stack Exchange itself is written in this type of mindset, and has scaled better than any other ASP.Net app with fewer resources than any other I am aware of. – Tracker1 Jul 19 '18 at 18:08
  • " Could you explain how Agent.Save(obj) is so much more tightly coupled than obj.Save() ?" This is the wrong example. A correct example would be Agent.Save(obj) vs. agentInstance.Save(obj). With the latter you have the possibility to inject agentInstance into the using code. In consequence you can inject any child class of Agent too which allows the reuse og the using code with different "types" of Agent without recompiling. This is low coupling. – Timothy Truckle Jul 19 '18 at 20:22
  • I think it really comes down to a couple things. Is state needed, how flexible does it need to be, and is it ok to have a global/instance state? That's up to each dev/architect to decide. I'd prefer a simpler codebase over adding complexity for scenarios that make everything more difficult to understand as a whole. One of the things I love about node/js is that I can write simple/clean code and still inject for testing without the code written to DI/IoC specifics. – Tracker1 Jul 20 '18 at 16:55
2

I personally think the only important part about such helper classes is that they be made private. Besides that - they are strictly a good idea (applied sparingly).

The way I think about this - is if in implementing a class (or function) - something like this is helpful, and makes that implementation clearer, how could that be bad? And OFTEN its critical to define such private helper classes to allow integration with and use of other algorithms which depend on data being in a particular shape.

Whether to label it 'helper' is a small matter of personal taste, but it connotes that it helps in implementation and its of no interest/use to a wider audience. If that's what makes sense - go for it!

  • 1
    Public utility classes might still be helpful. Prime example: java.lang.Math. – amon Jul 19 '18 at 6:51
1

The prevalence of static helper classes in based on a misconception. Just because we call classes with only static methods "utility classes" does not mean that it is not allowed to write common behavior in POJOs.

static helper classes are anti pattern for three reasons:

  1. The static access to this helper methods hides dependencies. If these "utility classes" were POJOs you could inject them int to a dependent class as constructor parameters which would make the dependency obvious for any user of a dependent class.

  2. The static access to this helper methods cause tight coupling. This means that the code using the helper methods is hard to reuse and (as a side effect) hart to test.

  3. Especially if they maintain state these are merely global variables. And hopefully nobody argues that global variables are any good...

Static helper classes are part of the STUPID code anti pattern.


Global state is unrelated to the question, – max630

The OP wrote:

But mostly it is indeed context dependent and statefull.

Static statefull constructs are global states.

any kind of code can use it. – max630

Yes, of cause. And almost all applications need some kind of global state.

But global state != global variable.

You can create global state with OO techniques via dependency injection But you cannot avoid global state with statefull static structures which are global variables at the bottom.

  • 2
    Global state is unrelated to the question, any kind of code can use it. – max630 Jul 18 '18 at 21:53
  • @max630 please see my update – Timothy Truckle Jul 19 '18 at 7:59
  • 1
    You can use static free functions without coupling. You pass around Func<Result, Args> objects, which are instantiated elsewhere. – Caleth Jul 19 '18 at 8:20
  • 1
    1) I generally think that hiding implementation is a good thing, where it's suitable. 2) Having everything as arguments/dependency-injected also creates a kind of design-time coupling, you can feel this when you find yourself having to spend a lot of time on changing signatures in long dependency chains. And like having every single function requiring your Logger, or other cross-cutting concerns, as an argument, urgh... (But yes, it can make low-level testing harder) 3) Of course static functions should be stateless. – Alex Jul 20 '18 at 14:38
  • 1
    @Alex Then let me say it the other way around: A unit is any bunch of code (including static referenced "utility" methods) that has the same reason to change. Anything inside this unit is implementation detail. Anything else is a dependency, and the unit should not have static access to it. – Timothy Truckle Jul 20 '18 at 18:38

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.