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:

  1. Dispense with the operation name. Goals are a better way to refer to an operation, as shown below.

  2. 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.

  3. 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: 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:

<Position> <name="Director"> <filledBy> <Director> <name="Martin Scorcese"> </Director> </filledBy> </Position> 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:

<Position> <name="Director"> <filledBy> <Director> <fullname=?name> <Director> </filledBy> </Position> 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)