Exercises and discussion: using modelling to identify good classes

The key issue for this session was: once we understand what behaviour is needed to meet the requirements, and we have the basic conceptual classes, how do we allocate behaviour to classes? What operations should our classes support? General issues are covered in What is a good class? (reading also listed separately on the schedule page): this note is to record an exercise we did on Friday of Week 3.

We started from the example of registering students for courses that was used in the Conceptual Modelling slides, so you have use case text and the starting point for a robustness diagram. We discussed how to add to the robustness diagram the need to check that a student has satisfied a course's prerequisites, and that the course is not full, before registering them. I didn't get a photo of that board, but we just added in a validate controller, linked to student and course entity objects. We discussed whether you repeat these entity objects, or just add links to the same ones, because the way I wrote it on the board was confusing. The answer is that we just add links. If we wrote new entity objects, then the informality of a robustness diagram is such that the reader would probably assume we meant to be involving a different student or course. In a UML diagram, the identity of diagram elements is more precisely defined, and people do sometimes repeat diagram elements e.g. classes within the same diagram for convenience, e.g. to avoid lots of crossing lines, but it is still better to avoid doing so.

Next I asked you to consider specifically the scenario (which I've reworded slightly, as the wording I used on the board was incredibly clumsy):

Student Jane Bloggs is to be registered for SEOC. SEOC has Inf2C-SE as prerequisite; it has a quota of 999 students; 17 students are currently registered on SEOC. Jane has taken Inf2C-SE.

Here's an extract from a use case diagram and an extract from a domain model, along with a sketch of a possible interface to the registration functionality:

diagrams setting the scene

I asked you to develop a UML seqence diagram, and also to sketch the corresponding Java code for Student and Course.

Modelling interactions: sequence diagram

Here's the solution we discussed:

object diagram

We discussed naming operations: e.g. isFull is a better name than checkSize for an operation that should return a boolean representing whether the course is full or not, because it's clearer what a given return value e.g true means.

We discussed how to check prerequisites, and there were (at least) two different approaches in the room. The one shown above has Student providing an operation hasPassed which takes a course (or course name? but it's usually better to take an object, rather than a string that identifies it) as argument, and returns a boolean. This works, but whether it's the best approach is arguable. Alternatives include:

How could we judge between these possibilities? When you choose the operations for your classes to implement, try to add value. If you expect the users of your Student objects to want to find out whether a student satisfies certain prerequisites, offer an operation that does what the users want; don't just return a bunch of data and make them do the work. (The more often you expect clients to want this functionality, the more important it is to offer it in a convenient form.) Here's one thought experiment: suppose we start off only modelling "standard" Edinburgh undergraduates, but now we have to let our Student class also represent students who have come from abroad with different qualifications. Suppose the university has some kind of procedure that validates that a given student's previous experience is suitable for letting them take a course that has Inf2C-SE as a prerequisite. If client code says s.satisfiesPrerequisites(seoc) then we can easily incorporate the special case reasoning inside the Student class, and the client code won't have to change. (On the other hand, how will the Student class know what the prerequisites for SEOC are? Will it be acceptable for them to be hard coded in Student code, or should the Student ask the seoc object for that information? If the latter, are we any further forward?) If, however, client code says s.getCourses() and then does its own computation to check prerequisites, or says hasTaken(inf2cse), the client code will have to change to handle the special case reasoning, and either the Student class will have to expose some kind of interface to allow clients to check whether the student is a special one, or the course record will have to lie about what courses the student has taken, perhaps having to invent other associated data such as the year the course (that was not taken!) was taken, and ... yuck.

The real question is: in your real development context, is it appropriate for the Student object to have the responsibility to report what classes the student has passed, or to have the responsibility to check whether a given course has been passed? Taking on responsibilities has a cost, and you should only let your classes do it if you think the responsibility is a reasonable one. At the same time, nobody wants irresponsible classes!

Even in this simple case the answer is not completely obvious. The moral is: keep your code and your design clean, and have appropriate tests, so that if (once you take into account further requirements on the system) it turns out that your first choice was not the best one, you can easily change it without breaking anything.

We considered which class should have the responsibility to do the validation. Could be Student, could be Course. A previous time when I offered this exercise, some people introduced an extra class just to have the responsibility of registering a student for a course, reducing Student and Course to dumb data objects. I explained that I wasn't convinced about this, because dumb data classes (though sometimes appropriate... see links in the mail I sent) are not in the spirit of OO. Putting the functionality that operates on the data elsewhere prevents us from encapsulating the data, meaning that potentially all our software is vulnerable to having to change if the data, or its format, changes.

We discussed the fact that in UML2, sequence diagrams do not have their instanceName:classifierName label underlined, though they used to in UML1. This contrasts with object diagrams:

object diagram

and I attempted to justify it, but honestly, just remembering it is probably better!

Extensions

Further things we did not consider in the session, but could have done: you may find it useful to think about them.
This page is maintained by Perdita Stevens (perdita@inf.ed.ac.uk)


Home : Teaching : Courses : Seoc : 2015_2016 : Schedule 

Informatics Forum, 10 Crichton Street, Edinburgh, EH8 9AB, Scotland, UK
Tel: +44 131 651 5661, Fax: +44 131 651 1426, E-mail: school-office@inf.ed.ac.uk
Please contact our webadmin with any comments or corrections. Logging and Cookies
Unless explicitly stated otherwise, all material is copyright © The University of Edinburgh