Information or behavior

Some time ago, I was present at a workshop that was about software design, specifically about encapsulation. The presenter talked about the advantages of good encapsulation, like decoupling. He also discussed a number of design smells and pointed out that these were about lack of encapsulation. In essence, good encapsulation is all about making a single entity responsible for a single piece of functionality.

Read more: Information or behavior

The second half of the workshop was a hands-on exercise, where the participants were asked to work out a design where responsibilities are encapsulated. It struck me that most of the participants started by searching for the entities and the information that they should possess. I think this is the wrong approach.

Thinking about information

When you think in terms of pieces of information, you come up with a design where information is grouped. Functions must access pieces of information to implement their required behavior. This will mostly not lead to a good design. To see what’s going on when thinking this way, let’s consider a concrete example.

Let’s assume we develop a computer game where de player must drive a car. When thinking about information only, we might arrive at the following entities in our game: Car, Player, Engine and perhaps some more. A Car may have properties like weight, speed and position. Player might have a name and perhaps a score or level. These are added as C# properties:

The Game class is the entry point here, so that is going to contain the logic to move the car. This logic then requires access to the properties that we defined for Player, Car and Engine.

What is happening when you’re thinking in pieces of information? One of the consequences is that information is grouped. But since this information is required at multiple places, the pieces of information must be exposed. This results in tight relationships between objects. And by that, we’re forced to break encapsulation.

Thinking about behavior

The other approach is to think about behavior: who is going to do what? Classes are not primarily seen as holders of information, but as entities responsible for certain behavior. By defining responsibilities well, coupling between classes is limited.

In this design, classes delegate responsibilities by calling methods. Instead of reading the information, the objects are seen as dynamic actors that actually do something.

A class exposes its possible actions as instance methods. When the class is well-designed, the methods describe what you can do with the class. When the class does this well, there is little reason to expose its internals. Encapsulation is preserved.

Conclusion

Thinking in terms of information tends to lead to design issues: different responsibilities might require the same information, but when the design is based on clustered information, then the responsibilities cannot be encapsulated.

Not thinking about responsibilities leads to missed abstractions, and this makes the design rigid. It makes the design also prone to design smells.

Don’t interpret this as a false dichotomy. When creating a design based on responsibilities, then you must also think about the availability of information. A class cannot take its responsibility if there is no way to perform the function. On the other hand, in an object-oriented world, a class without behavior accomplishes nothing.

Leave a Reply

Your email address will not be published. Required fields are marked *