I have been following the XP practices of writing unittest cases, then refactoring the code, etc.
I just noticed that my design hardly has any place for static util methods, especially if the method belongs to a 3rd party library.
e.g. if I were to test the following method:
Observation: Typically computeCos..() is just a plain utility method, but I am tempted to make it an instance method of some object like MyMathUtils.
This is becoz when I am testing client code, I wud like to make a mock object MyMathUtil object (When testing client code, MyMathUtil is a secondary object)
I have given a simple stupid example of computeCosFun.., but consider a really complex static util method which itself invokes static native library methods, it would be very difficult to write test cases for the clients of MyMathUtil.computeCos...()
Easiest thing is to make computeCos...() an instance method of MyMathUtils even though I realize it doesn't use any state of MyMathUtils.
Eventually I realize there is hardly any role for static util methods when following Agile methodology
I think you've found there is not much place for statics in "good" design, where "good" has a definition involving flexibility and testability. You'll find much agreement with your conclusions.
A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Joined: May 17, 2003
Thanks James. Is this a proven fact ? Are there any articles on this topic and is it considered a best practice.
I thought/considered Sun's Java APIs (especially java.lang) were very well designed. I know Sun doesn't use Agile methodology but then does that mean Agile leads one to a design which is different from traditional OO design.
Could there be performance issues, I am working on embedded environment. Martin Fowler & team preach that you shouldn't worry about performance in the beginning, but then I am wondering why "static behavior was introduced in the first place". Static state is shared across all the instances of the Class, but static behavior is typically a util method which could belong to some or other object. If the language didn't support static methods, then lots of bad coding practices could have been avoided (Java code written in procedural lang style).
Static (class) methods have both advantages and disadvantages. I do just about all of my software development using an agile, test-driven approach, and I find that my designs still find a use for static methods.
The main advantage of a static method is that it does not need an object instance to be constructed in order to use it. This means it can be used from anywhere in the system without either: passing in an object (clutters constructors and/or method signatures), creating an object just to discard it (a pointless waste of resources), or messing with Singletons (vastly overused, dangerous, and a candidate for "anti-pattern" status).
The main disadvantages of a static method are that: (a) it ties the client code to a particular class implementation, thus preventing substitution with a different implementation at run time (b) it prevents child classes from overriding the behaviour, and thus severely limits the options for polymorphism. These make static methods a poor choice for behaviour which might benefit from being replaced for testing or for configuration using run-time "wiring" or compile-time overriding.
For me, static methods still have their place, though. Static methods are really good at making small chunks of general-purpose behaviour available to many places in a class hierarchy. For example, I use static methods for the following common situations:
Converting an object to a printable string representation without risking NullPointerExceptions:
Converting a string to an integer and gracefully handling missing values or parse problems:
And so on. Each of these cases would otherwise clutter up the application with "copy and paste" boilerplate code.
These static methods are small enough, fast enough, and simple enough that I feel I can rely on their unit tests to ensure that they work correctly, then just use them wherever required. For me, something such as:
In testable code, there is still a place for utility methods, but it really prevents you from overusing them.
I actually don't see a general problem in instantiating an object just to call a method on it and discard it afterwards.
And I don't think that the JDK is a poster child for "traditional OO design". The first popular OO language was Smalltalk, and the OO principles we are rediscovering by applying Agile approaches are often well known in the Smalltalk community for decades know. Which is not too surprising - a lot of the Agile founders have a strong Smalltalk background.
The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Joined: May 17, 2003
Thanks Frank & Ilja, makes sense. So small well tested static util methods are acceptable but not as Component interfaces or for methods with side effects.
Joined: Jan 29, 2003
I've been burned by using static methods as a typing shortcut. For example in my little projects I use
Logger.log( "message" );
because it's short and easy. I'm stuck with dragging my Logger along with any class I want to reuse in a new project even if that project has its own logger.
In my big work project we have a cache with static methods. We inherited this from a vendor so I'm not sure of the original reason. Later we wanted two caches with different life spans so somebody (was it me?) copied the class to a new name. That doesn't sound good, does it? Later again we wanted to have two or three different implementations of caching, so now all the static methods call non-static methods on an implementation object. Now we can swap in implementations with different tuning algorithms or instrumentation for debugging. Whew, a factory for non-static caches would have been nice in the first place.