Normal
0
21
false
false
false
FR
X-NONE
X-NONE
The keyword
static is somewhat awkward in a pure
Oriented-Object world. I would like to expose here the usages of static I came up after 15
years of OO Programming.
The 2 rules
of thumb are:
A: Static fields that are not pure value constants should be prohibited.
B:
Static classes, that contain only pure functions, that compute outputs
from inputs parameters, are allowed. Personally, I am used to suffix
such class with XXXHelper.
You might
not agree with these 2 simple rules so let me justify them.
What’s
wrong with static fields that are not pure value constant? The underlying
motivation for creating a static field comes from the need for an object that
lives during all the program execution lifetime. Generally this is a central
object, shared by many methods. So instead of passing the object as a parameter
to all these methods, making it global makes it more convenient, easy or
readable. I see 3 main problems in this reasoning:
First, everytime
I stumbled on a need for an object that
lives during all the program execution lifetime I found out sooner or later (generally
later) that I was wrong. There is no such thing. For example imagine that your
program become hosted as an addin (in VisualStudio for example). Addin can be
unload and reloaded. Thus the program execution
lifetime become session lifetime.
And you certainly don’t want that the global object lives between sessions. The
cornerstone here, to get my point, is the concept of session. It is virtually impossible to forecast up-front what will be sessions in which our
code will live in the future. But there is a very common example of
session: Automatic tests. An automatic test (or a set of automatic tests) is a
mini session in itself. Having static mutable fields makes the code much less
testable because all these mini-sessions must shared the same mutable state,
with the need to initialize/clean up it.
Tests are
generally ran sequentially. But what if several sessions are ran in parallel and
they all share the same mutable objects. Then you need to synchronize access to
the global object. And trust me, synchronizing accesses will be a major pain,
not even taken account that this will slow down significantly your program. I
wrote an article on Managing states in a
multi-threaded environment without the synchronization pain. One of my preferred tip in the article is Thread / Resource affinity: The
idea is as simple as it is efficient here also: making sure that an object is
always accessed by the same thread. Basically each thread hold its own
instance. If N threads holds N states then states must be attached to N objects
and states cannot be static. To do so, using the ThreadStaticAttribute on
your static field can do the job. But it is much more elegant to create
a dedicated object for each thread that holds the complete thread-bounded context.
Finally,
the third problem with static fields comes from the fact that this makes the
program much less maintainable. Static fields represent global state. A global
state can be accessed from anywhere in source code. Thus from anywhere in the source
code, in any scope, you can potential create a dependency to the global state. The
dependency is generally non-obvious because it is generally indirect (because
the static field is generally encapsulated by a static static property). But
the result is that accesses to the global state become anarchical. It is
virtually impossible to enforce accesses to a global state and you will end up with some sort of side-effect nightmare. Sooner or later,
the need to refactor the global state in order to control its usage will urge (this is another empirical fact I learnt the hard way).
A
consequence of all this is that singleton class must be prohibited. From
what we just saw, the single static field of singleton makes program harder to test,
harder to maintain, and singletons foster concurrency problems. In my opinion,
the problem with singleton is that it is the easiest OOP design pattern to learn. As a
consequence, every OOP beginner knows the singleton and has a tendency to use
it. Instead of using singleton, I use what I call Managers. A manager is a purely non-static class especially created
in the spirit that only one instance will live at a particular point in time. A
manager doesn’t have the dirty static instance field trick. Instead managers
are generally referenced by other more high level managers. All this grape of managers represent the context in which the code is running. Manager can also be
easily passed as a parameter to methods that needs locally to access the context. Also, manager are generally free to
initialize and clean up, this make them convenient for testing.
Concerning
the second rule B, yes I love purely static helper classes, that don’t have state.
The simple CQL query…
SELECT METHODS
WHERE IsStatic
…just
showed that 36% of my code resides in static methods. Object-Oriented is a
great mean to model a problematic and creates proper abstraction. However, too
often classes contain functions that computes well-defined output
from well-defined input. These functions have a tendency to be potentially static and to be implemented with
a lot of lines of code. Doing so result in fat classes hard to understand and
maintain. This is why I prefer to nest this code inside dedicated helper
classes. Not only this makes my instance classes smaller and clearer, but also automatic
tests for helper classes are easy to write: tests just need to create input,
call a static method, and check output done by computation. There is no hidden
state to take care of initialize. Ironically, a helper class might encapsulate
its own private mini-object model that models its own mini-concern.
I know that
some others might see these helper classes like trash code that result from lack
of design. I agree, such helper classes could be avoided but for what? For more
instance classes whose purpose is not clear and obvious. Indeed, if their
underlying purpose was obvious in the first place, then the idea to put the
code in a static helper wouldn’t’ have even come to the mind. Keep It Simple
Stupid!