Object Orientation – you’re probably doing it wrong

Is it possible that almost everyone really has no idea that they’re doing it wrong?

If taken literally, and to the extreme, encapsulation means that objects should have no getters or setters, only command methods. If we follow this pattern, then our code becomes a lot simpler and easier to understand. But how then do we write user interfaces? We follow the CQRS pattern, of having two distinct sets of code — one containing our object model which is used for writing, and which contains the true status of our application, and a second containing the information used by the UI. The read-side model is updated by responding to events in the write-side model. As a consequence, we gain the ability to independently tune the performance of the two aspects of the application.

Martin Fowler called this pattern CQRS, but I think it’s more than that — I think that this is object orientation. Having accessor and mutator methods (getters and setters) leads to all sorts of trouble. The kind that encapsulation was designed to fix. A long time ago, the industry jumped onto interfaces as the defacto pattern for implementing encapsulation — after all, you’re not exactly exposing internal representation if you use a method — you can vary the implementation separately from the interface, the getter method, without changing your dependent code — problem solved, right? No, the problem is still very much in effect because this naive approach is still exposing way too many implementation details. It is almost always the case that when we change the implementation, we’ll also change the interface. This is seen very commonly in the java beans approach to OO — a very influential approach that I now believe is retarding engineering practices.

Try the cqrs approach for a while, and you’ll probably find that your code is cleaner and more elegant, and just as importantly, it is easier to maintain, contains fewer defects, and is faster, and therefore, less expensive to develop. All of this adds up to reduced costs, shorter time to market, and reduced risks.

In a typical webapp, the pattern is simple: javascript fires off rest requests to the server for data to display — that’s handled by the read-side, which is optimised to handle these queries. Eventually, the user submits a change that the server needs to know about, so the javascript at the front formulates a command and sends it, along with any appropriate data, to the back end for processing. This command will be processed by the rest controller, which will call a method on an aggregate root object which is responsible for propagating instructions to its subservient parts. While this is happening, events will be raised which are handled by both other parts of the write-side model, and by the read-side model which updates itself to reflect changes made to the write-side model (this is a one-way street — no read-side events are handled on the write-side). When the command processing is complete, the rest server returns the appropriate code to the client, which then issues a request for updated data from the read-side.

This pattern is remarkably simple, but it leads to very clear code and very clear separation of concerns. Rest services provide data to be rendered by the client. Rest services provide command processing interfaces. Write-side models process those commands. Read-side models react to notifications that the model has changed. All independent of each other. Not a getter in sight.

Where I have done this we have had separate databases for the two sides, and we’ve used the excellent Axon framework for the write-side, and the excellent spring-data framework for the read-side. I’d like to have used spring-data-rest, but that’s just not ready yet. We have also used spring-webmvc for our rest controllers.

We build all of this through maven — once — and release it to a common repo. Builds are repeatable, but we don’t care about that — we promote a single built artifact through all of our environments, ensuring that the artifact in production is the one we tested in functional testing, integration, QA, UAT, and Pre-Prod.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s