A couple of weeks ago, I read an "anti-patterns" ORM (Object-Relational Mapping) blog post by Mehdi Khalili. In the post, Khalili said something that I found very interesting (paraphrased):
The Domain Model should never be in an Invalid state because it doesn't expose state - it only exposes behaviors.
As part of my journey towards an understanding of Object-Oriented Programming (OOP) and Model-View-Controller (MVC) architecture, I've been playing around with building a Task/ToDo application. This application is so small in scope that it's easy to just start thinking about the data and the data persistence; but, what about the behaviors?
To explore the statement above, I wanted to try and build a Doman Model for Tasks that didn't have any "Setters". I wanted to see what it would look like if all model mutations had to be done through behavior-oriented method calls.
A Task (in my context) is a relatively simple concept. And, if I were going to create a database table for Tasks, it would probably have the following columns:
Now, the data-oriented part of my brain would see this list of columns and say, "Great, now I just need to create a Doman Entity with Getters and Setters for each of these columns." But this would expose the state of the object. And, in doing so, would likely push any task-related behavior out of the component and into the calling code.
Task open? true
Task open? false
Task complete? true
There is a changeDescription() method, which basically does what a setDescription() mutator would have done. But, using a slightly different terminology, I feel like I have provided a behavior rather than a naked mutator. While this change may seem rather superficial, I think it is profound in its mindset: rather than providing a way to change the state, I'm providing the domain entity with a "reason" to change.
I have no idea if this is a sane approach; but, I do like the idea of delaying the creation of "Setters" for as long as possible. I think doing so will help me think about why my domain model will actually need to change without simply assuming (by default) that every property of an entity should be changeable.
Want to use code from this post? Check out the license.