Streamlined MODELING

Frequently Asked Questions



Object Think

Collaboration Patterns

Collaboration Rules



Why is it called Streamlined Object Modeling?

Streamlined object modeling pares down object modeling to just the bare essentials necessary to model business domains, business rules, and business services. What gets eliminated are the many notations and diagrams that support code generation and detailed design. These have their places during later development stages, but get in the way when gathering business requirements. As a wise man once said, "The ability to simplify means to eliminate the unnecessary so that the necessary may speak." What is necessary for modeling a business domain is to find the objects, their relationships, the business rules governing them, and the business services performed by them. By simplifying the notation, streamlined object models communicate the domain to business experts as well as to developers. And although simplified in notation, streamlined object models capture complex business rules and business services, which can be readily translated into prototype code to validate these rules and services.

What are collaboration patterns?

Collaboration patterns are the fundamental patterns underlying streamlined object modeling. Each collaboration pattern contains two objects and represents a real world relationship within or between one of the four categories: people, places, things, or events. Because most business rules govern the conditions for establishing real world relationships - such as adding a customer to an order, scheduling a flight arrival at a gate - collaboration patterns help find business rules and organize them around the objects.

What are design molecules?

Design molecule is another name for a collaboration pattern. We used this analogy instead of the common "building block" analogy. Collaboration patterns are more like chemical molecules than "building blocks" because each part of the pattern - called a pattern player - has unique properties that determine exactly which other pattern players it can pair up with to form a collaboration pattern. Ultimately, only 12 pairs of the pattern players form stable molecules called collaboration patterns. However, like molecules, collaboration patterns can be combined to form compound collaboration molecules. These larger molecules come in two varieties: snap-togethers and overlays. Snap-together collaboration molecules connect two or more collaboration patterns into a larger structure. Overlay collaboration molecules merge pattern players from two or more collaboration patterns, creating new kinds of pattern players, with new characteristics derived from the originals.

How did you discover the collaboration patterns?

From our years of object modeling for commercial applications we knew most object modeling concerns modeling four categories of objects: people, places, things, and events. We realized that if we discovered the optimal principles for modeling each of these categories, then we could develop a set of fundamental patterns from which we could derive all other patterns.

This inquiry into the meaning of objects yielded a collection of object selection principles and pattern player objects. Evaluating existing patterns with the object selection principles and the pattern players revealed that many of our favorite object modeling patterns could be expressed in terms of the pattern player objects. In fact, many patterns that appeared unrelated because they contained different objects were shown to contain objects that were several pattern players combined. These combination patterns were considered second-generation. In the end, only 12 patterns were irreducible; from these or combinations of these, we theorized that we could model nearly all real-world entities and their interactions.

As proof to ourselves, which became material for the Streamlined Object Modeling book, we used the 12 patterns to build object models for commercial applications. In doing so, we determined that not only could object models be constructed from the patterns, but also that the patterns simplified the construction, organization, and coding of the object model. We were then enable to create strategies for organizing behaviors, properties, and business rules, and further strategies for implementing those behaviors, properties, and rules. All of these strategies were made much easier to remember and verify when they were based upon and described in term of the small set of collaboration patterns.

How do collaboration patterns compare to design patterns?

The goal of the collaboration patterns is knowledge representation using object think principles: personification, first-person think, localized decision-making, and encapsulation. Collaboration patterns help quickly model a business domain by identifying the objects, object relationships, and business rules, and distributing the business services among objects. The resulting model is easily understandable by the domain experts as well as by developers, and the model still exhibits good object model characteristics such as extensibility, and scalability. Design patterns enforce design goals such as reuse, efficiency, and pluggability. Because they extract properties, business services and rules into abstract reusable objects, design patterns vastly increase the size and complexity of the object model, which in turn decreases the understandability for non-technical domain experts. Use collaboration patterns to create an analysis object model that is understandable by domain experts, and then refactor this model with design patterns to increase its reuse, efficiency, and pluggability.



In the Peanut Butter - Jelly example why not let the bread apply the ingredient?

This question refers to the peanut butter and jelly sandwich object model on p.99 in chapter five. The questioner wants to know why couldn’t the bread slice think, “I am a bread slice. I apply an ingredient to myself in either a light or heavy amount.”, and why couldn’t the ingredient think, “I am an ingredient. I am applied to a bread slice in either a light or heavy amount.”? Thus the action of applying ingredient would be first-person for the bread slice and third-person for an ingredient, which is the opposite of the example in the book.

Later in the book, (pg 169) we introduce the principle “The Most Specific Carries the Load.” When trying to decide which object to put the work in choose the one that is most specific. Most specific is easy between collaborators ...role is more specific than actor, part is more specific than assembly etc, member is more specific than group. Here we have to distribute work among indirect collaborators the bread slice (place) and the ingredient (specific item). They are indirect because they collaborate through the transaction.

Then you have to look at the particulars of the problem. In our example there are more varieties of ingredient there are more characteristics of ingredients to consider. Since there are more types of ingredients than bread, the ingredient is “more specific” than the bread. In the future, different types of ingredients may require specializations of the Application, or have special requirements.

In our experiences the specific item (ingredient) is usually more varied than the place (bread). A loading dock receives all sorts of deliveries of many different types of things. How a thing is delivered depends on its characteristics (fragile, perishable, etc.) So the thing being delivered should make the proper kind of delivery transaction tailored to its needs.

In general the thing being acted upon should make the transaction describing the action since it has the majority of the characteristics that determine if the transaction is valid.

In the object world which method is best for milking a cow?

In the real world, the farmer milks a milking cow. In the object world, the milking cow offers up a milk method that creates a transaction recording how much milk was delivered to the farmer. There are two possibilities for the milk method in the MilkingCow class:

public MilkingTransaction milk(long millilitersRequested){ ... }


public MilkingTransaction milk(long millilitersRequested, Farmer aFarmer){ ... }

The second choice is what we prefer. The cow’s milk service creates the transaction because an old cow may have not be able to crank out milliliters requested. So the cow knows its limits of production and can validate milliliters requested better than the farmer. If the milliliters requested is too much then an exception can be thrown. The farmer is also a parameter because the transaction should not be created if the farmer does not have the proper privileges to milk the cow.

In our methodology we localize all the testing rules in the services involved in adding collaboration. So to test the milliliters requested would actually be a collaboration property rule (See Ch 4) of the cow called when the cow was added to a MilkingTransaction, and to test the farmer has the proper privileges would be a conflict rule of the cow called when both the cow and the farmer are added to the transaction. (See pps. 257 - 267 for a detailed example of collaboration and conflict rules in Java).

Testing rules are invoked when the collaborations are established in case another scenario creates a MilkingTransaction and adds the cow without going through the cow’s milk service. If the rule to validate the milliliters requested and the farmer were only in the cow’s milk service then they would not be called in the alternative scenario. We want the rules called every time a cow and a farmer are added to a MilkingTransaction regardless of which services added them. (See also: How to Implement Collaboration Rules)



Why not a role and place collaboration pattern?

Typically when you associate a person or thing (role or specific item) to a place you want to record history about when the association was made, for how long it is expected to last, etc. We record history using an event (transaction) object. Examples are assigning an employee to an office or assigning an piece of equipment to a production facility.

The patterns would be:

            (Role - Transaction) + (Transaction - Place).  [person at place]

            (Specific Item - Transaction) + (Transaction - Place).  [thing at place]

(See Figure 1.)

Patterns where a single object acts as multiple pattern players are called Snap-Together patterns and described in Chapter Nine. (See pp. 278-291)

These patterns work fine as long as the history of the association is all you care about. If however your system is also tracking the interactions of the person or thing at the place then you need an object to describe the person or thing in the context of the place. We describe a person or thing interacting within a specialized context using a role object. For example if our system wanted to track the production runs a piece of equipment made at a particular facility we would need an equipment facility role to desribe how the machine was configued for that facility, its production schedule, etc. When the equipment moved to a new facility it would require a new equipment facility role for that new facility. In this example the specific item (equipment) is also behaving like an actor object. Patterns where a single object participates as different collaborators are called Overlay Patterns. They are also described in Chapter Nine. (See pp. 283-296 )

Also, when a person or thing is assigned to a place and has a role for that place, we often combine the assignment and role object into one. (See Figure 2.). The FacilityEquipment object has both the description of the equipment in the facility and its history of assignment. It is not necessary to combine the two but often more convenient.

Benefits of having a separate FacilityEquipment object for each facility are (1) that it allows for change if different facilities begin to require different information for each machine, and (2) that it allows for customization of behavior for each facility. For example, due to the differing environmental conditions, a machine may require different settings or maintenance schedules for each facility. Preferences for settings and maintenance schedules times could be retained with the FacilityEquipment object.



Must collaboration rules be implemented as code within their objects?

No. We implemented them using programming code within our objects to show how everything fits together. Trying to explain it in words was difficult when some snippets of code could say it so clearly.

We recognize business rules can be in rules databases, stored procedures, or whatever. The important fact is that the object knows how to get to the rules and decides when to run them, rather than some centralized manager deciding when the rules should run. Similar to telling an object to save itself and the object knowing which data manager to contact to do the persistence.

In fact, keeping the rules stored externally is a great mechanism for allowing updates. The important part is when are the rules invoked and who invokes them, wherever they are located. Those are the issues we are trying to address.

Please explain how to implement collaboration rules.

One approach for implementing collaboration rules is shown in Chapter 8, and the source code provided with the book has an example similar to the milking cow example. In the book example a document is nominated for publication on a corporate online site by a committee team member. The document is the thing being acted on so it creates the nomination with the team member through a nominate service. The “nominate” service of the Document class is very similar to the “milk” service of the MilkingCow class.

Collaboration rules are implemented in “testAdd” and “testRemove” services described in detail in Ch 8. These methods are always called when a collaboration is established or dissolved between objects.

The constructor for MilkingTransaction looks like this:

public MilkingTransaction (long millilitersRequested, MilkingCow aCow, Farmer aFarmer) throws BusinessRuleException
  this.quantity = millilitersRequested;
  try { this.addCow(aCow); }
  catch(BusinessRuleException excptn)
       throw excptn;

The MilkingTransaction addCow service calls (1) its own testAddCow method that directs the checks for conflicts between the farmer and the cow and (2) the MilkingCow testAddMilkingTransaction service that tests whether the cow can handle the transaction:

/* MilkingTransaction service */

public void addCow (MilkingCow aCow) throws BusinessRuleException
  if (aCow == null)
     throw new BusinessRuleException("Tried to add null cow");

/* MilkingTransaction service */

public void testAddCow (MilkingCow aCow) throws BusinessRuleException
  if (this.cow != null)
     throw new BusinessRuleException("Cow already exists.");
  if (this.farmer != null)
     aCow.testAddMilkingTransactionConflict(this, this.farmer);

/* MilkingCow service */

public void testAddMilkingTransaction( MilkingTransaction aMTransaction)
throws BusinessRuleException
  if (aMTransaction.getMillilitersRequested() > this.getMaxMillimeters())
     throw new BusinessRuleException ("moo...too much...");

So now however a MilkingTransaction is created, the business rules are enforced when a cow is added to it. Here’s our preferred technique for creating the MilkingTransaction in the milk service:

/* MilkingCow service */

public MilkingTransaction milk(long millilitersRequested, Farmer
  aFarmer) throws BusinessRuleException
  return new MilkingTransaction(millilitersRequested, this, aFarmer);

Why don't the doAdd & doRemove methods test business rules?

The rationale about the add, testAdd, and doAdd methods is explained in-depth in the book on pp. 241 –245, and in our article Putting Business Rules into Business Objects.

In a nutshell, we don’t put the tests in the doAdds and doRemoves because we want the flexibility of bypassing rules in special cases—when restoring an object from persistent storage, or for special trusted business services. The reason for having the doAdds is the encapsulate the implementation of the assignment in case other things need to happen when the object changes state, in case the assignment implementation changes, in case specializations want to change the assignment implementation, etc.

Doesn't this mean we need to trust our developers of the add method to call the tests?

Yes. But our rational is that the add services make up the public access layer of services for changing an object’s state. These methods always invoke business rule checking they are the methods available to object editors, methods of other objects, and internal methods needing business rule checking. The doAdds are the internal methods for bypassing rule checking, but that should be done very selectively.

Should the add service always invoke a doAdd service?

Yes. The doAdd encapsulates the assignment implementation of the collaboration. For example, how a farmer is stored within a MilkingTransaction. (See also: How to Implement Collaboration Rules).

In fact the addFarmer method should look like this:

/* MilkingTransaction service */

public void addFarmer(Farmer Farmer) throws BusinessRuleException
  if (Farmer == null)
     throw new BusinessRuleException("Tried to add null farmer");

Do you include the testAdd method when there are no collaboration rules for that collaborator?

For extensibility, we put all the test methods in even if they are no-ops. Later if the problem domain changes so that there are collaboration rules associated with that collaborator, less code is affected.

Why are tests for null in the add methods and not the testAdd methods?

Tests for null are logic tests as opposed to business rule tests. Business rule tests depend upon the semantics of the business domain and are isolated in separate test methods to encapsulate them for maintenance and extension. Specializations may extend or override the testAdd methods to implement new business rules. Specializations rarely if never override logic tests so we put that check in the add method. (See also our article Putting Business Rules into Business Objects).

Is a BusinessRuleException a checked or unchecked exception?

Short answer: checked.

Long answer:

In the book we have BusinessRuleException as a checked exception, but the alternative is not entirely verboten. The rationale is that the typical Java rule for when to use RuntimeException is that you should do it only if the exception is unlikely in a properly configured and written system. For example, a NullPointerException should not happen because a user did not enter something; the programmer has the option to check for null or ensure that values are always initialized. Since business rule exceptions can and generally do happen based upon user interaction they do not fall under this category. For example, a user might try to have a farmer milk a cow that was milked too recently. On the other hand, some people like to make everything a RuntimeException. They feel this makes their code “cleaner” in that they do not require try/catch blocks and “throws” clauses in their code. The problem here is that someone needs to catch the exception so that the system can recover gracefully. In the end, the choice is yours.