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.
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.