CRUD applications tend to involve classes with many accessor methods and very little business logic, the behaviour being implemented at a higher level in manager (or god) classes. This usually signals that the domain model is anaemic. Many developers know the symptoms, but few know how to actually resolve the problem.
I have been suffering the same frustrations myself as I write classes that seem to have no responsibility other than to write and read attributes. OOP is not only rendered futile in such cases, but the amount of code that needs to be written also increases as I have to write classes that are effectively nothing more than data transfer objects and manager classes to act on those.
Through unit testing and refactoring, I have finally managed to develop a few simple rules to identify when a domain model is anemic. Without these two practices, it would have been just as difficult as many others are finding it.
Unit testing helped by forcing me into writing the “usage code” before implementing the classes. By first writing tests, I get an idea how the interfaces of my domain model will be used and can quickly flag up anything that seems out of place or redundant. For example, consider a simple
Account that has the following responsibilities:
- Represent a user account
- Hold information about a user (ie. username, password, email address, status)
- Used for authentication
This class seems very dumb at first, and one is tempted to implement only getter and setter methods as the interface.
Now, say we write a unit test for user authentication. What most people will probably do is this:
This, in the unit test, should immediately signal that the model is anemic. Here, the responsibility for checking that the input password is valid is handled by the calling code. However, the
Account class is supposed to take care of this.
The fix is to refactor the unit test as follows.
Now, the behaviour is encapsulated within the
Account class, making the implementation of the “authenticate user” use-case more robust.
There are many such small refactorings that can be performed on one’s code in order to make classes richer and reduce the symptoms of anemic domain models. One has only to write good unit tests and refactor whenever one thinks that things can be written in a better way.
I follow these principles:
- If calling code reads an attribute from an object to then act on that piece of information, the behaviour should be moved to the object.
- Getters and setters should not be systematically implemented; instead, write setters and setters only when unit tests indicate that they will be needed.
- If there are chain method calls on an object, this indicates that the object is lacking some behaviour.
I am sure other programmers have their own personal ways of resolving anemic domain models. I would be very interested in reading what techniques others use.