5

The problem

I have an application that has a User object and a Student object. Some users are students. All students are users. In the database (django-ORM based), this is represented as a Student table with a foreign-key to the User table.

I'm trying to create a REST API, and an object hierarchy in the iOS app that models this API. I'm having trouble deciding how to model this.

The Current Solution

The best I've come up with is this: Have a User model in iOS, have a Student model in iOS which inherits from User and extends it with more properties. Then, have a method which receives a JSON response from the server, and creates either a User or a Student model, depending on the dictinoary.

Finally, the server will need to always give me the most specific type. I.e., when I log in to the server, it will decide whether I'm a student or just a regular user, and will return me the proper dictionary.

Is this the best way?

This sounds a little complicated. But any other way I've thought of modeling it, e.g. changing the way the database is laid out, gives me a design in which the database isn't aware of all the constraints. For example, Student objects are allowed to own other objects (e..g, homework_paper). I can model this with a foreign key to a User object instead of to the Student object, and say that the Student is simply an extension of the user. But then the database doesn't force the fact that a homework_paper has to be owned by a student.

Is there a better way to solve this problem that I'm missing?

Edan Maor
  • 9,772
  • 17
  • 62
  • 92

1 Answers1

2

There is nothing that says the classes in your UI layer need to match 1-on-1 with your domain classes. Just like your domain classes do not have to follow your database tables exactly.

You can think of the classes for your UI layer your UI representations as a different set of classes. Classes you needed to make your UI work, or needed to use a framework to your advantage without compromising the business rules in your domain model and/or database design.

Your User UI class could well be a class that wraps both user and student domain classes. It would have knowledge of both User and Student domain classes. It is then up to this wrapper class to instantiate either a User or Student.

Another approach would be to model the User-Student relation as a "has a" relation instead of a "is a". After all, what are you going to do when user's can not only be students but teachers as well. For example when a teacher enrolls in some other course than the one (s)he teaches. Usually, these kinds of relations are better modelled using Roles than as "is a" relations. See Martin Fowler for more info on Dealing with Roles.

In any case, the User UI class would be the basis for your representation in your REST implementation and fill extra parts in that representation dependent on whether it is dealing with a user or a student or - in the role based approach - a user that has student stuff associated with it:

{
  "user": "/users/1234",
  "name": "Some non student's name",
  "stats": {
    ...
  }
}, 
{
  "user": "/users/4567",
  "name": "Some Student's name",
  "stats": {
    ...
  }
  "papers": [
    { "paperid": "/users/papers/111"
      ...
    },
    { "paperid": "/users/papers/222"
      ...
    },
    { "paperid": "/users/papers/333"
      ...
    }
  ]
}

Edit in response to comments

The server has to decide that anyway at some level, unless you want to have your UI differentiate between users and students at the URI level. Which I recommend AGAINST. It makes for unusable UI's. The user isn't interested in the implementation details and doesn't want to be confronted with them.

But no, if's are not needed.

Use polymorfism to your advantage.

The server can put polymorfism to good use receiving a student instance from its data access framework for any user that it retrieves by id. Students after all can always be referenced as users. So the server can simply ignore the fact that the user reference it gets from the data access framework might be a student. When the server actually needs to do/add specific student stuff, it should do so in a derived class.

No if statement needs to be used anywhere for this. Not even in the UI classes. The UI just needs to know that the User reference it receives could also be a Student and act accordingly. Preferably not by if User is Student (that would be tying the UI way to deeply to the class hierarchy), but by if IUser implements IStudent: asking the User reference whether it also implements the Student interface, and then getting and using that IStudent interface reference.

Marjan Venema
  • 19,136
  • 6
  • 65
  • 79
  • If I understood correctly, this seems to be very similar to my solution - have a User class in the UI which has knowledge of whether the specific user is a student or not (potentially maybe a teacher, down the line). Instantiate, with extra info, on demand. The only difference I see, is that the server returns a "User" object with extra details for a student, instead of returning a "Student" object if it's a student (with details of the user embedded in it as well), or a User object if it's just a user and not a student. Did I understand correctly? – Edan Maor Nov 02 '12 at 22:36
  • Yep, you understood correctly. Let the user interface deal with aggregating various domain classes into MVC triads. That after all is the function of the UI, making stuff from the domain available in a way that helps the user (instead of making the user follow the domain). It also helps in untying the UI layer from the domain layer , so that you won't have to change/recompile the UI layer (as much) when something in the domain changes. – Marjan Venema Nov 03 '12 at 10:19
  • The problem is, then the server has to actually decide, when returning a User object, whether it is actually a user or a trainer, and return the "lower in the hierarchy" object each time. This is a lot of not very nice `if` statements in the server. – Edan Maor Nov 03 '12 at 15:21
  • You're basically saying, as per the edit, use polymorphism both in the classes on the server and the classes on the UI. Then the only person who needs to have an `if` is the helper class which receives a "User or Student" from the Server, and returns either a User or a Student class. I'm not sure whether this is actually possible in Django's ORM, by the way, which is why I asked whether if's were necessary. So we basically agree that it's the right general approach... – Edan Maor Nov 03 '12 at 19:24
  • Yup. We are in agreement. :-) Though I would urge you to delve further into the Roles document by Martin Fowler. It is a far better way of dealing with the many different roles that people can have than inheritance... – Marjan Venema Nov 03 '12 at 19:37