Void Methods Considered Anti-Pattern
If you want to know why you should avoid void methods, this article is just for you. Here you can find all their sins and see how they can impact your system.
Join the DZone community and get the full member experience.Join For Free
Today's topic is quite different from all of my previous topics. Today, I will let myself loose and hopefully trigger a discussion, at least in the comments, regarding the usage of void methods in our code and if we should consider them a code smell. I will cover some basics of void keyword and mention cases when we may see it as beneficial to use methods with this keyword. Then I will provide arguments to show you that, in the end, it may not be such a good idea.
But first, please keep in mind that this text is written from the perspective of the Java language and some cases may not be applicable in your favorite language.
Void Keyword Purpose
As any other keyword, void has a reason to exists – or it at least seems to. In Java, as in other languages derived from C, it is used to describe methods that are executed normally but do not provide returned value to its caller.
It is worth mentioning that in Java, alongside void keyword we have Void type which is used to represent the void return type as a class. It has only a private constructor so we cannot instantiate it. Additionally, the only value we can assign to a Void variable is null.
When and Why We May Need Void Methods?
In most cases, we use void methods when we need to perform an operation with some kind of side effects. The most common use case of void methods is System.out.println which prints desired text to standard output.
Other examples are:
- Running a job or task, like running your Java app with the main method
- Performing database query
- Using bean life-cycle annotation, like @PostConstruct
- Setters for your object properties are voids by default
Additionally, some libraries or APIs you have to integrate with use void methods and, by extension, you need to use them too. javax.mail library may be a good example here. Its most important method, SendMessage, is void so even if you prefer not to use voids yourself, you still may be forced to do it.
About why we use void methods - as usually, it depends. For example, in case of printing it may be hard to come up with what exactly should be returned. The same holds true for running jobs or tasks but there the matter is more complex. For life-cycle annotations, there is nothing that they can return. They are just simple hooks and that is all, even if we decide to return something from such method it will be omitted anyway.
As you can see void methods seem pretty useful, so now you may be tempted to ask: Why exactly do I believe that we should avoid them if they are so helpful? – and as usual, I am here to help you and provide the answer.
Why Using Void Methods Is a Bad Idea?
Break encapsulation may lead to leaking some unnecessary implementation details of our application. Additionally, it could result in needing more in-depth knowledge of system from anyone interested in contributing to or solving some tasks around app. It may not be a case for a relatively simple code base, but it will for sure show its full “glory” in a larger application. Even so, I am sure that almost everyone of us forgot to call a method like public void doSth(..arguments) and spent an hour or so thinking, “why is my code not working?”.
Do not provide any contract, in terms that we have input and output, we just have input and after input we have magic. We have to guess what exactly is going on inside the method. In my opinion, it is the biggest problem with void methods. You may notice that it is the reason behind all of the other problems described below, at least in some part.
Can limit local reasoning because you lose information about what is actually returned by method. You have to dive into implementation to get knowledge about the expected outcome of method execution. Of course, descriptive naming may reduce the impact of this issue but still, normal methods provide more information, and what is even more important is that such information is more visible for the reader.
Are significantly harder to test. Lack of returned value makes it impossible to perform any kind of assertion-based tests known from libraries like JUnit. To verify if our method works as desired we will have to check the state of object it modifies (simple case) or state of some test database which plays the role of production counterpart (complex case). It can get even worse when we are forced to use methods like .spy() (which itself is worth a similar article), from libraries like Mockito, to verify correctness of particular method inner workings.
Live only thanks to the side effects (another semi anti-pattern especially in functional programming). If you want to avoid or limit them in your codebase you should also stay away from void keyword.
Tends to spread very fast across codebase because it looks like an easier and faster way to implement what we need.
Above you can find some useful tips for preparing a good spaghetti code. Back to being serious, these are my fundamental arguments against using void methods. If you disagree with any of them or have another argument to support my view I invite you to the comment section of this article to have a cultural discussion over the topic.
As we are slowly reaching the end of today’s reading there is one more important question to ask.
Are All Void Methods Bad?
Certainly not, but most of them are. Tasks like printing to console, logging to file or sending mails are good examples of when void methods may be used without causing too many problems. However, in almost any other case they should be avoided and used in as limited fashion as possible, at least in my opinion.
If limiting the use of voids is impossible you should focus on limiting their impact on overall application. For instance, you can put them as low in your execution order as possible. Therefore, any failure of such method can be better isolated and overall impact on style and inner workings of our codebase will be lessened.
I will say it one more time just to be clear: in most cases void methods are bad and should be considered anti-pattern, using them may lead to a very tasteful spaghetti code where everything is implicitly stateful.
I have presented my view on using void methods and provide a hopefully clear explanation of why I think so. I hope that my text will raise some questions about your codebase style and quality or at least that next time you will think twice before creating a method like public void doSth(). As usual, thank you for your time.
Opinions expressed by DZone contributors are their own.