22

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.

Diversity
  • 329
  • 1
  • 2
  • 7
  • 2
    Possible duplicate of [What are the valid uses of static classes?](https://softwareengineering.stackexchange.com/questions/266938/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
  • "I think static should be removed from Java. Especially now where it is possible to use even more sophisticated functional language elements." This is a strange position to have since the introduction of functional elements to Java leads to static helper methods being *more* appealing. If you have a common filter condition, why not define it as a static method and pass references to the filter method. What do you think is preferable to that? – JimmyJames Jul 19 '18 at 20:18
  • @JimmyJames *"why not define it as a static method and pass references to the filter method."* Because in Java you cannot have a "reference" to anything static. What you are refering to are *functional interfaces* implemented as *lambdas*. At the bottom this are *anonymous inner classes*, not "static references". – Timothy Truckle Jul 19 '18 at 20:27
  • @TimothyTruckle Java 8 introduced the method references e.g. `ContainingType::methodName`. Read about it here: https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html – JimmyJames Jul 19 '18 at 20:34
  • I think this question would be better whitout so much answers in it. – Alex Jul 19 '18 at 21:58
  • @JimmyJames *"Java 8 introduced the method references e.g. `ContainingType::methodName`."* - Right, but they also refer to *member methods*, not to `static` methods. (and are nothing more than *syntactic sugar* for shorter lambda expressions) – Timothy Truckle Jul 20 '18 at 08:40
  • @TimothyTruckle "but they also refer to member methods, not to static methods" I'm confused by this statement. Method references can refer to member methods, static methods, and constructors. What do you mean by "not static methods"? – JimmyJames Jul 20 '18 at 13:23

5 Answers5

22

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.

Deduplicator
  • 8,591
  • 5
  • 31
  • 50
  • I don't see why "free functions" require to be `static`. *static access* always leads to tight coupling which should be avoided. – Timothy Truckle Jul 19 '18 at 08:03
  • 2
    @TimothyTruckle Either they are static, or they have a superfluous `this`, and require something be instantiated appropriately – Caleth Jul 19 '18 at 08:18
  • 6
    @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 08:22
  • 1
    @Caleth ok, I agree. But *require something be instantiated appropriately* is not something bad in an OO language (free function belong to a *Functional* language and the tight coupling along with the *hidden dependency* is still a problem of *static access* at least in Java. – Timothy Truckle Jul 19 '18 at 08:23
  • @TimothyTruckle you don't have to use *static access* to access *static functions*. They can just be instances of a function interface that you pass around – Caleth Jul 19 '18 at 08:24
  • @nvoigt *"Whether that's good or not is entirely up to what the function in question does."* I agree as long as the function does not maintain state (directly or indirectly) – Timothy Truckle Jul 19 '18 at 08:30
  • 5
    @TimothyTruckle Absolutely, maintaining state would be the prime reason for being "not good". – nvoigt Jul 19 '18 at 08: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
  • @DavidArno: Made special notice that shared mutable state, especially the global kind, remains evil. – Deduplicator Jul 19 '18 at 11:27
  • 1
    @TimothyTruckle Use of static methods does not *always* lead to tight coupling. Calling a stateless static function that knows nothing about it's callers is not [tight coupling](https://stackoverflow.com/questions/2832017/what-is-the-difference-between-loose-coupling-and-tight-coupling-in-the-object-o) – JimmyJames Jul 19 '18 at 20:11
  • @JimmyJames: *"Calling a stateless static function that knows nothing about it's callers is not tight coupling"* Well, you cannot simply exchange the function accessed, so the *using code* has tight coupling to the static function. – Timothy Truckle Jul 19 '18 at 20:16
  • 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
  • 1
    @JimmyJames *" Tight coupling in this context would imply some sort of inter-dependency. A one-way dependency does not meet that requirement."* A "two way dependency" is not *tight coupling* but a *design error*. – Timothy Truckle Jul 20 '18 at 08:35
  • @TimothyTruckle Only depending on public interfaces is weak coupling: The internals are free to change. Dependency-injection is a tool for special cases, not to be abused and overused, as it increases complexity and (generally) reduces efficiency. – Deduplicator Jul 20 '18 at 09:01
21

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.

Greg Burghardt
  • 34,276
  • 8
  • 63
  • 114
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.

Tracker1
  • 314
  • 1
  • 5
  • *"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!

Lewis Pringle
  • 2,935
  • 1
  • 9
  • 15
2

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.

Timothy Truckle
  • 2,336
  • 9
  • 12
  • 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 07:59
  • 1
    You can use static free functions without coupling. You pass around `Func` objects, which are instantiated elsewhere. – Caleth Jul 19 '18 at 08:20
  • @Caleth then they are not `static`. And BTW: this is exactly what I wrote. – Timothy Truckle Jul 19 '18 at 08:27
  • @TimothyTruckle it's not clear to me. It sounds like you are only considering the `Math.abs(var)` *use* of static methods, where I agree the surrounding scope is coupled to `Math` – Caleth Jul 19 '18 at 08:30
  • If you inject the state as an object info a class it is no longer global. You can pass it into s static function as well, if there were any state to handle. I still don't see any difference. – max630 Jul 19 '18 at 08:56
  • @max630 changing the state of some other object passed as parameter is *not* maintaining state... – Timothy Truckle Jul 19 '18 at 08:59
  • 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
  • And as with everything else here in life, an extreme approach in either direction is rarely pragmatic. The challenge is in the balance: To make detailed technical evaluations based on actual technical effects, instead of trying to get around it with ideological substitutes. "static helper classes are anti pattern" sound like ideology to me. – Alex Jul 20 '18 at 14:43
  • @Alex *"I generally think that hiding implementation is a good thing, where it's suitable."* I was talking about hiding **dependencies** not implementation. – Timothy Truckle Jul 20 '18 at 15:33
  • @Alex *"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."* this painful changes are usually the result of another codesmell: violation of "tell, don't ask" and the "Law of Demeter: Don't talk to strangers!". – Timothy Truckle Jul 20 '18 at 15:35
  • A. But isn't the dependencies of a function a reflection of its implementation? I don't think we can talk about them as two separate things. B. Object-orientation and its principles is another paradigm, as far as I know we haven't all agreed that it's the one and only truth. – Alex Jul 20 '18 at 16:55
  • @Alex *"But isn't the dependencies of a function a reflection of its implementation?"* No, because it is an *dependency*. A dependency is something that has *a different reason to change*. **/** *"I don't think we can talk about them as two separate things."* I think we cannot pretend it is the same. – Timothy Truckle Jul 20 '18 at 17:25
  • @Alex *"Object-orientation and its principles is another paradigm, as far as I know we haven't all agreed that it's the one and only truth."* But Java ia an OO language after all (despite that it has *some* FP features). So I believe when coding in Java it is a good thing to follow the OO paradigm. – Timothy Truckle Jul 20 '18 at 17:28
  • Hmm... I'm sure the primary meaning of a "dependency" is a resource of some kind that something is dependent on to be able to "do something". Regardless of whether the type or implementation of the dependencies change or not. And depending on how a function is designed to do something, it might require completely different dependencies. I'm not saying that implementation and dependencies is the same thing, but that they are highly correlated. Java supports OOP, but I think we usually say that it like most other languages supports multiple paradigms and allows you to choose yourself. – Alex Jul 20 '18 at 18:26
  • 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