3

I use a traditional MVC pattern for my web projects:

  • Controllers: handle use case scenarios steps (can call business logic in models or services)

  • Views: presentation

  • Models......

I hit a wall with the model that prevents me from properly embracing object orientation. I got perhaps the wrong assumption that an entity should have only a single model.

For example, in my current web site project I have an 'image' entity. So I have a model to represent a row in the database 'image' table: I fetch the record to the model constructor, which nicely populate corresponding class properties. I can then use the instance in my code. Nice.

Problem is the other way around, when I must receive data from a form for database storage. The raw data from form needs quite some business processing, and involves coupling between data and logic for reuse, so a class is appropriate. Problem is that if I use the same model as above, the one for getting data FROM the database, things gets really ugly with lots of conditional in constructor.

Is one of the right thing to do, would simply create a separate model class for getting data TO the database, and not stay stuck with single model class for image ? What's the good practice in such case ?

  • 2
    Model-View-Controller is just a UI pattern - it's not a pattern to describe the complete architecture of your application. So the Model is really more like a ViewModel - i.e. it is a model which contains your UI state and UI behaviour. You do not typically want to be coupling your View directly to models used by your ORM or Data Layer. – Ben Cottrell Mar 7 '17 at 22:05
0

Your problem is very common among applications which are not tiny. Sooner or later you might start needing different representations of the same entity, for whatever reason, be it performance or simply better fulfilling your business logic layer.

Having different models for a single entity is not a bad idea, if that is what solves your issue.

I usually implement a thick CUD (Create, Update, Delete) layer to properly validate my entities, this thick layer consists of validation of business rules, object's properties, relations, but should an object pass the entire write layer then I am pretty sure the model is valid. With that in mind I then use a very thin layer for reads which is very fast, because it's stripped down of all the transformations that would have been otherwise necessary.

To make applications as flexible as possible without implementing a lot of overhead, I like to atomize my read queries so that they return only primary keys of entities and then use another layer, you may call it ModelCreators, which has methods accepting ids from the atomized layer and using those constructs models.

In practice it then may look like this:

package Users.Devices.Atomized;

// pseudo-Java code
final class UsersDevicesQuery {

    public List<int> findDevicesForUser(final int userId) {
        // logic to filter out ids of user's devices
    }
}

package Users.Devices.ModelCreators;

final class WithPushTokenQuery {

    public List<WithPushToken> loadModels(final List<int> ids) {
        // logic to return models
    }
}

This approach has proved to me to be pretty good, because it keeps classes and methods very cohesive and yet very dynamic - if you decide to change your model structure you can do so without touching the querying logic and/or if you want to change the querying logic you can do so without altering the classes used to constructing models.

0

It is a very good decision to split in multiple classes (models). In Domain Driven Design you must do this: in every Bounded Context a different model (class if you want) exists, even if they overlap a bit.

Also, in CQRS, you even split the Write side from the Read side into Write (Command) and Read (Query) models. In this way your models become clearer/cleaner and you get to optimize almost at infinitum the read side of the application.

As other have already said, MVC is not well suited for complex domain modeling, as it is more of a UI architecture.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.