Topic 5
Use Case Texts; Basic Git Merging
What we will cover this week
- More detailed analysis with use case texts
- Introduction to Git merging (practical exercise will be next week)
Use-case texts
Last week we looked at how to identify use cases and show them on a use-case diagram. The next step is to break down each use case shown on the diagram into a series of steps describing how an actor will interact with the system in order to complete the use case. A use-case text has two columns:
- Actor action, describing how the actor will interact with the system
- System response, describing how the system will respond.
Example use-case text: Enrol student
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the admin staff selects to enrol a new student. | - |
| 2 | - | System prompts the user for the student details (name, address, date of birth, course) |
| 3 | The user enters the details specified in step 2. | - |
| 4 | - | System checks validity of details, e.g. date of birth is sensible |
| 5 | - | System allocates student ID for new student |
| 6 | - | System enrols student in university |
| 7 | - | System confirms enrolment is successful |
Alternative courses of action
Our use-case text must also include alternative courses of action. These describe how the system should react to errors, which can help us design robust systems. These go below the main use-case text. For example, in the previous use-case text:
Example use-case text: Edit student details
This is a simplified version assuming includes or extends are not being used.
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the admin staff selects to edit the student details | - |
| 2 | - | System prompts the user for the student ID |
| 3 | The member of staff enters the student ID. | - |
| 4 | - | System finds the student with that ID |
| 5 | - | System displays details of that student in editable text boxes |
| 6 | The admin staff changes the details. | - |
| 7 | - | System checks that the new details are valid (e.g. no blank strings) |
| 8 | - | System updates details of the student |
| 9 | - | System displays a confirmation message to the user. |
Alternative courses of action:
Design-level use-case texts: assigning responsibilities to our use cases
Once you have done the basic use-case texts (so called analysis-level use case texts), the next thing to do is assign responsibilities to each system response step in the use case text. This involves deciding which domain model classes are required for each system response step.
By doing this, we are linking the user-oriented analysis (use cases) with our first design step (the domain model). Doing this will help us perform detailed system design with sequence diagrams, which is the step following use case analysis.
We will now convert each of the two use case texts above into design-level use case texts. This involves going through each system response step and thinking about which domain model classes, if any, would be responsible for each step in turn. We will highlight the domain model classes in the use-case text, and then discuss the rationale for our decisions.
Design-level use case text: enrol a student
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the admin staff selects to enrol a new student. | - |
| 2 | - | The UI prompts the user for the student details (name, address, date of birth, course) |
| 3 | The user enters the details specified in step 2. | - |
| 4 | - | The UI checks validity of details, e.g. date of birth is sensible |
| 5 | - | The University object allocates student ID for new student, using the highest ID so far plus one |
| 6 | - | A Student object is created and added to the list of Students in the University object |
| 7 | - | The UI confirms enrolment is successful. |
Note what we have done here. We have gone through each "System response" step in the use case text and analysed it more deeply to determine which classes in our domain model have the responsibility for that step. In some cases, e.g. step 4, we don't need to involve the domain model classes because we are just doing a simple validation. But in others, the system response is more complex and requires interaction with the domain model classes. We will look at two of those steps (step 5 and step 6) in more detail and discuss the rationale for choosing the classes shown in the design-level use-case text:
- Step 5 involves allocating a student ID. What do we need for this? We need to talk to the domain model object which knows about all the existing IDs. The
Studentclass does not know this, as a singleStudentknows only about its own ID. TheUniversityclass, however, contains a list of allStudents added so far, and therefore knows about all IDs allocated so far. So theUniversityclass is the class which has the responsibility for allocating the ID. It might do this, for example, by looking at the ID of the most recently added student (the one at the end of the list) and allocate that number plus one. - Step 6 involves creating a student. If you think about this, it involves two steps: creating a student and adding that student to the list of students. The first step creates a
Studentobject, so we reference this in the design-level use-case text. The second step involves adding that student to the list of existing students. What object contains the list of existing students? It's theUniversityobject in our system, so theUniversityhas the responsibility for this step. - What class would have the overall responsibility for step 6, though, in other words, creating a student object and then adding it to the list of students? We could put this inside our UI. However, we might want to re-use the enrolment process in another application with a different UI. So instead, we can place the entire step 6 - both creating a student, and adding it to the list - inside the
Universityclass, as a method.
Design-level use-case text: edit student details
We will run through the same process of explaining the domain model classes we have chosen to allocate responsibilities for the important system response steps, which in this example are steps 4 and 8. (The other steps are trivial and only require the UI).
- In step 4 we are searching for a student by ID. As you hopefully appreciate now, it is easy to allocate a responsibility for this step. Only the
Universityknows about all theStudents (as it contains a list of them) and therefore it must be theUniversity's responsibility to find a student using its ID. It would do this by looping through the student objects in the list until it finds a match. (Or, you might use a map - if you remember, this is the Kotlin equivalent of a dictionary - to store the students, using the ID as the key). - In step 8 we update the details of the student we have found. This only involves the specific
Studentobject we found - nothing else - therefore theStudentwill have responsibility for this step.
This gives the design-level use-case text below:
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the admin staff selects to edit the student details | - |
| 2 | - | The UI prompts the user for the student ID |
| 3 | The member of staff enters the student ID. | - |
| 4 | - | The University object finds the Student object with that ID |
| 5 | - | The UI displays details of that student in editable text boxes |
| 6 | The admin staff changes the details. | - |
| 7 | - | The UI checks that the new details are valid (e.g. no blank strings) |
| 8 | - | The details of the found Student object are updated |
| 9 | - | The UI displays a confirmation message to the user. |
Exercise 1
Answer to exercise 1
These are the analysis level use-case texts.
Add an event
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the venue staff selects to add a new event. | - |
| 2 | - | System prompts the user for the event details (name, type, date) |
| 3 | The venue staff enters the details specified in step 2. | - |
| 4 | - | System checks validity of details, e.g. date is not in the past, fields are not blank |
| 5 | - | System checks there is no event already booked for that date and time |
| 6 | - | System adds event to venue |
| 7 | - | System confirms successful addition |
Book an event
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the customer selects to book an event. | - |
| 2 | - | System prompts the user for the event name. |
| 3 | The customer enters the event name. | - |
| 4 | - | System checks event name is not blank |
| 5 | - | System searches for event with that name |
| 6 | - | System displays details of matching events |
| 7 | Customer chooses event and enters number of people they would like to book for | - |
| 8 | - | System checks input is a valid number |
| 9 | - | System checks availability (is there enough space for that number of people) |
| 10 | - | System allocates a booking ID and creates a booking |
| 11 | - | System shows booking details to customer |
Exercise 2
Answer to exercise 2
These are the design level use-case texts.
Add an event
| Step | Actor action | System response |
|---|---|---|
| 1 | The use case begins when the venue staff selects to add a new event. | - |
| 2 | - | The UI prompts the user for the event details (name, type, date) |
| 3 | The venue staff enters the details specified in step 2. | - |
| 4 | - | The UI checks validity of details, e.g. date is not in the past, fields are not blank |
| 5 | - | The Venue checks that there is no event already present at that date and time |
| 6 | - | An Event object is created, and added to the Venue object |
| 7 | - | The UI confirms successful addition |
Book an event
| Step | Actor action | System response | Notes |
|---|---|---|---|
| 1 | The use case begins when the customer selects to book an event. | - | - |
| 2 | - | The UI prompts the user for the event name. | - |
| 3 | The customer enters the event name. | - | - |
| 4 | - | The UI checks event name is not blank | - |
| 5 | - | The Venue searches for Event objects with that name | - |
| 6 | - | The UI displays details of matching Event objects | - |
| 7 | Customer chooses event and enters number of people they would like to book for | - | - |
| 8 | - | The UI checks input is a valid number | - |
| 9 | - | The Venue object checks the venue capacity and compares it to the number of people booked already for the event, provided by the Event object, plus the number of people in the booking | To do this we will need to add a capacity attribute to the Venue. Also, to avoid us having to loop through all the Bookings in an Event to find the number of people attending so far, it would make sense to add an nAttendees attribute to Event which can be updated whenever a booking is made or cancelled. |
| 10 | - | The Event object allocates a booking ID and creates a Booking object containing the selected Event and current Customer | The class responsible for allocating the booking ID will have to be a class which knows about all the Bookings, to avoid duplicates. This will have to be the Event class. However, we have a problem that we could have duplicate booking IDs across different events. To prevent this, we could change the booking ID to be a String so that it can include event name and date as well as ID to avoid such duplicates (e.g. OASIS-250703-2048) |
| 11 | - | The UI shows the booking details to the customer | - |
Note above how the process of use-case analysis has caused us to make changes to our design:
- we have added a
capacityattribute toVenueandnAttendeesattribute toEventto allow us to easily and efficiently prevent over-booking of an event. - we have changed the booking ID of a
Bookingto be aStringto allow it to contain the event name and date as well as a unique ID, preventing duplicate booking IDs across different events.
This often happens: as we get deeper into the analysis and design process, additional attributes and methods, or changes to existing attributes, can be discovered.
Git Merging
We will use the opportunity to introduce the basics of Git merging. You may remember that in Week 1, we discussed Git branching as part of Exercise 5. We also saw that, once updates have been done on a branch, they can be merged into another. For example, experimental features on the dev branch can be merged into the main branch once they have been thoroughly tested.
To merge another branch into the current branch, you run the git command:
For example, if you are in main and want to merge dev into main, you would run the command:
Merge Conflicts
Often the merge works automatically. However, you can get into a situation where changes have been made independently to the same part of code (e.g the same method) in the two branches we're working with. For example, we might implement a bug fix on main in a method containing a new feature on dev. This is known as a conflict. Both branches have updates on the same method, so Git does not know which of the two updates to pick for the merge. We will look at merge conflicts via a practical exercise next time