This cropped up on the TDD mailing list and it made me smile so I wanted to share it along with some commentary. A fairly common request from folks in the CF community is for “static” methods (and data members) to be added to CFML. Folks look at Java, think it’s a cool concept, and want it in CFML as well. I generally pop up and say it’s a bad idea and that Java only has static because it doesn’t have any concept of a global application scope (which CFML does, of course).
Anyway, someone posted a code fragment on the TDD mailing list, asking how to test one class in isolation that has methods that explicitly depend on static methods of another class. When you have dependencies, the typical approach in testing is to mock the dependencies so that you test the “unit” in isolation. Dependencies on static methods (and static data members) are pretty much impossible to mock without resorting to some sort of “cheating” (preprocessing the source or manipulating the compiled binary).
Folks on the list responded that this dependency was a design flaw that needed to be fixed to make the code testable. Arnauld Bailly of OQube went a little further:
Don’t use static. Static is evil. Use objects. Refactor to use objects and DI. Then your problem disappears.
Static is something that crept in Java probably because Sun wanted to market its language to C/C++ developers (just kidding, but who knows? I don’t have time to search on the web for the “right” answer).
Don’t use static (and don’t repeat yourself :-).
Nuno Filipe Marques also suggested refactoring to use objects rather than class statics and then rely on Dependency Injection (DI) to make the class easier to test.
Charlie Poole agreed that this is a design flaw and also criticized statics:
If your goal is that class1 should be independently testable, then it’s a design flaw. [snip]
That’s not to say that the statics are OK – IME, they bite you sooner or later. It’s a question of how soon.
The reason for this negativity is much the same as why CFCs should not depend on shared scopes (such as application and session): it introduces a hard-to-test dependency. Most CFers seem to accept the argument that allowing CFCs to depend on application and session scope (except in very tightly controlled circumstances) is a problem for both testability and maintainability.
Consider that issue when you find yourself thinking that “static” would be good to add to CFML!
As an aside, Scala has an interesting approach to this problem: instead of statics, it allows you to define a singleton object (with the same name as the class with which it is associated) – with regular methods and data members – so that you can inject it just like other objects and therefore maintain isolation for testing (and thus improve maintainability and flexibility). There’s nothing wrong with using a singleton object in place of static methods and data members on a class – don’t assume the Java way is the only way!