Specifying operations
The effects or goals of use cases and operations can be described with OCL, abstracting away from the details of sequences of interaction and internal algorithms. Again, the advantage is that the more important issue of what we're trying to achieve can be written down separately from the (possibly many) ways of achieving it.For example:
use case schedule job (type : JobCategory, c: Customer)(ss-->exists(x | P{x}) is an OCL way of saying that the conditional expression P{x} comes out true for at least one member x of the set ss. Here we're saying that, of all the jobs assigned to this customer, there is at least one future job of the right category.)
post c.jobs-->exists (j:Job | j.category == type AND j.date >= today)
-- The Jobs attached to this Customer now include one (which we'll call j here) whose category is of the requested type of job (fix burst etc) and is scheduled for some time in the future.
Notice that
- We don't have to restate things that are constrained by the type diagram and its accompanying invariants. So it's implicit that the new Job must be assigned a plumber with the appropriate skills (because of the "1" cardinality on the Job::assignee association, and because of the invariant we wrote about skills).
- The postcondition relates together the states before and after the complete task of scheduling a job (or whatever) has been done --- no matter how long it takes, and no matter how many in-between stages there may be. Negociating the date, assigning an available plumber all take time and various subsidiary operations and interactions between the business and the customer, and within any supporting software; but we don't care about them at this level of description.
- A postcondition states what's required, but also leave things open. For example, we don't care which plumber is assigned, provided they have the relevant skills. Contrast this with writing program code, in which you would have to write some algorithm that would always end up choosing a specific one. This feature of postconditions is very valuable where there may be several different variants of the same basic behaviour which differ in detail. Different subtypes might have the same basic spec but additionally assign specific plumbers, or add extra criteria for their selection.
Snapshots can again help illustrate what the OCL is saying. For a postcondition, we need to show two states, before and after the operation has occurred. We use red (or thicker lines) for new associations, attribute values, and objects, and can cross out old associations and attribute values.
How is OCL practically useful?
- It's beeen found that, the more precisely you try to state them, the more you expose gaps and inconsistencies in your client's requirements. Other ways of finding these holes are to animate scenarios or to get right on and write a prototype; but the route to these can be quite long even in a RAD environment, and the benefit of the OCL is that you can write interesting things about high-level issues even before considering any software.
- OCL ensures that the requirement is unambiguous.
- The OCL statements act as the basis of test harnesses for any software written subsequently.
- It's neutral about the implementation language. If several different software components are written within the same domain, you'll want to test conformity of each of them to the same set of rules.
- OCL is more succinct at dealing with sets, not needing explicit iterators. They come up a lot.