Jens Schauder is software developer since 1997. He loves software development for the constant challenges and constantly changing environment. A great chance to learn and teach. He is also blogger, author of various articles and speaker at conferences. Jens is a DZone MVB and is not an employee of DZone and has posted 86 posts at DZone. You can read more from them at their website. View Full User Profile

Why static is Bad and How to Avoid It

07.08.2013
| 25300 views |
  • submit to reddit

Everybody who worked with a project which included a StringUtil(s) class with only static methods, raise her hand! Thought so. Are those methods bad? Probably not so much, although I had a word to say about the name, after all if a class is not a utility it isn’t useful (by the definition of Wiktionary) and we hopefully haven’t much of that kind in our projects.

But static methods turn bad, when they become more complex than the typical content of a StringUtil class. The problem is your code becomes hard wired to that static method. There is no easy way to replace the reference to the static method with something else, and if you are testing your code using automated tests, this is exactly what you want to do.

If you don’t test your code using automated tests, do something about it NOW!

Converting a static method to something easily mocked is straight forward once you’ve done it once or twice. Lets start with an example:

public class Utility{
    public static int doSomething(){
        //…
    }
}
 
public class Client{
    public void foo(){
        //…
        Utility.doSomething();
        //…
    }
}

The Client uses a static method in Utility and we want to get rid of that. The first step is to make the doSomethingmethod non-static. It is really as easy as removing the static modifier. Of course now the Client needs and instance ofUtility, so we just create one for now:

public class Utility{
    public int doSomething(){
        //…
    }
}
 
public class Client{
    public void foo(){
        //…
        new Utility().doSomething();
        //…
    }
}

Of course this doesn’t improve the situation much. We still have a static reference to the Utility class, since the constructor is just another static method. But now we can simply inject the dependency from the outside:

public class Utility{
    public int doSomething(){
        //…
    }
}
 
public class Client{
    private final Utility utility;
 
    public Client(Utility aUtility){
        utility = aUtility;
    }
 
    public void foo(){
        //…
        utility.doSomething();
        //…
    }
}

Now you can replace Utility by a mocked instance for tests, you can use a wrapped instance for logging or make it implement an interface and so one. Basically you are back in OO world. Of course you can use your favorite DI-Framework to inject the dependency (just make sure you do it properly), or if you don’t mind the compile time dependency you can create an alternative constructor in the Client which uses the default implementation.

Published at DZone with permission of Jens Schauder, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Dapeng Liu replied on Mon, 2013/07/08 - 4:56am

IMO, if the static method is free of side effects, then it would be much tameable. There shouldn't be any need to "mock" it in the client's test, if the static method is already covered by its own tests 

Jens Schauder replied on Mon, 2013/07/08 - 7:10am in response to: Dapeng Liu

free of side effect goes a long way, but isn't enough.

Take System.currentTimeMillies(); It is free of side effects, but since it depends on side effects (the progress of time) it makes the client hard to test.

Another example a rather complex class doing some reflection analysis of a class passed in as an argument. Although it was free of side effects it still caused lots of headaches when testing the client, because one had to provide a carefully designed class in order to get the needed result from the static method, which in turn was necessary to control which execution path gets taken.


So if you have a static function that is:

simple: Easy to get a specific result you need for testing

pure: causes no side effects and doesn't depend on side effects

and you are sure the team notices when any of that changes

then and only than static methods might be without problem. 

Jess Holle replied on Mon, 2013/07/08 - 7:17am

Calling a language programming feature "bad" because your choice of testing tools doesn't allow you to mock it out is ridiculous.  One should think thrice before mocking -- as it's the interactions between units that cause many of the issues.  Where one must mock, then use a capable tool that can actually do the job (e.g. jmockit).

Yaozong Zhu replied on Tue, 2013/07/09 - 9:06am

Generally, it's not straightforward to replace the behavior provided by statistic method without the aid of some advanced Mock framework feature. Personally, I would like to use Dependency Injection as much as possible, but if the 'function' are self-contained and have a big client base, statistic method is still justifiable. 

Oleksandr Alesinskyy replied on Wed, 2013/07/10 - 4:17am

So let summarize it this way:

Static methods are good, a misuse of static methods is bad

BTW, you may substitute "static methods" with virtually anything in the sentence above :)


Jens Schauder replied on Wed, 2013/07/10 - 5:03am in response to: Oleksandr Alesinskyy

Nope, that summary is wrong.


Static methods are bad, but there are very limited situations where static methods are acceptable, although they are still bad.

Jess Holle replied on Wed, 2013/07/10 - 6:11am in response to: Jens Schauder

So what's bad about static methods?

If there's any real chance you'll need to have different implementations at non-test runtime, then you don't want a static method.  If there's no real chance of this, then why bother?  Why force everyone to get an instance from a factory method or such when there will never realistically be anther implementation?

Mocking is a poor reason to drive such decisions.  There are tools that mock statics.  If you refuse to use a good testing tool then that's the decision point that needs to be revisited, not static methods.

Oleksandr Alesinskyy replied on Wed, 2013/07/10 - 7:45am in response to: Jens Schauder

 Nothing is bad - if used properly.

Robert Brown replied on Wed, 2013/07/10 - 8:34am in response to: Jess Holle

Statics are bad because they are very, very easy to misuse by storing state (having a side effect as noted above) either accidentally, or on purpose especially by junior developers who haven't experienced the untangling required when something all of a sudden CAN'T be static (adding multi-tenancy to a single tenant system anyone?).  Using Statics gives your code a high level of cohesion which can eventually make maintenance a nightmare.  For example, you build a system using statics wherever you don't want to take the time to inject a dependency, you even did a pretty good job of not storing state except where "it really is a static state".  Then a year later and 5 unassuming developers touching the code later and suddenly production stops working because you introduced a threaded routine that somewhere in the call stack relies on that state and now the state has changed under some other part of the code's feet.  These things usually only happen in production because development usually doesn't include a good multi-user experience.  And unwinding/troubleshooting the system is also very difficult because cause and effect is likely not connected. 

So I look at Statics this way.  There is a rule "Thou shalt not use Statics", that rule, like all other rules, is made to be broken.  It's there to make sure when you do use a static you are thinking about why you are doing it and how it can be misused instead of how it can be used properly.  Something that can be misused eventually will.  

Also, look at the code that is there, how much extra work is it really to inject the dependency instead of using a static?  Injecting the dependency is not complicated, it opens up more options for the future that are hard to implement later, the only downside is a couple more lines of code.

Weiqi Gao replied on Wed, 2013/07/10 - 10:03am

No Java program will run without at least one static method---the main() method.  So static methods can't be all bad.  And if we count constructors as static methods, then I'd say static methods are essential for Java programs.

Static methods do couple the classes in your application tighter than non-static methods, which can lead to testing headaches, refactoring headaches, and even runtime anomalies.  Therefore there is a desire to delegate their use to another tool, which hopefully won't bother us developers that much.  And dependency injection frameworks are the tools for doing it.

This is similar to the situation with memory management, which is essential to any Java program, but we developers don't do it by hand.  We let the garbage collector do it.  An argument can be made that object creation should be thought in similar light: its essential to any Java program, but using a dependency injector relieves the developer from having to do the tedious work.

If the garbage collector is where objects go to die, then the dependency injector is where objects come from to live.

Lukas Eder replied on Wed, 2013/07/10 - 12:20pm

I've avoided many lengthy discussions with coworkers insisting on making virtually everything testable (they meant mockable but said testable)... At some point, I walked away from discussions, wrote my 2-3 high-level integration tests, which also cover plenty of static methods, and got right onto the 80 / 20 ratio.

I think, automated testing can live with the odd static, singleton or other anti-pattern-du-jour.

And static imports are totally awesome! :-)

Dapeng Liu replied on Wed, 2013/07/10 - 8:30pm

i still can't convince myself the benefit of replacing StringUtils.join with stringUtils.join


Sabart Sabartson replied on Wed, 2013/07/10 - 9:57pm in response to: Dapeng Liu

 Coz there's no benefit at all.

Sabart Sabartson replied on Wed, 2013/07/10 - 9:59pm in response to: Lukas Eder

 I totally agree.

Mocks are to provide fake implementations to unavailable services. There's no need to mock utility classes.

Sabart Sabartson replied on Wed, 2013/07/10 - 10:06pm in response to: Robert Brown

 Statics are bad because they are very, very easy to misuse ... by junior developers

Just as every single idiom of every programming language. Bu StringUtils is an example of statics used right.

development usually doesn't include a good multi-user experience

Aren't tests supposed to cover that?



Oleksandr Alesinskyy replied on Thu, 2013/07/11 - 4:01am in response to: Robert Brown

Junior developers are bad because they tend to misuse each and every language feature ;)

On more serious note - concept (and limitations) of static is very clear and may be easily explained even to very junior developers. so instead of calling names to language features better put efforts into educating less experienced developers on your team(s).

Wa So replied on Thu, 2013/07/11 - 8:51am

"Everybody who worked with a project which included a StringUtil(s) class with only static methods, raise her hand!" 

I personally prefer the singular "they" over the genderless "she"

Jess Holle replied on Thu, 2013/07/11 - 9:10am

Yeah, as a male, I hate being referred to as a genderless "she".

English lacks proper neuter pronouns (since "it" is universally offensive when used to refer to a person).  The best solution really would seem to be "they" rather than implying all those referred to are female, which is no better than  implying that all those referred to are male.

Robert Brown replied on Thu, 2013/07/11 - 9:43am in response to: Sabart Sabartson

I would actually contend that StringUtils is statics done right for the wrong reasons.  StringUtils is a kludge to overcome the problem that you can't extend the String class to include functionality in an OO manner.  Same goes for most Utility type classes.  

Testing is very difficult if not impossible when considering Statics in a threaded environment as you would somehow have to test every possible combination of start times between all of the threads.  While this is also somewhat true of objects passed into the thread, at the very least the developer can be assured that, barring statics, there is no way an object that is not passed into the thread can be effected by that thread.  Statics especially ones that are buried deep in a stack are often difficult to discover and even more difficult to fix.

Well defined non side effect static methods are OK.  But making sure all of your developers know what that means is difficult, and when they decide to implement a recursive sort routine as a static method thinking that doesn't have side effects and use an internal private (it's private so it can't have a side effect right?) static variable to store where they are in the recursion.

I've found that you should always assume other developers don't have the knowledge you do and that you don't have all the knowledge other developers do.  Ask 10 developers what IoC is and see what explanations you get. Ask 10 developers what MVC is or event based programming and see what happens.  Ask an edit form/post form/get response paradigm web developer to write an interactive UI and see what happens with the event model (hint it can become very very linear and break when something non linear (like someone adding new data while the async save event is processing) happens).  This is where guidelines come into play as rules for development that can be broken for good reasons but those reasons have to be examined.  


Oleksandr Alesinskyy replied on Thu, 2013/07/11 - 10:01am in response to: Robert Brown

First of all, guidelines is a lame excuse for a lack understanding.

Secondly,. removal of static does not make you code thread-safe by magic. Just inject a shared mutable object with your (and, honestly speaking. my) beloved DI and you have the same bunch of problems.

Oleksandr Alesinskyy replied on Thu, 2013/07/11 - 10:11am in response to: Jess Holle

 Especially as 'she' is no more (and no less) genderless as 'he'.

Dapeng Liu replied on Thu, 2013/07/11 - 10:42am in response to: Oleksandr Alesinskyy

+1

Thread safety has nothing to do with static 

No one will accept Math.abs returns -1 under whatever situation

For debugging, I find pure functions are actually the easiest to reason, they are among the "can not go wrong" category, provided we have comprehensive tests coverage

Wa So replied on Thu, 2013/07/11 - 1:37pm in response to: Sabart Sabartson

What if your test case doesn't test the logic of the utility method, but you want to stub it out so that your actual test case can pass?  As the author said-"There is no easy way to replace the reference to the static method with something else, and if you are testing your code using automated tests, this is exactly what you want to do"

Jess Holle replied on Thu, 2013/07/11 - 2:37pm

Don't go on a crusade against statics because:

  1. You insist on mocking in your tests -- which you should avoid in most cases.
  2. You don't use a good mocking tool.

Use JMockit, for instance, and avoid all this silly mess about "you'd better change your perfectly stable code [possibly destabilizing it] because it's hard to mock ___".  That's a case of the tail wagging the dog -- and all because of the choice of inferior mocking tools!

Peter Verhas replied on Tue, 2013/07/16 - 9:39am

Reading the comments many thoughts came up in my mind. Being a Java developer relatively inexperience in C++ I just learned recently that in C++ every function is "static" by default (they call no "static" method as virtual). If that was such a big problem it was not default by design. Or you can just say that this is also a proof of C++ being bad if you are a heated C++ hater. (Note that I use the word "static" in Java meaning in the above sentences, C++ uses static for different meaning.)

As for mocking: static methods can also be mocked, though this is a bit more difficult and needs mangling with the "function pointers" on a deeper level. PowerMock gives you tools for it. When you mock a method then the mock object is injected into the place of the original class and therefore you use the mocked method instead of the real one. In other words you replace the function reference along with the containing object. In case of static methods the containing object is the class itself. To mock that you need to replace the class. You can do that in the class loader mangling the JVM byte code in the class file. Tools do that for you.

Finally you come to the tricky part when you even want to mock classes that are loaded by the system class loader which you eventually (well, not eventually, but as a matter of fact) can not replace or pass by. But some trick may also help there and finally you can mock even the system class.

https://www.google.com/search?q=how+to+mock+the+system+class


Man Rush replied on Fri, 2013/07/19 - 1:41am

Is it really the solution? So all of your constuctors look like this?

public Client(StringUtils stringUtils, DateUtils dateUtils, ArrayUtils arrayUtils, SomeOtherUtils otherUtils /* and finally here comes the really needed arguments */)

I don't think, injecting tons of utility objects is the solution. Any better ideas?

Lund Wolfe replied on Sun, 2014/01/12 - 5:18pm

static is as simple as it gets.  If you don't get it, even as a junior developer, you're in the wrong field.

KISS and YAGNI

If the application requirements change or static was used improperly, change the code as needed.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.