Mutable properties

All of the fields of a Correspondence object are immutable. They are set at the time of construction. They define the identity of an object, so they cannot be allowed to change.

How, then, can you represent mutable properties in Correspondence? By doing the only thing that Correspondence allows you to do: create more objects.

A class for each atomic operation
A Correspondence object represents an atomic operation. It records the fact that someone has made a change. So one such change could be the modification of a property. Let's express the atomic operations of a project and one of its mutable properties:

  • CreateProject(): Project
  • SetProjectName(project: Project, name: string)

Since we have two atomic operations, we define two Correspondence classes. The class that represents the CreateProject operation is the Project itself. The class that represents the SetProjectName operation will be called ProjectName.

Define prerequisites
It is apparent from the definitions of these two atomic operations that the Project is a prerequisite for the ProjectName. You can't name a project before you create it. And in order for the ProjectName to make sense, you must know which Project you are talking about.

image So if Project is the only prerequisite for ProjectName, we can have an object model like the diagram on the right. If we set the project name three times, we end up with three ProjectName objects that are equal successors of the Project object.

There's one significant problem with the model just described. It is impossible to tell from the model alone which is the correct name of the project. It was set three times, and nothing about the diagram tells us which is the intended name. We could go by the time of creation, but that is insufficient in light of synchronization. One user might have set the name on one machine, while another user set the name on a different machine. We can't see the intent of the users in the model, so we can't make a reasonable decision.

Current knowledge is a prerequisite
The solution is to capture that intent by adding prerequisites. The prerequisites of an atomic operation are not just the parameters required for the operation to make sense in isolation. They also include the operations that have come before. The operation was performed by a user with a certain set of knowledge. If we capture that knowledge as prerequisites, we can glean the user's intent.

image In our case, we are going to capture the current project name as a prerequisite for any new project name. The user knew that the project was called WSE when he changed it to Indigo. Later, he knew that it was Indigo when changing it to WCF. This changes the diagram to the one on the left.

This diagram captures the intent of the user. He was changing the project name with the knowledge of the prior project name. And now the diagram clearly shows what the current name is: it is the last in the chain of succession.

Detect conflicts
image So what about the case of the two users on different machines? What if the developer chose the name Indigo while the analyst chose WCF? Both of those decisions were made with the knowledge of the name WSE, and so you get the diagram on the right.

From this diagram, it is apparent that there is a conflict. We no longer have just one leaf of the tree of ProjectNames. Now we have two leaves. Both of these siblings are just as worthy in the chain of succession of representing the current name of the project.

Correspondence makes no assumptions about how to resolve conflicts. But it does make it obvious when they have occurred. It is now up to the application to decide on a conflict resolution strategy. Knowing that there was a problem is the first step.

Fields of a Correspondence object are immutable. Modifiable properties are implemented as a pattern involving a new class, prior operations as prerequisites, and conflict detection. Conflict resolution is the responsibility of the application.

Leave a Reply

You must be logged in to post a comment.