- Mutable global state is bad
- Replacing methods at runtime is mutating global state
- It can be done in Java, but I don’t recommend it, it is a bad idea and it misses the point.
First, let me just state that which I hope all readers already know. “Mutating Global State” is a bad idea. Still, not convinced that global state leads to hard to test, maintain and understand code base? Check Wikipedia or search the web for “Global Variables Good” & “Global Variables Bad“. Here is the breakdown of web page hits returned by Google.
Dynamic languages allow you to change method definition at runtime. On one side this makes testing really easy since now I have a lot more seams in my application where I can intercept the calls. At first glance it looks like that this is a good idea. The problem is that code is part of your global state. In static languages the code is not mutable hence it is a constant and therefore not part of global state. In dynamic languages distinction between code and data is blurred and therefore it can be changed. Since code can be mutated and it is globally accessible it is part of the global state.
Here is a list of problems which you encounter when trying to test an application which has a lot of global state. Notice how all of these issues apply to testing code in a dynamic language where we did monkey-patching in order to intercept method calls:
- The order of tests matter (test may communicate through global state)
- Tests can not be run in parallel (global state interactions)
- We need a teardown method for cleanup (code smell of global state)
- New tests can break old tests (by changing global state)
- Tests know too much about the implementation (refactoring code breaks our tests)
So the argument goes like this. Dynamic languages are more testable because through mutable global state we have more seams than static languages. But this misses the point. Why is your code base written in such a bad way that you have to resort to such drastic measures like global state. Yes many design errors can be hacked through global state, but that does not make it a good idea!
In Java we too can replace method definitions at runtime. It is called a ClassLoader. You simply create a new ClassLoader and as you load your code you can replace a method call with another method call. There are even frameworks which make this easy known as Aspect Oriented Programming. But you don’t see anyone suggesting this in Java world as a good approach to testing.
Too me it sounds more like: Dynamic languages encourage bad application design since they provide so much rope that they make it impossible for you to hang yourself instead you drown in it.
Disclaimer: I am actually a big fan of dynamic languages. And this blog by no means should be read as Java is better than <chose you favorite dynamic language>. Instead read this as people who claim that in dynamic languages there is no need for dependency injection and good OO design really don’t understand how to write well designed and testable code. Yes, you can fight static with static, but it does not make it a good idea, its still static cling.