Is using a lot of static methods a bad thing?

Language AgnosticStatic Methods

Language Agnostic Problem Overview


I tend to declare as static all the methods in a class when that class doesn't require to keep track of internal states. For example, if I need to transform A into B and don't rely on some internal state C that may vary, I create a static transform. If there is an internal state C that I want to be able to adjust, then I add a constructor to set C and don't use a static transform.

I read various recommendations (including on StackOverflow) NOT to overuse static methods but I still fail to understand what it wrong with the rule of thumb above.

Is that a reasonable approach or not?

Language Agnostic Solutions


Solution 1 - Language Agnostic

There are two kinds of common static methods:

  • A "safe" static method will always give the same output for the same inputs. It modifies no globals and doesn't call any "unsafe" static methods of any class. Essentially, you are using a limited sort of functional programming -- don't be afraid of these, they're fine.
  • An "unsafe" static method mutates global state, or proxies to a global object, or some other non-testable behavior. These are throwbacks to procedural programming and should be refactored if at all possible.

There are a few common uses of "unsafe" statics -- for example, in the Singleton pattern -- but be aware that despite any pretty names you call them, you're just mutating global variables. Think carefully before using unsafe statics.

Solution 2 - Language Agnostic

An object without any internal state is a suspicious thing.

Normally, objects encapsulate state and behavior. An object that only encapsulates behavior is odd. Sometimes it's an example of Lightweight or Flyweight.

Other times, it's procedural design done in an object language.

Solution 3 - Language Agnostic

This is really only a follow up to John Millikin's great answer.


Although it can be safe to make stateless methods (which are pretty much functions) static, it can sometimes lead to coupling that is hard to modify. Consider you have a static method as such:

public class StaticClassVersionOne {
    public static void doSomeFunkyThing(int arg);
}

Which you call as:

StaticClassVersionOne.doSomeFunkyThing(42);

Which is all well and good, and very convenient, until you come across a case where you have to modify the behaviour of the static method, and find that you are tightly bound to StaticClassVersionOne. Possibly you could modify the code and it would be fine, but if there was other callers dependent on the old behaviour, they'll need to be accounted for in the body of the method. In some cases that method body can get pretty ugly or unmaintainable if it tries to balance all these behaviours. If you split out the methods you may have to modify code in several places to take account of it, or make calls to new classes.

But consider if you had created an interface to provide the method, and given it to callers, now when the behaviour has to change, a new class can be created to implement the interface, which is cleaner, more easily tested, and more maintainable, and that instead is given to the callers. In this scenario the calling classes don't need to be altered or even recompiled, and the changes are localised.

It may or it may not be a likely situation, but I think it is worth considering.

Solution 4 - Language Agnostic

That seems to be a reasonable approach. The reason you don't want to use too many static classes/methods is that you end up moving away from object oriented programming and more into the realm of structured programming.

In your case where you are simply transforming A to B, say all we're doing is transforming text to go from

"hello" =>(transform)=> "<b>Hello!</b>"

Then a static method would make sense.

However, if you're invoking these static methods on an object frequently and it tends to be unique for many calls (e.g. the way you use it depends on the input), or it is part of the inherent behavior of the object, it would be wise to make it part of the object and maintaining a state of it. One way to do this would be to implement it as an interface.

class Interface{
    method toHtml(){
        return transformed string (e.g. "<b>Hello!</b>")
    }

    method toConsole(){
        return transformed string (e.g. "printf Hello!")
    }
}


class Object implements Interface {
    mystring = "hello"

    //the implementations of the interface would yield the necessary 
    //functionality, and it is reusable across the board since it 
    //is an interface so... you can make it specific to the object

   method toHtml()
   method toConsole()
}

Edit: One good example of great use of static methods are html helper methods in Asp.Net MVC or Ruby. They create html elements that aren't tied to the behavior of an object, and are therefore static.

Edit 2: Changed functional programming to structured programming (for some reason I got confused), props to Torsten for pointing that out.

Solution 5 - Language Agnostic

The other option is to add them as non-static methods on the originating object:

i.e., changing:

public class BarUtil {
    public static Foo transform(Bar toFoo) { ... }
}

into

public class Bar {
    ...
    public Foo transform() { ...}
}

however in many situations this isn't possible (e.g., regular class code generation from XSD/WSDL/etc), or it will make the class very long, and transformation methods can often be a real pain for complex objects and you just want them in their own separate class. So yeah, I have static methods in utility classes.

Solution 6 - Language Agnostic

Static classes are fine as long as they're used in the right places.

Namely: Methods that are 'leaf' methods (they do not modify state, they merely transform the input somehow). Good examples of this are things like Path.Combine. These sorts of things are useful and make for terser syntax.

The problems I have with statics are numerous:

Firstly, if you have static classes, dependencies are hidden. Consider the following:

public static class ResourceLoader
{
    public static void Init(string _rootPath) { ... etc. }
    public static void GetResource(string _resourceName)  { ... etc. }
    public static void Quit() { ... etc. }
}

public static class TextureManager
{
    private static Dictionary<string, Texture> m_textures;

    public static Init(IEnumerable<GraphicsFormat> _formats) 
    {
        m_textures = new Dictionary<string, Texture>();

        foreach(var graphicsFormat in _formats)
        {
              // do something to create loading classes for all 
              // supported formats or some other contrived example!
        }
    }

    public static Texture GetTexture(string _path) 
    {
        if(m_textures.ContainsKey(_path))
            return m_textures[_path];

        // How do we know that ResourceLoader is valid at this point?
        var texture = ResourceLoader.LoadResource(_path);
        m_textures.Add(_path, texture);
        return texture; 
    }

    public static Quit() { ... cleanup code }       
}

Looking at TextureManager, you cannot tell what initialisation steps must be carried out by looking at a constructor. You must delve into the class to find its dependencies and initialise things in the correct order. In this case, it needs the ResourceLoader to be initialised before running. Now scale up this dependency nightmare and you can probably guess what will happen. Imagine trying to maintain code where there is no explicit order of initialisation. Contrast this with dependency injection with instances -- in that case the code won't even compile if the dependencies are not fulfilled!

Furthermore, if you use statics that modify state, it's like a house of cards. You never know who has access to what, and the design tends to resemble a spaghetti monster.

Finally, and just as importantly, using statics ties a program to a specific implementation. Static code is the antithesis of designing for testability. Testing code that is riddled with statics is a nightmare. A static call can never be swapped for a test double (unless you use testing frameworks specifically designed to mock out static types), so a static system causes everything that uses it to be an instant integration test.

In short, statics are fine for some things and for small tools or throwaway code I wouldn't discourage their use. However, beyond that, they are a bloody nightmare for maintainability, good design and ease of testing.

Here's a good article on the problems: http://gamearchitect.net/2008/09/13/an-anatomy-of-despair-managers-and-contexts/

Solution 7 - Language Agnostic

The reason you are warned away from static methods is that using them forfeits one of the advantages of objects. Objects are intended for data encapsulation. This prevents unexpected side effects from happening which avoids bugs. Static methods have no encapsulated data* and so don't garner this benefit.

That said, if you have no use of internal data, they are fine to use and slightly faster to execute. Make sure you aren't touching global data in them though.

  • Some languages also have class-level variables which would allow for encapsulation of data and static methods.

Solution 8 - Language Agnostic

I recently refactored an application to remove/modify some classes that had been initially implemented as static classes. Over time these classes acquired so much and people just kept tagging the new functions as static, since there was never an instance floating around.

So, my answer is that static classes aren't inherently bad but it might be easier to start creating instances now, then have to refactor later.

Solution 9 - Language Agnostic

I'd consider it a design smell. If you find yourself using mostly static methods, you probably don't have a very good OO design. It's not necessarily bad, but as with all smells it would make me stop and re-evaluate. It hints that you might be able make a better OO design, or that maybe you should go the other direction and avoid OO entirely for this problem.

Solution 10 - Language Agnostic

Well, there is no silver bullet of course. Static classes are ok for little utilities/helpers. But using static methods for business logic programming is certainly evil. Consider the following code

   public class BusinessService
   {
    
        public Guid CreateItem(Item newItem, Guid userID, Guid ownerID)
        {
        	var newItemId = itemsRepository.Create(createItem, userID, ownerID);
        	**var searchItem = ItemsProcessor.SplitItem(newItem);**
        	searchRepository.Add(searchItem);
        	return newItemId;
        }
    }

You see a static method call to ItemsProcessor.SplitItem(newItem); It smells cause

  • You dont have explicit dependency declared and if you don't dig into code you might overlook the coupling between your class and static method container
  • You can't test BusinessService isolating it from ItemsProcessor (most test tools do not mock static classes) and it makes unit testing impossible. No Unit Tests == low quality

Solution 11 - Language Agnostic

I used to go back and forth between a class with a bunch of static methods and a singleton. Both solve the problem, but the singleton can be much more easily replaced with more than one. (Programmers always seem so certain that there will only be 1 of something and I found myself wrong enough times to completely give up on static methods except in some very limited cases).

Anyway, the singleton gives you the ability to later pass something into the factory to get a different instance and that changes the behavior of your entire program without refactoring. Changing a global class of static methods into something with different "backing" data or a slightly different behavior (child class) is a major pain in the butt.

And static methods have no similar advantage.

So yes, they are bad.

Solution 12 - Language Agnostic

As long as not internal state comes into play, this is fine. Note that usually static methods are expected to be thread-safe, so if you use helper data structures, use them in a thread-safe manner.

Solution 13 - Language Agnostic

If you know you will never need to use the internal state of C, it's fine. Should that ever change in the future, though, you'd need to make the method non-static. If it's non-static to begin with, you can just ignore the internal state if you don't need it.

Solution 14 - Language Agnostic

If it's a utility method, it's nice to make it static. Guava and Apache Commons are built upon this principle.

My opinion on this is purely pragmatic. If it's your app code, static methods are generally not the best thing to have. Static methods have serious unit-testing limitations - they can't be easily mocked: you can't inject a mocked static functionality into some other test. You also can't usually inject functionality into a static method.

So in my app logic I usually have small static utility-like method calls. I.e.

static cutNotNull(String s, int length){
  return s == null ? null : s.substring(0, length);
}

one of the benefits is that I don't test such methods :-)

Solution 15 - Language Agnostic

Static methods are generally a bad choice even for stateless code. Instead make a singleton class with these methods that is instantiated once and injected into those classes wanting to use the methods. Such classes are easier to mock and test. They are far more object oriented. You can wrap them with a proxy when needed. Statics make OO much harder and I see no reason to use them in almost all cases. Not 100% but almost all.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLoloView Question on Stackoverflow
Solution 1 - Language AgnosticJohn MillikinView Answer on Stackoverflow
Solution 2 - Language AgnosticS.LottView Answer on Stackoverflow
Solution 3 - Language AgnosticGrundlefleckView Answer on Stackoverflow
Solution 4 - Language AgnosticMunkiPhDView Answer on Stackoverflow
Solution 5 - Language AgnosticJeeBeeView Answer on Stackoverflow
Solution 6 - Language AgnosticMark SimpsonView Answer on Stackoverflow
Solution 7 - Language AgnosticSteve RoweView Answer on Stackoverflow
Solution 8 - Language AgnosticoverslackedView Answer on Stackoverflow
Solution 9 - Language AgnosticpatrosView Answer on Stackoverflow
Solution 10 - Language AgnosticKonstantin ChernovView Answer on Stackoverflow
Solution 11 - Language AgnosticBill KView Answer on Stackoverflow
Solution 12 - Language AgnosticLuceroView Answer on Stackoverflow
Solution 13 - Language AgnosticAdam CrumeView Answer on Stackoverflow
Solution 14 - Language AgnosticAndrey ChaschevView Answer on Stackoverflow
Solution 15 - Language AgnosticJohnView Answer on Stackoverflow