Object Behavior Must Not Be Configurable

Using object properties as configuration parameters is a very common mistake we keep making mostly because our objects are mutable—we configure them. We change their behavior by injecting parameters or even entire settings/configuration objects into them. Do I have to say that it’s abusive and disrespectful from a philosophical point of view? I can, but let’s take a look at it from a practical perspective.

The Take (2009) by David Drury

Let’s say there is a class that is supposed to read a web page and return its content:

Done, the encoding is encapsulated and configurable. Now, let’s say we want to change the behavior of the class for the situation of an empty page. If an empty page is loaded, we want to return "<html/>". But not always. We want this to be configurable. Here is what we do:

The class is getting bigger, huh? It’s great, we’re good programmers and our code must be complex, right? The more complex it is, the better programmers we are! I’m being sarcastic. Definitely not! But let’s move on. Now we want our class to proceed anyway, even if the encoding is not supported on the current platform:

Class PageSettings is basically a holder of parameters, without any behavior. It has getters, which give us access to the parameters: isEncodeAnyway(), isAlwaysHtml(), and getEncoding(). If we keep going in this direction, there could be a few dozen configuration settings in that class. This may look very convenient and is a very typical pattern in Java world. For example, look at JobConf from Hadoop. This is how we will call our highly configurable Page (I’m assuming PageSettings is immutable):

However, no matter how convenient it may look at first glance, this approach is very wrong. Mostly because it encourages us to make big and non-cohesive objects. They grow in size and become less testable, less maintainable and less readable.

Encapsulated properties must not be used to change the behavior of an object

To prevent that from happening, I would suggest a simple rule here: object behavior should not be configurable. Or, more technically, encapsulated properties must not be used to change the behavior of an object.

Object properties are there only to coordinate the location of a real-world entity, which the object is representing. The uri is the coordinate, while the alwaysHtml boolean property is a behavior changing trigger. See the difference?

You may say that AlwaysTextPage will make two calls to the encapsulated origin, in case of an unsupported encoding, which will lead to a duplicated HTTP request. That’s true and this is by design. We don’t want this duplicated HTTP roundtrip to happen. Let’s introduce one more class, which will cache the page fetched ( not thread-safe, but it’s not important now):

This is probably the most code-intensive post on this site so far, but I hope it’s readable and I managed to convey the idea. Now we have five classes, each of which is rather small, easy to read and easy to reuse.