Goal-driven Modeling, Part II
Conrad Bock
Reprinted from
Journal Of Object-Oriented Programming
Vol 13, No 11, March 2001
Copyright © 2001
101 Communications, Inc, New York, NY
This is the fifth article in a series on modeling behavior in the
context of object orientation, and the second on goal-driven modeling in
particular. The previous article showed how to
use goals in existing object-oriented languages to constrain the choice
of operation parameters, discover new object structure, and support more
powerful forms of method dispatch. This article elaborates on that by
proposing extensions to object-oriented languages that more directly
support goal-driven modeling.
Goal-driven Operations
The previous article identified at least three parts of invoking a
behavior: the task to be done, the inputs to the task, and how the task
is carried out [1]. Object-orientation defines the
task to be done only in the name of an operation on a class, and perhaps
in postconditions to the operation. For example, an operation for
filling a position in a company may have the name FILL and postconditions stating that the position is
filled and the recruitment cap is adhered to. See the left side of
Figure 1 where the postcondition is expressed in OCL, UML's Object
Constraint Language [2]. A purely goal-driven
model, by contrast would:
- Dispense with the operation name. Goals are a better way to refer
to an operation, as shown below.
- Create a goal by generalizing the postcondition so that it does
not constrain how the task is done. In the FILL example, it would not include the recruitment
cap, and would state the purpose of the operation in terms of its
effect on objects.
- Provide for the goal to support inputs/outputs to/from the
task. This is functionality outside the scope of normal
postconditions.
The goal of the FILL operation on the POSITION class could be expressed in an adapted form of
OCL like this:
self.filledBy = ?new-employeeout
The self keyword refers to the instance of POSITION
on which the goal is being achieved. The variable
?new-employeeout is introduced here to make the postcondition
more suitable for goal-driven modeling. The out subscript indicates
that the variable is bound during the achievement of the goal, rather
than passed in at the time the operation is invoked. You can imagine a
similar subscript notation for in parameters.
Once the formalization of goals is in place, we can drop the operation
name and place goals directly on classes instead of operations. For
example, FILL operation on the class DEPARTMENT would be the OCL above. Postconditions that
constrain the way the goal is carried out can still be attached to the
goal. An adaptation of UML notation for goal-driven operations is shown
in right part of Figure 1.
Figure 1: Goal-driven operation
Invoking Goals
After goal-driven operations are declared on a class, modelers can call
on goals to be satisfied rather than invoking operations. Like any
operation, this triggers the execution of a method that achieves the
goal. This requires a new way to invoke operations that uses goals
instead of operation names. For example, suppose we invented a language
that used OCL as statements in a procedure, like this:
Position pos = "ProjectManager";
ProjectManager pm;
Achieve-Goal pos.filledBy = ?pm;
The first two statements declare variables, the pos variable being
initialized to the PROJECTMANAGER position. The second statement asks that a goal
on the position be achieved, binding the uninitialized pm variable.
The difference between the Achieve-Goal statement above and a regular
assignment statement is that the right side is a variable, specifically
an out variable that must is bound by achieving the goal. Other goals
might use a constant or a bound variable on the right side, whereupon
the goal would be to hire a particular person. The difference between a
regular assignment and a goal-driven assignment is that the variable
cannot be bound directly, by reading from a persistent store, for
example, but must get its value through a complex process. Regular
assignments are implemented on objects as read/write accessor operations
that only query and modify objects, without any complex processing.
Accessors are not goal-driven operations.
The above goal-driven code could be mixed in with the usual imperative
code. For example, a legacy program could be converted to a goal-driven
program one statement at a time. The film-staffing example of the
previous article may have started life like this:
void Staff-Film(Film f)
{
// Assume the producer started the project.
Producer p = f.producer;
//The producer gets funding.
p.getFunding();
//The producer hires the director.
Director d;
d = p.hireDirector();
//The director hires the cinematographer.
Cinematographer c;
c = d.hireCinematographer();
}
The above formulation is typical object-orientation in that it puts
operations on the objects responsible for them. This buries the
organizational structure of the film project in detailed method
implementations. For example, the hiring process conceptually goes by
the organization chart, namely, the director works for the producer, the
cinematographer works for the director, and so on. But this is recorded
above in methods of objects, like the method for hireDirector on
producer.
A goal-driven version would focus on the purpose of the hiring process,
namely that a position is filled, not how it is filled, who does the
hiring, and so on. As explained in the previous article, this guides
the choice of parameters, forcing the introduction of a relation between
the manager and the position, thereby giving enough structure to
generate an organization chart [1]. The goal-driven
version of the film staffing procedure would be:
void Staff-Film(Film f)
{
//Get funding
Achieve-Goal f.funding = $10,000,000.
// Fill the director position.
Position dpos = "Director";
Director d;
Achieve-Goal dpos.filledBy ?d;
//Fill the cinematographer position
Position cpos = "Cinematographer";
Cinematographer c;
Achieve-Goal cpos.filledBy ?c;
}
The goal-driven procedure completely hides the way a position is filled
and funding acquired. It may be that hiring is not done by the
organization chart, but is farmed out to an external HR group. Or
perhaps on this particular film the producer is not the one responsible
for funding. The straightforward OO approach makes this decision too
early and embeds it in the code, despite OO's separation of operation
and method. This is because standard OO practice focuses on the agent
that will be responsible for the action, and attaches the operation to
the agent, rather than simply stating the goal of the action and letting
the agent and method be chosen from that.
The success of goal-driven techniques in use-case development shows how
much more intuitive it is to express procedures in goal-oriented terms
[3][4][5].
Especially if the procedure is in a non-computer domain, like chemical
processes, flight control, or business modeling, the expert is not
concerned with the issues of object-orientation, but with the goals that
need to be achieved, regardless of the object responsible for them [6]. This is consistent with the results of business
process reengineering, which suggests that enterprises are more
organized and efficient when business processes are defined
independently of which departments are responsible for each step [7]. Goal-based procedures support breakdown of tasks
into subgoals, ordering those goals in time, and decomposing them
further into subgoals. The language proposed above integrates
goal-oriented, object-oriented, and imperative techniques to facilitate
the communication between non-computer expert and developer.
Goal-driven Methods and Components
Once a goal is invoked, the method for the goal is executed, in the same
as any operation. Such a method does not have parameters in the sense
of a normal operation, however. It has a goal instead. For example,
the POSITION class might have the method like this,
again adapting OCL:
context Position :: self.filledBy = ?new-employee out
{
Employee hiredcandidate;
// Procedure for hiring goes here, binding
// hiredcandiate.
self.filledBy = hiredcandidate;
?new-employee = hiredcandidate;
}
The first line above specifies the goal of the operation and the object
on which it resides. The rest is the way the goal is achieved, that is,
the method. At some point in the procedure, a link is established
between the position and the candidate who was hired. This is an
ordinary accessor statement that creates a link, not a goal-driven
operation. Above it happens at the end of the procedure, but it could
be anywhere. For example, it may be that the hired candidate is
determined in the middle of the procedure, and after that their office
is assigned, and so on. It is only important that some part of the
procedure is declared as the goal in the context header. It is also
perfectly suitable for a procedure to have multiple goals. In this
case, the particular goal requested at runtime is achieved by the
procedure, even if the other declared goals are not achieved in that
runtime scenario.
In an object-oriented approach, the type of object on which the goal is
invoked determines the method. The above procedure would be stored on
POSITION in this case. However, you can see that
the above method does not require an OO framework to be invoked. All it
needs is a request to achieve the goal. This request might not be
directed at a specific object, but could be to any agent responsible for
dispatching goal requests to the proper method. More general dispatch
techniques are described in the previous article.
Here we introduce a component-oriented dispatch technique based on
goal-driven methods. Methods can be grouped together in a component and
their goals published in an extended interface definition language that
supports goals instead of operations. Such a goal-based IDL would look
similar to class extensions defined earlier. When a binary-compatible
component is registered with a system, its goals can be indexed in way
that invocation of those goals quickly finds the components that have
matches in their interfaces. If the system administrator is careful to
have only one component supporting each goal, then the dispatcher can
uniquely determine the method. The methods may even be on objects in a
component, as long as the component has a way of dispatching to those
objects when a goal is invoked on the component.
Relation to UML and Business Rules
So far we've adapted textual languages for goal-driven modeling, but
graphical languages can also be used, and the semantics associated with
these brings out important connections to state machines and business
rules. Figure 2 shows an example model for goal-driven procedures
adapted from UML Activity Diagrams [2] and
Martin/Odell Event Diagrams [8]. The top part of
the figure is normal Martin/Odell notation for invoking operations, with
goals notated by filled triangles. The bottom shows the invocation of
completely goal-driven operations proposed here. Goal-driven
presentation is a bit more cumbersome because it is difficult to elide
the parameters. A tool can support names for goal-driven parameters
that are hyperlinked to the goal themselves. As long as programmers can
use goals, because they need the parameters, then there is no harm in
using a name just for graphical purposes.
Figure 2: Goal-driven Activity/Event Diagrams
As explained in an earlier article of this series, the underlying
semantics for UML Activity Diagrams is State Machines, where each step
in the activity is a state of executing the activity as a whole [9].
The idea is due to Odell, who observes that the connections between goal
invocations are equivalent to state machine transitions in which the
fulfillment of a goal by the first step triggers the transition to the
next step [8]. Odell further notes that these are equivalent to rules
that govern behavior. The rule in this case is simply that if the goal
of having a director for the film is achieved, then the system should
invoke the goal of having a cinematographer for the film.
This relation between procedures and rules is critical to the
implementation of business processes in ecommerce applications. Two
companies implementing a business-to-business interaction follow a
process that traverses both companies. However, the systems of each
company operate independently. They are not controlled by a centralized
application governing of the business process [10].
One way to implement this is for each company's system to react to
events as they occur [11]. Each system is notified
of events, such as the completion of a goal by the other company and
reacts according to its own business rules. If the rules are designed
properly, the interaction between companies appears as a smooth-flowing
business process.
When translating the diagrams of Figure 2 to business rules, one must
decide whether the rules should apply locally to that one process, or
globally to all processes. For example, it may be there is an
alternative procedure for film staffing that invokes the goal of having
a director, but then goes on to get the casting director instead of the
cinematographer. The rule that says to get the cinematographer right
after the director should be specialized to only apply when using the
particular film-staffing procedure in Figure 2.
On the other hand, you may want business rules to apply globally.
Figure 3 shows two processes, each in its own department, and each with
its own reaction to the completion of the FIXROOF goal. Accounts payable reacts by billing the
customer and Operations reacts by reassigning the workers that were
assigned to the completed job. In this case, either business process
may have invoked the FIXROOF
goal, but both rules react to its completion. The issue of multiple
reactions or methods responding to one goal enters the area of general
rule systems. This topic is taken up in a later article.
Figure 3: Global Business Rules
Note on XML
This article used OCL to express goals and goal-driven operations, but
XML could have been used instead. It is mostly for reasons of
compactness that one might use OCL rather than XML. For example,
model-based repositories often support read/write accessor operations
that accept an XML format for input/output. These repositories have an
operation that accepts an XML file containing something like:
The above is the XML version of a write accessor for the director
position of a film project. XML supports the import of parts of a model
because metainformation, such as attribute names, is recorded directly
in file. Binary formats optimize away metainformation so cannot
transfer partial models. The above XML could be used for the goal of an
operation by introducing an variable for the director:
The above is similar to the various XML query languages that support
matching XML against objects and databases [12]. XML syntax is more
cumbersome than the OCL, but the meaning is the same. Another advantage
of OCL is that it can express complex combinations of boolean operators.
The point of mentioning XML here is that it has the effect of directing
the industry's attention to an object-centric way of modeling accessor
operations, and consequently to goal-driven operations in general. A
standard is still emerging for XML queries like the above, but when it
arrives, it could be applied to XSL, the rule transformation language of
XML, to write business rules also.
Conclusion
This is article proposes extensions to object-oriented modeling that
support goal-driven techniques described in the previous article. It
uses UML's Object Constraint Language to express goals, but could use
XML also. Based on this more formal goal model, purely goal-driven
operations are introduced, along with textual and graphical syntaxes for
invoking them, and writing their methods. The proposed language
integrates goal-oriented, object-oriented, and imperative approaches.
References
[1] Bock, Conrad, "Goal-driven Modeling,"
Journal of Object-Oriented Programming, 13:5, September 2000.
[2] Object Management Group, OMG Unified Modeling Language, version 1.4,
available at www.omg.org.
[3] Cockburn, A., "Goals and Use Cases", Journal of Object-Oriented
Programming, 10:5, September/October 1997
[4] Cockburn, A., "Using Goal-Based Use Cases", Journal of
Object-Oriented Programming, 10:7, November/December 1997.
[5] Constantine, L.L. , and L. Lockwood, Software for Use: A Practical
Guide to the Models and Methods of Usage-Centered Design,
Addison-Wesley, Reading, MA, 1999.
[6] Walters, J.R. and N.R. Neilson, Crafting Knowledge-based Systems,
Wiley, New York, 1988.
[7] Hammer, M. and J. Champy, Reenginerring the Corporation,
HarperCollins, New York, 1993.
[8] Martin, James, and James J. Odell, Object-Oriented Methods: A
Foundation (UML edition), Prentice Hall, Englewood Cliffs, NJ, 1998.
[9] Bock, Conrad, "Unified Behavior
Models," Journal of Object-Oriented Programming, 12(5), September 1999.
[10] Riemer, Karsten, "ebXML", presentation to OMG ADTF, Orlando,
January, 20001, www.omg.org.
[11] Object Management Group, UML Profile for Enterprise Distributed
Object Computing Request for Proposal, http://doc.omg.org/ad/99-03-10.
[12] World Wide Web Consortium,
www.w3.org/TR/1998/NOTE-xml-ql-19980819/ and
www.w3.org/TandS/QL/QL98/pp/xql.html.
Return to Bock Online
If you have any comments on this page or problems, contact
Conrad Bock (conrad dot bock at nist dot gov)