Forgetting About Object Orientation

With the arrival of dependency injection and web services, it seems that we have started to focus more on services and how they can work together causing objects to be reduced to nothing more than storage units. Objects become nothing more than a way to couple data together in a handy format that can be passed on from one service to the next. Object orientation however is still in the core of most modern programming languages and for good reasons.

Object orientation offers many benefits such as consistency, encapsulation and abstraction. Services can offer some abstraction as well, but it fails to provide the level of consistency and encapsulation a well designed domain object can. Using services as the core often means that you have to provide getters and setters on all your objects, these methods are required for the services that need to manipulate the objects, but they are available for all others as well.

I never liked objects with all those setters as this is not what object orientation is about. Your objects need to be in control and they can only take control by having a strict well defined API that has clear operations you can perform on the objects. In a web application this is difficult however, because most of the time we simply update data based on user input. In those cases, there is nothing you can do about it. This however means that there are no restrictions on the object. As soon as there are some restrictions that ties data together or enforces certain rules, these should be reflected in the code as well.

In the typical web service where the service itself does all the work, these rules and restrictions are checked by the service. While this works, this also means that all changes on the object must pass through that service, or you end up duplicating logic or forgot about it opening up possible bugs. It is far better to enforce these rules on the object itself. This keeps the logic close to where it is important and avoids code duplication.

I must admit that I have fallen down this hole as well, where my application only consisted of DAOs and DTOs which were read and filled by the services. Since there are no domain objects, all logic was implemented in the service. Doing so did cause bugs to appear where in some cases certain things were done, but in others it wasn't. A real example of this was handling e-mail addresses where in some cases they were converted to lowercase but in other cases they weren't. This means that an account with a certain e-mail address was not found (due to case sensitive comparison) but could not be created because the e-mail address was already registered (case insensitive).

Fixing this was rather straight forward, but it turned out that this mismatch was not just in a single place but spread out over the code in multiple locations. You can imagine it wasn't very fun to fix all the paths where things could go wrong. Recently I added an Email business object that does the conversion upon creation, this means that if I see an Email object, I know it is safe to work with as it has been validated and normalized.

I am still exploring domain objects and see where they can be useful but I am optimistic that they will improve my code and make cleaner, easier to maintain and less susceptible to bugs.