Question

I am not sure if I am supposed to user domain objects directly in the user interface. For example I wish to design the user interface for the domain entity user User wich has a user id, name, password and a list of roles. The entity is designed in such a way that it can never be in an invalid state (for example an invalid password or empty userId)

public class User {
    public User(String userId, String name, String password) {
        //Initialization and validation
    }

    public String getUserId {
        /*implementation*/
    }
    public void changePassword(String oldPassword, String newPassword) {
        /*Set new password if it complies with the rules
        and if the the old one is correct*/
    }

    public void setName(String Name) {
        /*implementation*/
    }
    public String getName() {
        /*implementation*/
    }

    public List<Role> getRoles() {
        /*implementation*/
    }

    public void addRole(Role role) {
        /*implementation*/
    }
}

What is the most appropriate way to design the user interface?

1) Stick to the domain model: Design 3 windows. Window "New user" creates a new user with the given userId, name and password. Another window "Change password" to change the password and another one "Modify user" that lets you modify the name and roles of an existing user

2) It could be desirable to use only one window to create the user with the given userId, name, password and list of roles. I should be able to add roles even when I haven't typed the userId yet.

Option 1 is the easiest to implement because I can use the domain objects in the user interface directly. But the user interfaces could result painful to use. Option 2 is desirable but the domain objets are not usable directly. I do not see how can I add roles if the user is not created yet. I cannot create the user because I might not have the correct information at that moment, for example a temporary empty textbox that represents the userId. How can I achieve this?

The only clean solution I can think of is creating classes to use in the user interface that will mimic the information in the real domain objects. So I will be able to create an empty User to add Roles, then set the userId after that. The user interface can use that information to create the real domain objet.

Is there an easy way around this? How is this usually managed?

Was it helpful?

Solution

That's a lot of questions, but you're right to ask them because they are crucial ones when you start looking at how to pass objects between layers.

Let's start with

"How is this usually managed ?"

You rightly pointed out that the way you want to present a domain object to the user isn't always in its raw form - sometimes you want to show a bit less of it, like in the user example where the addition of roles can in a different UI than the user creation/modification, sometimes you want to show a bit more, displaying 2 objects simultaneously side by side, or presenting mixed data from 2 objects for instance.

A slight precision by the way : you consider option 1 (multiple windows) to be sticking to the domain model more, while I think it tends to mimic the model less because it doesn't present the whole domain object in a single screen -but that's a detail.

So how do you usually deal with that ? Well precisely as you said it -by creating UI-specific objects tailored for your views

The only clean solution I can think of is creating classes to use in the user interface that will mimic the information in the real domain objects. So I will be able to create an empty User to add Roles, then set the userId after that.

These are often referred to as DTO's, ViewModel objects in the .NET/MVVM world, etc.

The user interface can use that information to create the real domain objet.

Usually, it's not the responsibility of the UI itself to create/update domain objects from UI objects. The mapping is done in another layer.

Now that we've seen the basic solution, let's see how it's unusually managed ;)

There are a few alternatives. One of them is the Naked Objects pattern where all user interfaces are direct representations of the domain objects. This simplifies the problem a lot, but it remains to be seen if such UIs are always the best in terms of workflow and ease of use.

Or, you could get away just using your domain objects in the presentation layer. This recent post points out the problems that occur when you have multiple representations of the same object and examines the possibility of using the same domain objects across all layers. The problem here is that you may have to force some data into your domain objects that is not purely domain related, and you may have to renounce some of the invariants as well (such as, "a user cannot exist without at least a role attached", if you separate the user creation and role assignment user interfaces).

Finally, to get back to the user/role example and "I do not see how can I add roles if the user is not created yet" : you don't have to have an existing User object for the end user of your application to be able to select roles. You could just have the roles selected on the screen and hold them until the actual instanciation of the User object is done, and still enforce all the required fields such as the ID.

OTHER TIPS

What is the problem with Option 2 ? You can create the a new User object first and then add Rules to it. If you don't have all necessary information to create a new User object (e.g. empty userid textbox) than just give the user a notification that this field is necessary to fill out.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top