Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Magma Commit Strategies
Last updated at 8:38 pm UTC on 22 March 2006
Q: I don't want to reference a MagmaSession in my domain. How can I perform the necessary #commits: while still keeping it decoupled from Magma?

A: There are at least three approaches that can be used.

1) Program-controlled transactions: You signal commit notifications in your domain. A controller catches these notifications and applies them to its session. When no controller is listening, the notifications are ignored, allowing testing of the domain with or without the database. While you do not have to reference a MagmaSession, it is not completely transparent because you do have to signal the notifications:
	name: aString
		MagmaSessionRequest signalCommit: [ name := aString ]

This approach gives the program control over when commits are performed. It also allows the user to be free of any concern about remebering to "save"; everything that requires a transaction will be committed without them thinking about it.

One disadvantage is reduced concurrency-detection. The signalCommit: does the refresh, update and commit without the user ever seeing whether the changed value was already changed. For this reason, this sort of commmit strategy is useful for low-concurrency models, i.e., where different analysts work on their "own" domain objects.


2) User-controlled transactions, with auto-begin: With this approach, the user is always in a transaction. The program provides a "Save" or "Commit" button which the user occasionally presses as they modify the domain model. The program could also provide its own "Cancel" function (which would send #abort, followed by #begin to the MagmaSession) to provide a rudimentary undo function. To use auto-begin, your program does an initial #begin when connecting the session, then every commit should instead use #commitAndBegin instead of #commit.

Since Magma needs transactions to be short, this approach is most suitable for programs with very frequent domain changes; such as programs that support "data entry" activities. Performance is increased because the #begin step occurs right after the commit automatically with only one trip to the server.

This approach also allows complete transparency; i.e., the domain can be written with no awareness of any database. No commits or signals are needed in the code.

Concurrency detection is also much better; consider our name: setter example from above. This time, the code is, simply:
	name: aString
		name := aString

This time, if this object has changed the user will get a commit-error when they commit and the object will update to the current value.

Users decide when to "save", therefore the program should be written so the user has control only when the domain is in a consistent state worthy of being committed. For example, in a banking application, when a user initiates a transfer, don't let them commit between the withdraw and the deposit, only after both.

This approach is less favorable for programs that do not update the domain model frequently. Because users are always in a transaction, their MagmaSessions will not receive auto-abort signals. It is therefore up to the users to keep their views refreshed by either committing or aborting. If they do not, and there are lots of changes happening to the domain by other users, Magma will eventually terminate the an inactive users session, bloated with pending changes, and the user will have to log in again.


3) User-controlled transactions, user-controlled begin: In this approach, the program provides the user with both a "begin" as well as "commit" button somewhere, so they are in complete control of transactions. This is just like the previous option except, since the user is not always in a transaction, auto-abort signals will be received. This is in exchange for the additioonal clicking the user must do to explicitly #begin their transactions.

About refreshPersistentObjectsEvenWhenChangedOnlyByMe

Within each of these strategies, another option further enhances their flexibility:
  mySession refreshPersistentObjectsEvenWhenChangedOnlyByMe: true

Setting this option to true does reduce performance slightly, but is used to be "more-connected" to the repository. It causes your changes to be lost if they were changed by someone else.

The default value is false which, when using commit-strategy (3), allows users to make changes to an object, "test" them, and, only after that, #begin and immediately #commit a transaction. The #begin is non-destructive to their own changes which were not changed by another user. In this way it is a sort of "merge" with the users local model.