Static methods are like the song of a siren--enchanting but dangerous. I remember flirting with this danger in days of yore, but I've since learned to resist their temptation. Why do I no longer fall for their lure?
- Referencing a static method is easy because you don't have to create the containing object beforehand.
Is this really a valid reason? You don't have to type this when dealing with a non-static method:
SomeObject so = new SomeObject();
so.DoSomething();
and instead could type this:
new SomeObject().DoSomething();
Is this any more difficult than a static method call such as this?
SomeObject.DoSomething();
- Calling a static method doesn't involve the overhead of creating a new instance of an object.
This could potentially be a valid reason, but given the way that today's runtime environments optimize the creation of object instances, the speed of current computers, and the large memory space of modern machines, the potential of this argument is nearly nil. Besides, making a method static for this reason is an upfront optimization that is much better left to when there is proof there is a need for optimization.
-
A static method does not rely upon the internal state of its owning object, so why not make it static? I'd rather look at this from the opposite direction: Leaving aside the above reasons, why would you want to make it static? Sure, the static method doesn't rely upon the internal state right now, but neither would an instance method, so why give up the object-oriented aspect of a non-static method?
-
Static methods kill your tests.
This is the biggest reason of all to not use static methods in your code. The reason static methods kill tests is because there is no way to override their behavior. As an example, let's consider a static method called GetCustomer that accepts a customer ID and returns a Customer instance. Let's also assume you are writing a method called "ChangeCustomerFirstName" in another class and that it has two parameters: a) the new first name for the customer; b) the ID of the customer in which the name will change. Here is some example code for the sake of illustration:
public class CustomerService
{
public static Customer GetCustomer(Guid id)
{
//Do database work to get the customer and return it
}
public static void SaveCustomer(Customer customer)
{
//Do database work to save the customer
}
}
public class ClassThatUsesCustomerService
{
public void ChangeCustomerFirstName(Guid customerID, string newFirstName)
{
Customer customer = CustomerService.GetCustomer(customerID);
customer.FirstName = newFirstName;
CustomerService.SaveCustomer(customer);
}
}
When coding the above methods I would have written a minimum of three tests, one for each method and each in their own fixture. However, when writing the test for the ClassThatUsesCustomerService.ChangeCustomerFirstName method, I would not want it to use the "real" CustomerService.GetCustomer method. Why is this? Two reasons:
-
I don't want the test to run against the database. If I'm writing a test for the ChangeCustomerFirstName method, there is no reason for me to run against the database because it doesn't directly use the database. Sure, an object it depends upon might use the database, but such an object would already have tests written for it. All I want to test in this particular method is that the method changes the name of the customer and then hands the changed customer off to the CustomerService--regardless of what CustomerService implementation it hands it off to. If the methods in the CustomerService class are static, I can't override them and therefore I can't replace the real version of the CustomerService class with my own version that exists solely for testing. One of my bigger pet-peeves after joining any project is to find out the project's "service" or "back-end" layer consists of all static methods. It's hard to get really upset about it because I, too, have done such things in the past, but it is always a disappointment because at that point I know for sure they aren't writing tests all that much. If they had been, they would have forced themselves to deal with this situation.
-
I want to make sure it changes the first name of the customer without having to write SQL code to check the database to see if the new first name was persisted. If I could override the behavior of the CustomerService.Save method or replace it completely with a different implementation of the CustomerService class, I could verify the Customer instance the SaveCustomer method receives is a Customer with the new first name.
-
Static Methods are not Object-Oriented.
Static methods are very similar in nature to functions in a non-OO language like C. Yes, static methods are contained by a class and therefore different than C functions, but they are not associated with an object instance and are consequently very similar. This, of course, disallows their use in an OO way, such as when I want to pass an object to a method and then have that method utilize a method on the object.
The above remarks are not to say one should never, ever use static methods. However, before creating one you should think about how the method will be used. I offer these tips:
-
If the method represents something in the particular system you are building, do not make it static. By this I mean that if the method has some sort of intrinsic relationship with the system you are building, such as "ValidateCustomerHasEnoughMoneyToPurchaseProduct", then you probably don't want to make it static. This is because other pieces in your system will depend upon this method, and in order to test those other pieces you'll want to swap out the "real" implementation of "ValidateCustomerHasEnoughMoneyToPurchaseProduct" with another implementation that does exactly what you want it to. Even if you aren't writing tests (tsk-tsk-tsk) you might want to extend the behavior for other situations, and static methods will annoy the heck out of you when they stop such extensions in their tracks.
-
If it is a method that conducts processing that will never change, and that processing uses very few resources and doesn't take a lot of time, you can use a static method (but you still don't have to). For instance, the System.Math class has a number of static methods that will not change (the writers of the library could change the implementation at some point in the future, I suppose).
-
If you ponder the above two tips and you're still not sure, don't make it static.
Comments
Steve,
I commend your effort at discouraging use of static. I have wanted to write my own blog on this subject as well. I will help in stopping others from using static. I think some people just like to argue, they even say, well, just because it is OO doesn’t mean it is better. I will try to think of more reasons not to use static. I think sun is part of the problem. main should not be a static. The standard app start should have been a runnable. I started a paper on this subject, I will have to find it. Even constants are not necessary as a static.
Mike
Thanks a lot, Mike–glad you’re in agreement. I’d love to hear reasons as they come to your mind.
Main tends to always be static, at least in major environments these days. I could probably think of valid reasons as to why it is this way and valid reasons why it shouldn’t be. In the end, I think the use of static stems from a lack of experience in the bigger picture of software engineering. Well, at least it seems this way for me, as I used to overuse it (I didn’t think I was at the time) and I see it well overused on most projects. I rarely ever use it now, and when I do I feel like I’m doing something wrong. Sometimes it’s fine, but I like the “wrong” feeling I get because it causes me to stop and think before I move foward. If anything, I tend to lean in the opposite direction these days by not using static enough–although I’m not sure if that’s truly possible.
I’m planning to add to this post in the near future and diagram a few ways to get around the use of static methods in more advanced scenarios.
Thanks again…good to know someone is reading.
~Steve
Your blog post hits close to home.
I once had to rework a project to make all it’s public Members static functions. The idea was that the users of my dll didn’t want to have to instantiate the classes in the dll because of the “performance” hit of instantiation. But I still needed to be able to test the classes, use interfaces, and inherit from thier base.
So…
I created a static class that mearly instantiated the appropriate class(ala a factory) and called the method on it. Which means that Every time a function of this static class was called, a new instance was created. This increased the amount of instantiations(the very thing they wanted to prevent) by 5 fold at least.
Eventually the code was reviewed, a scolding given, and the dll reworked. I stripped out all interfaces and all class inheritance to make everly last method static. All mocks were now usless(static classes cannot implement an interface), all automated tests had to be scrapped.
Wow, Brian…that’s about as an extreme example I can think of…and it actually happened to you. Whew! I totally feel your pain.
The requests from technical “leaders” never ceases to amaze me. I wonder if they had ever written a single test to see if the object instantiation(s) were causing an issue? That’s a rhetorical question, of course, because I’m certain they didn’t. This reminds me of another post I wrote a while back, located here.
So you would suggest using a static class called Service with methods to load and save your objects? And do do:
Customer c = CustomerService.Get(1);
rather than:
Customer c = new Customr(1);
?
Also if CustomerService.Save() is in your method in the object, then wouldn’t that be the same as just doing the database work in the method with a proper DAL?
I’m not entirely sure what you mean, Justyn. I was trying to advise against the use of static methods in nearly all circumstances. If you are trying to obtain a reference to an already existing Customer instance, as it appears you are trying to do above, I would favor something like this:
Customer c = aCustomerRepositoryInstance.Get( 1 );
The “aCustomerRepositoryInstance” above would be an instance of a repository you have already obtained or one that is passed to the method one is currently in. For more on repositories, see Rob’s post here:
http://www.thoughtshapes.com/Blog/?p=21
I avoid static methods as much as possible because they make testing extremely difficult–if not downright impossible–and they don’t really offer anything of value in 99% of circumstances. As for the term “static class” (which I know did not originate from you so I am not picking on you in any way), I instantly frown my face when I hear such a thing because then it almost certainly means one is not using OO techniques to build the system. When I saw support for static classes in .NET 2.0 the only thought that came to mind was “why?” It appears to me that this entire concept will have an effect of pushing developers in the wrong direction.
I’ll give you a quick example that I probably should have added to the original post: In the MSDN documentation if you go to the topic “static classes [.NET Framework]” you’ll see them point out how the “Environment” class is a good example of static class usage. While this may be true from Microsoft’s perspective, it is not for me. What if I write a new class that is dependent upon the data in the Environment class? How could I test this new class for all the edge cases in terms of what it expects from the Environment class? Because the Environment class is static there is no way for me to override the behavior of it and thefore supply the data that I want to supply to the new class–unless I wrap the Environment class with my own “CustomEnvironment” class that is not static and provides virtual methods that I can override (or I use an interface that allows similar behavior). Let’s say my new class that depends on the Environment does something different if Environment.TickCount returns a value less than 1000 than it does if it returns 1000 or above? How do I test how this new class behaves if I can’t override the Environment class? If I wrap the Environment class with a CustomEnvironment class that has overrideable methods, I can then supply a CustomEnvironment class to my new class that returns the exact TickCount that I want it to return–that tests the case that I want to test.
I guess my question is, why wouldn’t you just use a constructor to load an instance?
Class c = new Class(uniqueID);
vs.
Class c = RepositoryInstance.GetClass(uniqueID);
A guiding principle to follow in software development is the Single Responsibility Principle (SRP). Generally speaking, you don’t want the “Class” class you list above to have the responsibility of loading itself from your storage mechanism. You should code “Class” to do what it is responsible for doing, and remove the loading of its data from it. There are many reasons for this, not the least of which is testing. If I feed the data of “Class” into it via the constructor rather than relying on it to go get the rest of its contents itself, I can then control the data that gets fed into it, can therefore test all the edge cases of data that it expects, and can much more easily test classes that depend on “Class” in some way
The only static class i have written on my own volition has been a dumping ground of regex patterns. With awsome method names like ContainsUpperAlpha(String toCheck) or ContainsXNumerics(String toCheck, int numberOfNumerics) or IsAZipCode(String toCheck).
I’ve written similar classes before, Brian, and this is the exact type of thing that static methods are okay for…your class is similar in nature to the “Math” class I mentioned in the post. Still, though, if I’m writing such a class these days I hesitate to make the methods static because I might want to mock the returns from the methods. The thoughts that would come to my mind were I to begin coding such a class are, “Well, I can make it static now and then refactor later if I need to, but, on the other hand, why make these methods static now? Am I really afraid of the cost of object instantiation?”
I then usually lie down on the side of non-static methods. As usual, and repeat after me everyone: the tests drive my code, the tests drive my code, the tests drive my code.
Hi,
Let’s try to be a devil’s advocate here.
I think static method and even static classes make perfectly sense like sealed or final classes even if many people don’t like them, or claim they break the OOP paradigm and so on.
At the end of the road, what matters most is ease of use, get the job done, and the degree of control you give to your framework users.
Another thing that disturbs me, is that it seems that the main reason for not using static is unit testing. So because unit testing makes it hard or undoable, we must not use it ? Is not unit testing made to test our code and not the other way around ?
It sounds to me like those people who started to say that because is was non trivial to test a private method, we should turn them all public ! This is non sense even more when they try to convince you that all method that matters should be public or whatever crazy reason.
Concerning tests, a good framework should allow us to test anything. Some good frameworks out there already provide us the needed freedom. Take MbUnit or Rhino Mocks as examples.
Cheers.
Hi Richard,
I appreciate your advocacy for the devil. Metaphorically speaking, you couldn’t be more correct. :) (Kidding, kidding…it was too hard to pass up on the opportunity).
Your point of “At the end of the road, what matters most is ease of use, get the job done, and the degree of control you give to your framework users” is valid. However, the devil is in the details. Ease of use, getting the job done, and the degree of control you give to your framework users is a matter of opinion–and in my opinion I believe that static methods almost always work against these goals. I said “almost always” in that last sentence because I do believe there is a time and a place for everything in this world, much less in a development environment.
As for your disturbance at the main reason for removing static methods being because of testing needs, I think I understand where you’re coming from. You ask, “Is not unit testing made to test our code and not the other way around?” While there is some validity to this question and I would have agreed with your implied answer once upon a time, I now disagree. I believe in the following statement: “The tests drive the code.” This is the mantra I code by because I believe that if I am to consider myself a professional developer then I must test all my code. Because the tests drive the code (and that is because I write a test before I write code), the reality of it really does become, “Our code is meant to run against our tests.” That may seem odd but it is true from my perspective. Now, I’m not saying you have to agree with my perspective, but that’s where I stand, firmly. In the end, if you consider the tests as the most important thing in any project you work on, I’m quite sure you will have a better development experience. I know–unequivocably–that I have a better development experience with this perspective than I did before I became a true practitioner of TDD.
In regards to testing private methods, there is no need to make them public in order to bring them under test. If you practice TDD you will write the test before the code. This leads to a state in which you will not create a private method unless it is used by your code…and since the only code you write is because there is a test for it, you will only write private methods when they are indirectly called in your test(s). This is another great benefit of TDD: unused code is kept to a minimum because the only unused code is that which is no longer called as the result of a change in the system…and there are tools to spot such code and then remove it.
Steve,
After more than a year doing unit testing, I do agree 100% with “The tests drive the code”.
I also agree with your point about private methods. The unit tests are based on expectations and not the concrete implementation of the method been tested. A private method can be created to make the code more readable or for code reuse purposes.
Going back to static methods, since “The tests drive the code”, I would use static methods if I want to prevent a developer from mocking the behavior of a method. Let’s say Math.Add(int a, int b). Under no circumstance I’d want a developer mocking this method to say that 2+3 (a and b) should return 10.
Depending on the mocking framework, instead of using a static method, a non-virtual method would work. In my case, I am using RhinoMocks and by making a method non-virtual, I prevent it from been mocked.
Hi Teo,
Glad to hear that you're testing. Isn't it great?
I'm halfway with you and halfway against you in regards to the Math.Add method. Logically speaking you're correct: why would anyone want to allow the possibility to break the laws of mathematics? On the other hand, though, it always depends on the situation...and in that statement lies the key to allowing such behavior overriding. Because I can likely answer "it depends" to just about any question you can fathom, this leads to a corollary: I want to allow my system to adapt to the situations I am not currently thinking of. I'll give you an example...
What if the code I am writing that depends upon Math.Add is supposed to handle an OutOfMemoryException that stems from the Math.Add method? Let's say for some reason this is a specific situation in which the user is to be presented with "We're sorry but the process is currently out of memory." A contrived example? Perhaps, but nevertheless it is possible and serves the purpose of providing me with an argument. How would I write a test for this situation if I can't override the Math.Add method? It would be almost impossible because I'd have to set up the environment to a point where a call to Math.Add causes such a condition...which would be impossible to do across different machines, would lead to a host of unpredictable results, etc.
Now, balance your thoughts with my inclination to create a flexible, free system. I wouldn't have such a problem because I'd be able to override that Add method and throw an OutOfMemoryException and therefore test to see how the client code of the Add method handles such a situation. If I had a nickel for each time I thought I was creating code that didn't have to be overriden only to later find out that it did, I wouldn't be a rich man but I'd have...say...over $1.50. :)
And, what is the risk to allowing such freedom in the system? Do we really think a developer is going to override an Add method and provide his/her own faulty addition? I doubt it very much. I've got a lot more to worry about on my plate on a typical project than worrying about such things as this.
An another note, am I writing a library for others to use? If so, do I ever think the clients of my Math.Add method are going to need to override it? If they are, do I care? They can write their own wrapper that uses my method and still get all their testing done, right? If so maybe I would do a static Add method. Again, it all depends. If I'm writing an application that uses the Add functionality I might want to make it virtual, wrap it with an interface, etc. If I'm writing a library maybe I would do the static method. There is never a completely clear cut answer because nothing in life is ever clear cut.
I'm not saying you're wrong by any means. I'm only sharing my thoughts. I like freedom. I don't like logical handcuffs. I like to do what I want to do when I want to do it. I like to throw rules out the window and instead think through the things I'm doing. I'm saying that using virtual leads to the kind of development life that I like. I think we're both on the same exact page and that I'm being nitpicky with you, but my nitpickiness is only to prove a point: Let people be free to do what they want. If they screw up a Math.Add kind of thing, you're likely to have many more problems on your plate than broken Add functionality.
Steve,
“If they screw up a Math.Add kind of thing, you're likely to have many more problems on your plate than broken Add functionality”. You are right about this; I do have other major problems having developers implement the main logic of a module poorly or faulty and not mentioning missing requirements :(.
Before I started doing unit testing, I wrote the company framework and most of the methods are static; of course, it is a Framework! Well, now that we are doing unit testing we are paying the price of not been able to test several failure scenarios. Also, to test the business logic layer (where no data access is required; it should be mocked) we are forced to have a running database, because the auditing framework cannot be mocked. I guess we will fix this at some point.
Going back to your point, yes, there is a possibility that at some moment the Math.Add method must be mocked to throw an exception or condition a result. So if there is a remote possibility, why tie ourselves with static methods or sealed classes?
If been able to test code is our priority, we should not handcuff ourselves. I totally agree with you.
Regards,
Teo
I can certainly see your point where unit testing is concerned. We used a static property at my last job that exposed the same class, somewhat similar to HttpContext.Current. We did a static property because we wanted something easy to type, not worrying about construction and still using inheritance in our class. Having a .Current property allowed this.
It was pretty nice to not have to worry about object construction everytime you called the object. I guess I don’t totally agree with your statement that static methods and/or classes should be banned from a developer’s toolkit based on principal.
Given the choice, I would prefer a factory over a static method/property at this point, but I don’t 100% agree with the “Static is bad…mmkay” side of things either. It has its place, it is just up to developers to figure out when and where that place is valid.
Forgot one thing:
Do they really kill your tests? Why can’t you just test the static method/property in a unit test with a normal call to the method?
[Test]
public void TestMyStaticMethod()
{
Customer c = CustomerRepository.GetById(1000);
Assert.IsNotNull(c);
Assert.AreEqual(c.Id, 1000);
etc….
}
Doesn’t that allow you to unit test the method? Forgive my ignorance, I don’t have a huge amount of experience with unit testing.
Hi Jeff,
Just to make sure my thoughts are not misinterpreted, I don’t think I ever said that static methods/classes should be banned; my belief is that, based on a lot of experience on a lot of different projects, they are totally overused. There is a time and place for everything, I suppose, but in most cases declaring a method as static is not the right call when it comes to building an application. I’ve got a handful of static methods in the application I’m building, for instance, but each one is never used by the application code itself other than in application initialization. Other than that I’ve got a few static methods I use in my tests and that’s it…and I stand by that.
To address your second post, yes, they do kill your tests. If the “CustomerRepository” you mention above was living in isolation your point would be valid. However, the problem in testing comes when something you are testing depends upon that CustomerRepository static method, but you want to control what the CustomerRepository.GetById method returns so you can test all possibilities in the class under test.
When you commit yourself to disciplined TDD these issues become apparent–and then you are forced to build a truly flexible system. I remember having the same exact thoughts as you have above, but once I became committed to TDD and I forced myself to practice it before judging it, the judgement was over: TDD (and non-static) had won.
I hope this spurs you on in some way…and if so, I’d love to someday hear about your adventures.
OK, Fair enough. I might have jumped the gun a little bit in regards to your position on static classes/methods. I do agree they can be overused and probably are in most cases.
As for my testing example, I have done a little bit of unit testing (not really TDD per se) in my solo adventures. One thing I have done is use Spring (Or any other container technology) and interfaces to inject a stub or mock Repository into my test. For my unit tests I can specify a particular .config file which injects the stub or mock in place of a real “production” repository.
I don’t know what the trade offs are for this type of scenario, like I said previously, I haven’t done a lot of TDD.
I applaud your efforts to educate the development community on this though, keep up the good work.
Jeff,
I’m quite impressed by your honesty and sincerity.
You are very much on the right track in terms of injecting dependencies into the system, regardless of whether it is done by Spring or your own framework (I prefer doing such a thing myself so I don’t have to rely upon a third party–unless there are other features of it that I find useful enough to use). This is one of the keys to creating a testable, flexible system. With this approach and with commitment on your part in terms of TDD, I’m confident you’ll soon see how much better a development world you can live in…and the more you’ll enjoy your work. Not a day goes by that I don’t greatly appreciate the tests in the system.
Thank you very much for your kind compliment, too.
Regarding your point:
Static Methods are not Object-Oriented.
Static methods are very similar in nature to functions in a non-OO language like C. Yes, static methods are contained by a class and therefore different than C functions, but they are not associated with an object instance and are consequently very similar.
The way I look at it, in a slightly abstract sense, static methods are indeed associated with an object, but it is a single, global instance. This is the real problem of static methods; They imply a global variable.
You're a thinker...very nice.
You are right: there is a not-so-subtle, yet abstract, concept here. But I personally think we should not discuss static members in terms of single, global instance. Using the word instance can mislead some because static members are shared amongst all instances of a type.
I discuss static members vs. non-static members in terms of type members and instance members. This eliminates any ambiguity in that there are members scoped to a type, accessible by referencing the type, and there are members scoped to a type instance, accessible by referencing that instance.