Domain models with 10+ data fields, what should be correct way to instantiate/build it?

Well I’ve seen many examples of domain models, but almost all of them are simple enough(about 2-4 data fields), so the model has a constructor that takes all the parameters and initialize its properties inside this constructor. Below is such an example from Mathias Verraes’ DDD example:

class Employee{
    private $name;
    private $position;
    private $salaryScale;

    public function __construct($name, $position, $salaryScale){
            $this->name = $name;
            $this->position = $position;
            $this->salaryScale = $salaryScale;
        }

   // business logic omitted 
}

But in reality, most domain models are much more complex and some can easily have more than 5 or even more than 10 data fields. I tried my best to make sure no table contains more than 15 columns, but I cannot make it any less than this for some tables. For instance, my Message domain model contains 9 fields, and some domain models have up to 12-13:

class Message extends DomainModel{
    private $id
    private $sender;
    private $recipient;
    private $title;
    private $content;
    private $dateSent;
    private $dateModified;
    private $outbox;
    private $status;  

    // methods omitted
}

So if I instantiate this domain model by simply passing all the data fields as parameters, the constructor will have at least 9 parameters. I dont know what you think, but to me a method should not accept more than 6 arguments, or it looks like code smell to me. This article on stackoverflow agrees with me:
http://stackoverflow.com/questions/7962398/having-lots-of-parameters-in-a-constructor

And the question then is, how can I create and build a fully loaded domain model that has a lot of data fields. Right now I have repositories creating an empty domain model first, and then call the setters to inject each data field to the model. However, since I have already moved to domain driven design, these setters will be removed soon. The presence of setters breaks encapsulation, and I should not rely on them anyway. So I will have to change this to another technique of constructing my domain models.

The above stackoverflow article suggests the approach of builder design pattern, but it doesnt work well with PHP since this language has no inner/nested class support like Java. Even using a model builder class, the builder still needs to use setter methods to initialize private properties for domain model, so I end up with the setters once again(which I plan to remove). The issue is that there’s no good way to make the data fields accessible to the model and the model builder, without making them public(Java’s private inner class or C++'s friend class can solve this problem, but we dont have such methodologies in PHP). I dont use any public properties, it breaks encapsulation completely. I know Doctrine uses reflection to make private properties public when initializing them, but I doubt its a good solution either, as @TomB pointed out that using reflection to break encapsulation is not clever:

Another possible solution is also from the stackoverflow article, in which Necromancer and Sahil Muthoo suggested that one could create value objects and decompose the domain object into 2-3 value objects, which each value objects hold another small number of data. I do sometimes apply this approach, such as decomposing user data into user, userprofile, userexperience domain objects. However, it only works in ideal situation when its quite obvious and convenient to group related data fields into value objects or smaller domain models. In my example code above, I fail to see any of these fields can be grouped into value objects. Consequently, this approach only works at minor circumstances, and cannot be applied universally.

What do you think? How am I supposed to construct and build domain model objects that contain a lot of data fields? How would you solve this problem in practice?

While this does not directly answer your question, ask yourself what the difference is between your Message object and a Message array. In other words, after taking away all the getter/setter stuff, what does your domain object actually do?

Well the domain object contains business logic. If I remove the setter, I can have domain methods such as Message::compose($title, $content), Message::send($sender, $recipient), Message:update($content, $dateModified), etc to impose real domain logic. For a true OO API, the users should not be concerned with how to set each property in Message model, but rather how to do realistic operations on the Message such as compose, send, update, etc. In this way, you can visualize Message like a real life object, and OOP is supposed to model real life entities anyway.

Below is another example of how to replace setter methods by real domain methods:
http://verraes.net/2013/04/crud-is-an-anti-pattern/

Do you see the contradiction? Why would you need to create a fully loaded domain model?

Keep in mind that a domain model should not care about persistence.

Because many times I need to load a domain model using the repository. The domain methods I mentioned above are mutator methods that alter the domain model’s state. They work well when you are creating a new model, or to update an old model. But how about loading a model from database? The repository needs to construct the model, and this is where I have the problem if there are a lot of data fields.

Now we get to the real problem. Persistence. You want to be able to set the state of an object using data from an external source. Does it really matter how the state gets set? Am I really violating encapsulation if I just set the internal properties directly? Why bother going through getter/setters and dealing with business logic when all I am really trying to do is to transfer state information?.

Use reflection and the problem is solved.

I see, so thats the rationale for doctrine to fetch entity data information from database. I understand, thanks.

Okay I have looked into Doctrine’s source code and it does seem very interesting to use reflection to set the private properties. However, for as far as I know, Doctrine will need to create a ReflectionClass and a lot of ReflectionProperty objects for each domain model. For an entity with 10 data fields, this means at least 11 Reflection objects(1 reflection class, 10 reflection property). For each of these reflection properties, I will need to call ReflectionProperty::setAccessible(True) followed by ReflectionProperty::setValue($model, $value). If I have 10 different kinds of domain models to create, this means at least 110(10 domain models x 11 reflection objects per model) reflection objects to create, and even more reflection operations/methods to invoke. So I wonder how this will affect performance, since I know that Reflection is very slow, even slower than the infamous call_user_func_array(). What do you think?

I think the success of Doctrine 2 speaks for itself. In practice the speed/memory issues are not bad especially when compared to the alternatives.

Consider writing an application in which a single request requires 10 objects each with 10 properties. Make sure the app actually does something besides querying the database. That might give you a more useful basis for comparison.

From a slightly different point of view, I’m not convinced that methods like Message::compose($title, $content) really implement business logic. I suspect they just store the arguments internally which would make them crud. If they actually do something else then fine.

The point being is that if you have an anemic domain model then you may as well just use public properties or even arrays to max out performance.

Finally, if you have not already, take a look at the Command Query Responsibility Segregation (CQRS) pattern. http://www.whitewashing.de/2012/08/18/oop_business_applications__command_query_responsibility_seggregation.html. I think it’s safe to say that most requests are read only and that the requirements for read only data can be drastically different than the requirements for read write. Note that the writer of the post I linked is one of the primary developers of Doctrine 2. Lots of good stuff on his site.

I see, maybe I will run a sample test of Reflection vs public Setter method in terms of speed for 10, 100, 1000 and 10000 iterations, so that I can find how much the bottleneck is and when it becomes nontrivial.

Yeah, Message::compose($title, $content) itself does encapsulate a portion of CRUD inside by validating and setting the properties for Message:$title and Message:$content, but it feels more natural this way. There will be other methods too that will expose or mutate the Message object, so of course Message::compose($title, $content) is not the only one here.

I definitely wont take on anemic domain model approach, and as I hinted earlier my application has been using rich domain model. Anemic Domain model is a terrible antipattern, and I wont use it unless I am forced to work in an environment that the senior developer uses it and loves it(but then, I wont be making the design design for model/domain layer).

Sure. Such a test might yield useful information if your applications query for thousands of objects and then do absolutely nothing with them. Strange apps but okay. Otherwise, these sorts of bench marks tend to be a waste of time. But who knows, you may discover that the um-teen thousands of applications in production that currently use D2 are in fact way too slow.

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.