Monthly Archives: May 2010

Multiple States and Multiple Dependencies Using Message-Based Checkbox Patterns

Fourth in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

While a basic Ultimate Checkbox List Pattern uses only a single Boolean value – e.g. isSelected – its questioning event can allow more than just one answer: in addition to finding out if a row is selected (e.g. checking a checkbox), a questioning event can determine if a specific list item is visible or enabled at all. For example, the current user might not have rights to see a particular value; the page might have a terse or verbose option; some criteria might be selectable based on a separate criteria selection; or a set of items might have a maximum number of selections.

Like the selected state, the enabled state of a list item could be embedded in the item data itself, however one can choose to extend the Ultimate Checkbox List Pattern to. As each change in the list (or its proxy) makes every item check its state (see Multiple Views Using a Message-Based Checkbox Pattern), disabling any or all items is as easy as disabling one (remember that only visible items have item renderers with listeners which check state).

public class ThingieEvent extends Event
{
    public function ThingieEvent(...)
    {
        ...
    }
    public var thingie : Thingie;
    public var isSelected : Boolean = false;
    public var isEnableded : Boolean = true; // new flag public var notificationListener : Function;
}

The item renderer registers a listener the first time it checks the current item’s state by adding it to the questioning event:

...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        theEvent.notificationListener = this.onExternalThingieChange;
        this.dispatchEvent(theEvent);
        isThingieSelectedCheck.selected = theEvent.isSelected;
        isThingieSelectedCheck.enabled = theEvent.isEnabled;
...

And whenever the item renderer’s notification listener indicates something external changed, it will check the state of the specific data currently in the item renderer.

    private function onExternalThingieChange(event : Event) : void
    {
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data as Thingie;
        this.dispatchEvent(theEvent);
        isThingieSelecctedCheck.selected = theEvent.isSelected;
        isThingieSelecctedCheck.enabled = theEvent.isEnabled;
    }

On the list manager side, the first time the item renderer asks for a selection status by dispatching a questioning event, the list manager adds the notification listener (if present) using weak references. It can add the callback as a listener directly to the data list (e.g. ArrayCollection), or it can add it to a separate IEventDispatcher object in order to proxy events explicitly from multiple sources (e.g. signal a change when the _thingieList changes and when the user changes between “terse” to “verbose”).

    private var _thingieList : ArrayCollection = new ArrayCollection();
    private var _thingieListProxy : EventDispatcher = new EventDispatcher();
      ...
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, onThingiesChange);
        context.addEventListener(Event.STATE_CHANGE, onThingiesChange); // something else that requires a change-check
      ...

    private function onThingiesChange(event : Event = null) : void
    {
        _thingieListProxy.dispatchEvent(new Event(Event.CHANGE));
    }

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);
        event.isEnabled = (context.currentState == SELECTABLE_STATE) && (_thingieList.length < MAX_SELECTED_THINGIE_COUNT);
        if (event.notificationListener != null)
            _thingieListProxy.addEventListener(Event.CHANGE, notificationListener, false, 0, true);
    }

If the onThingsChange event carried information, it would link the listener and the dispatcher more tightly than we want. Using a generic Event with the type Event.CHANGE (the simplest possible notification) insures that the dispatcher can send that notification for any reason it wants; it is not restricted by any required or expected event parameters.

For those who like sequence diagrams:sequence diagram for multiple=

(Update: sample application in the final installment)

Multiple Views Using a Message-Based Checkbox Pattern

Third in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

The previous post showed how one can have an item renderer communicate with one of its containers to set and retrieve the selected (e.g. checked) state of the item renderer’s data. If, however, the same data (and its selected state) appear in more than one view, one needs to add another set of notifications to the pattern.

If something other than a particular item renderer changes the values in the thingieList, the item renderer needs to know to change the checkbox status. Rather than iterating through the children of the DataGrid or List to find all the ItemRenderers to tweak them, we can have sort of a “push” notification: the item renderer passes a listener function to the list manager the first time it asks for an item’s selected status, and external changes call that listener. To make things as generic as possible, the listener does not expect any specific type of event (i.e. the event does not contain information about the change); it simply checks its own status whenever it’s called.

This combination seems complicated, but it’s built on what we’ve done before:

  • The view dispatches an AmISelected event with a reference to its event listener function in it.
  • The list controller adds the event listener
  1. Something changes the list
  2. The list dispatches a CHANGE (or COLLECTION_CHANGE) event to all the listener functions
  3. The view listener functions dispatch an AmISelected event (without a listener reference in it)
  4. The list controller received the AmISelected event object and sets its .isSelected property based on the list
  5. The item renderer checks the .isSelected property and updates its display based on the answer


This causes a lot of events that don’t actually find any changes (i.e. every item renderer whose data have not be selected or deselected), however the cost for these events is low and the value of simplicity is high.

The item renderer registers a listener the first time it checks its data’s status:

 ...
        var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
        theEvent.thingie = data.thingie;

        theEvent.notificationListener = this.onExternalThingieChange; this.dispatchEvent(theEvent); // ---- listeners execute here

        isThingieSelectedCheck.selected = theEvent.isSelected;
 ...

And the item renderer’s listener function checks the status

private function onExternalThingieChange(event : Event) : void
{
    var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
    theEvent.thingie = data.thingie;
    this.dispatchEvent(theEvent);
    isThingieSelectedCheck.selected = theEvent.isSelected;
}

On the list manager side, it adds the callback function (if present) as a listener using weak references. It could add the callback as a listener directly to the data list or to a separate IEventDispatcher object if it was going to fire events explicitly

private function onIsThingieSelected(event : ThingieEvent) : void
{
    event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);

    if (event.notificationListener != null)
        _thingieList.addEventListener(CollectionEvent.COLLECTION_CHANGE, event.notificationListener, false, 0, true);
}

By adding one notification, changes to the selection list automatically update all items whether they are visible or become visible later, so the user can can modify or clear the list without tight coupling with all the other views that add and remove items.

(Update: sample application in the final installment)

The Ultimate Checkbox List Pattern

Second in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

A common task is to put checkboxes into a list or grid. Instead of adding Boolean property values to the dataProvider items, the Ultimate Checkbox List Pattern leaves the display item alone (e.g. a pure value object) and uses membership in a separate list of items to indicate if an item is selected (checked). Often, this list of selected rows itself is very useful. Standard ActionScript events communicate between the item renderers (with a checkbox) and a container object or the form itself acting as a controller for the selected list.

The key to this pattern is anonymous communication: the list controller does not know what components are sending messages asking if this or that object is or is not selected, and the view (i.e. an ItemRenderer) does not know who is listening and answering its questions. They communicate using a custom event that adds a reference to the item, and a Boolean: isSelected. For example,

public class ThingieEvent extends Event
{
    public var thingie : Thingie;
    public var isSelected : Boolean = false;
    public var notificationListener : Function;
}

Changing the Selected State
The ItemRenderer sends an event when user interaction with its checkbox changes the selected state:

 ...
        var theEvent : ThingieEvent = new ThingieEvent(THINGIE_SELECTION, true);
        theEvent.thingie = this.data.thingie;
        theEvent.isSelected = thingieCheckBox.selected;
        this.dispatchEvent(theEvent);
 ...

The list manager might handle the event like this:

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        var existingIndex: int = _thingieList.getIndexOf(event.thingie);
        if (event.isSelected != (existingIndex != -1))
        {
            if (event.isSelected)
                _thingieList.addItem(event.thingie);
            else
                _thingieList.removeItemAt(existingIndex);
        }
    } 

    private var _thingieList : ArrayCollection = new ArrayCollection();

Getting the Selected State
When an ItemRenderer initializes itself, it needs to know if it should set the checkbox.selected attribute based on the data. It needs to ask someone outside itself if the current item should be checked. Rather than have the list manager add event listeners to every ItemRenderer, the ItemRenderer dispatches an event, waits for all the listeners to review it , and look at the event’s properties as the answer to the question.
It dispatches an event that bubbles (or is proxied up to the DataGrid or List) to some container acting as a list manager. It will set the event.isSelected property. Once the dispatchEvent() method returns, the ItemRenderer looks at that property.

 ...
    var theEvent : ThingieEvent = new ThingieEvent(IS_THINGIE_SELECTED, true);
    theEvent.thingie = data.thingie;

    this.dispatchEvent(theEvent); // ---- listeners execute here

    isThingieSelectedCheck.selected = theEvent.isSelected;
 ...

Note that after the .dispatchEvent(), the event has whatever value the listeners put in there. On the list manager side, the listener might look like this:

    private function onIsThingieSelected(event : ThingieEvent) : void
    {
        event.isSelected = (_thingieList.getIndexOf(event.thingie) != -1);
    }

Note that it does not cost anything to add a listener more than once, and using a weak reference prevents memory issues. The Ultimate Checkbox List Pattern uses bubbling events; if one is not fond of them, one can proxy the events through custom Column classes, then through the top-level Grid or Listbox, and then up to whatever is acting as the list manager.

An advantage to bubbling events is immunity to changes in the number of containers between the item renderer and the list manager. One can even encapsulate some set of containers into a component and embed it in another container without changing this pattern.

The Ultimate Checkbox List Pattern has several advantages over using a flag in the dataProvider item to persist checked status:

  • The dataProvider items can remain pure value object (e.g. unchanged from an loosly-linked data module)
  • The same item can have separate selection-states on an infinite number of lists
  • The list of selected items is always current and available at a high level; one does not need to iterate through the dataProvider items
  • Items remain selected even when they are not visible or if they are not in the dataProvider’s collection. One can page off and back and previously selected items are still selected.
  • Items can be selected and deselected across several different views (if the list manager tests membership using an ID instead  of object identity). E.g. one can have browse lists and search results that reflect each other’s selection (ee the next posting for details).

(Update: sample application in the final installment)

Go Ask Your Container

First in a series of five. This blog entry is part of my article in the Flash and Flex Magazine

One of the things I had to learn moving from Windows programming to Flash/ActionScript programming was all the asynchronous patterns (aka two-part procedures). If one needs to load a resource in the middle of a process, one cannot just call a loader and wait for the results before continuing. One has to register an event listener to the loader object and put the remainder of the process into that listener function. When the loader is done loading, it calls the listener, and the rest of the process goes on its merry way. While this is indeed asynchronous programming, events themselves are not asynchronous.

Events are dispatched (aka “fired”, “launched”, “broadcast”, “thrown”) from classes implementing IEventDispatcher – usually by descending from or containing the class EventDispatcher – by calling the event handler functions (“listeners”) previously registered. The dispatcher does not care how many listeners have registered themselves or what they do: it just calls every one registered for a particular message.

Event handlers are, at their core, callback functions. One can call them explicitly, but they are designed to be registered with a dispatcher, and wait for it to call them. One should keep these callback functions very lightweight because events themselves are not asynchronous.

When one to fires an event by calling a dispatcher’s dispatchEvent method, the method literates through the list of registered listener functions, calling each one with the Event object as a parameter, and waiting for it to return before calling the next listener function. Then the dispatchEvent method itself returns. The code that calls dispatchEvent can assume that, when that call returns, all the listeners have had a chance to see and modify the Event object.

One can use events as a bidirectional messages between the dispatcher and the listeners, not just a one-way notification system; the event object can receive information from the listeners as well as send information. Combined with bubbling events that allow containers to get events without registering with the originating dispatcher, this patterns allows nested objects like ItemRenderers to ask questions of their high-level containers without each intermediate container passing the events up and the results down. This relationship is a loosely-linked one: the dispatcher does not know what object is setting the answer properties of the Event object; the listener does not know what object is dispatching the Event object. The form can add or remove containers without breaking.

The Event class already has one Boolean property that is designed for listeners to set: the defaultPrevented property. Listeners can call event.preventDefault() to set this, and the dispatching code can check the value (the dispatchEvent method itself returns this value as well).

For example, an ItemRenderer needs to know if the data it is displaying is part of the set that the user wants to focus on. The data itself does not know, but the top-level form object does. The ItemRenderer can dispatch an event containing its data object and a property for the current status.

public class AmIInUserFocusEvent extends Event
{ 
    public function AmIInUserFocusEvent(type : String = AM_I_IN_FOCUS, bubbles : Boolean = true, cancelable : Boolean = false) 
    { 
        super(type, bubbles, cancelable);
    }

    public var rowData : RowData; public var isInUserFocus : Boolean; 
}

In the ItemRenderer:

 ...
       var newEvent : AmIInUserFocusEvent = new AmIInUserFocusEvent(AM_I_IN_FOCUS, true);
       newEvent.rowData = this.data as RowData;

       this.dispatchEvent(newEvent); // ---- listeners execute here 

       if (newEvent.isInUserFocus) 
           text.styleName = "focusStyle"; 
       else 
           text.styleName = "neglectedStyle"; 
 ...

In some container that holds the item renderer’s list or grid :

 ... 
        this.addEventListener(AM_I_IN_FOCUS, onFocusQuestion);

        ....

    private function onFocusQuestion(event : AmIInUserFocusEvent) : void
    {
        event.isInUserFocus = focusList.contains(event.rowData); 
    }
 ...

To summarize, in additional to sending notifications and data out, events can also get answers. ActionScript’s built-in event framework allows loosely-coupled communication between different parts of a form, even across component bounds.

(Update: sample application in the final installment)

Distributed Dates

When you announce an event in email or put in on your web site, instead of just showing text describing the event, make it easy for your audience to save the date. With the prevalence of on-line and PDA and cell phone calendars, you can get your event on their calendar easily.

Providing the event information yourself instead of depending on your audience to copy ensures accuracy (i.e. no transcription or transposition errors) and complete: you can include the street address, contact phone number and email, directions, links to on-line maps, prerequisites, and preparation suggestions (e.g. “Bring a jacket because it gets cold in the evening”)

I’ll be talking about three different ways to communicate event information:

  • Load it on their Yahoo or Google Calendar using a link
  • Distribute it as an iCalendarFile
  • Share your public calendar

Load It on Their Yahoo or Google Calendar Using a Link

Both Yahoo and Google have a format for describing a calendar event as a URL. If you supply these as links on your web page or HTML email, users can click them and immediately add the event to their own calendars.

Yahoo Calendar Links

The Yahoo Calendar link is at the bottom of each Yahoo Calendar page as text. Note that the link represents the event as it was when the page appeared; it does not dynamically reflect any changed you make, so save any changes and then copy the link.

Google Calendar Links

The details page for a Google Calendar event has a link in the lower right corner: “Publish this event”. It will pop-up a dialog with the address selected for easy copying.

Distribute It as an iCalendar File

As with most computer things, calendar items have a standard format so every system can understand the data. The iCalendar format replaces an older format named vCalendar. You can send this file as an email attachment or as a downloadable file on your web site (example below)

Almost all calendar applications (like Outlook/Exchange, Backpack, Notes, Sunbird) will import “iCal” files (some will export as well). Some operating systems associate the .ical and .ics file extensions with the calendar program so that program automatically imports the calendar file whenever the file is “executed”.

Share Your Calendar

Both Yahoo and Google allow you to create an on-line calendar and publish it so users of those systems can merge it (subscribe) with their own calendars. Your subscribers will see events as soon as you add them with no action on their part. They will also see them in relation to their own scheduled calendar events, so they can plan and anticipate.

Here is a Yahoo Calendar that subscribes to several other calendars. All the subscribed calendars show up as items in the right-hand column.

Subscribing to a Yahoo Calendar

Instruct your users to go to their Yahoo Calendar and select the “Edit” link My Time Lines in the upper right corner of the top date display (not the top right corner of the screen)

They can select any of their group’s calendar or a friend’s calendar:

Here is a Google Calendar that subscribes to another calendar. The events are color-coded to show which calendar they come from. In this case, pink is “my” events; red is for Sign Language Club De Anza calendar’s events.

Note that subscribing to someone else’s calendar does not expose your calendar

Sharing/Publishing Your Yahoo Calendar

Insure that the calendar you are going to share is completely public (do not share your personal calendar just because it has some public events on it). If you manage a Yahoo group, you can publish that group’s calendar. You can also create a separate Yahoo account to publish.

Pick a calendar and set its publication in the Calendar | Setting | Calendar page:

Subscribing to a Google Calendar

Tell your subscribers to choose the Other calendars | Add link on the left panel. They can select a friend’s calendar or enter the calendar’s address.

You can find the address of your calendar at Settings | Calendar Details (scroll down) Calendar Address

Sharing/Publishing Your Google Calendar

Google Calendar allows you to create many calendars and publish them individually.

Specify your calendar’s publication in the Calendar | Setting (top left corner)| Calendars | Share this calendar

You can make the calendar either public or available to specific Google Calendar users.


Example of a Yahoo Calendar URL – wrapped to multiple lines for ease of reading

http://calendar.yahoo.com/?
  v=60&
  VIEW=d&
  in_loc=Adobe+HQ+-+San+Jose&
  in_csz=San+Jose%2c+CA+95110&
  type=20&
  TITLE=Silvafug+South+-+San+Jose+-+Design+and+Development+Workflow&
  ST=20090515T013000Z&DUR=0100&
  URL=http%3a%2f%2fria.meetup.com%2f12%2fcalendar%2f10232257%2f&
  DESC=For+full+details%2c+including+the+address%2c+and+to+RSVP+see%3a%0ahttp%3a%2f
     %2fria.meetup.com%2f12%2fcalendar%2f10232257
    %2f%0aFlex+3+%26+Adobe+AIR+Junkies%0aThere+are+two+sessions+this+month+12th+in+San+Francisco+and+14th+in+San+Jose.+The+presentations+will...

Example of a Google Calendar URL – wrapped to multiple lines for ease of reading

http://www.google.com/calendar/event?
 action=TEMPLATE&
 text=Silvafug+South+-+San+Jose+-+Design+and+Development+Workflow&
 dates=20090515T013000Z%2f20090515T023000Z&location=San+Jose%2c+CA+95110&
 sprop=website%3ahttp%3a%2f%2fria.meetup.com%2f12%2fcalendar%2f10232257%2f&
 sprop=name%3aFlex+3+%26+Adobe+AIR+Junkies&
 details=For+full+details%2c+including+the+address%2c+and+to+RSVP+see%3a%0ahttp%3a%2f
  %2fria.meetup.com%2f12%2fcalendar%2f10232257
  %2f%0aFlex+3+%26+Adobe+AIR+Junkies%0aThere+are+two+sessions+this+month+12th+in+San+Francisco+and+14th+in+San+Jose.+The+presentations+will+be+the+same+so+RSVP+to+the+one+that+is+a%26hellip%3b%22

Example of an iCalendar file (from Wikipedia)
Here is a simple example of an iCalendar object, “Bastille Day Party” event which occurs July 14, 1997 17:00 (UTC) through July 15, 1997 03:59:59 (UTC):

BEGIN:VCALENDARVERSION:2.0PRODID:-//hacksw/handcal//NONSGML v1.0//ENBEGIN:VEVENTDTSTART:19970714T170000ZDTEND:19970715T035959ZSUMMARY:Bastille Day PartyEND:VEVENTEND:VCALENDAR

Other References

See also toomanydaves…words by davelms

Copyright © (copyright) All Rights Already Reserved

Throwing a copyright notice on a page is a reflexive action, but as with most checklist items, it deserves more mindfulness. The point of copyright is to protect the layout of graphics and images, and the exact phrasing of text. If it’s worth protecting, then it’s worth a few moments of attention.

A copyright notice is the word “copyright” or its token © — “c” in a circle (pick one, not both) , the year of publication, and the entity holding the copyright; that’s it. No “All Rights Reserved”, no history of changes: just that.

© 2010 Richard C Haven

Most important, however, is to have content worth protecting.


Notes

Copyright notices

Use of a copyright notice © consisting of the letter C inside a circle (that is, © or U+00A9), the abbreviation “Copr.”, or the word “Copyright”, followed by the year of the first publication of the work and the name of the copyright holder was part of previous United States statutory requirements, but since 1989, when the U.S. adhered to the Berne Convention, the use of copyright notices has become optional to claim copyright, as the Berne Convention makes copyright automatic.[8] However, notice of copyright (using these marks) does have consequences in terms of allowable damages in an infringement lawsuit in some places.

http://en.wikipedia.org/wiki/Copyright

“All Rights Reserved”:

This notice became obsolete and essentially deprecated on August 23, 2000, as every country that was a member of the Buenos Aires Convention (which is the only copyright treaty requiring this notice to be used) is also a member of the Berne Convention which requires protection be granted without any formality of notice of copyright.

http://en.wikipedia.org/wiki/All_rights_reserved

Hi, I’m Biill

Another lamentably rare old-school habit is naming parameters as uniquely as if they were local variables (which they are), especially in constructors. For example:

public function MyClass(transportationBill : Bill, sponsor : Sponsor,
      submissionDate : Date, referenceId : String = "", fundingBiill : Bill = null)
{
    this.transportationBill = transportationBill;
    this.sponsor = sponsor;
    this.submissionDate = submissionDate;
    this.referenceId = referenceId;
    this.fundingBill = fundingBill;
}

All nice and compilable, except it has a silent bug that will sneak up and ruin someone’s day. Note the typo in the last, optional argument: “…Bii…”. The reference this.fundingBill = fundingBill works fine, but assigns the class attribute fundingBill to itself because no parameter has that name.

If all the constructors had a unique name, then any typos would show as compiler errors:

public function MyClass(aTransportationBill : Bill, aSponsor : Sponsor,
    aSubmissionDate : Date, aReferenceId : String = "", aFundingBiill : Bill = null)
{
    this.transportationBill = aTransportationBill;
    this.sponsor = aSponsor;
    this.submissionDate = aSubmissionDate;
    this.referenceId = aReferenceId;
    this.fundingBill = aFundingBill;    // <---- compiler error
}

The roles of each token is clear within each line: some are class attributes and some are arguments.

Note that I am not a fan of Hungarian notation: the type of each token should be described in full words, not in a vowel-less prefix. The role of each, however, can be implied with a language artifact like a grammatically correct article (e.g. indefinite (“a”) for parameters and definite (“the”) for local variables).

public function doSomething(aRequest : Request) : void
{
    if (aRequest != null)
    {
        var theValue : String = aRequest.id.toLowerCase() + aRequest.host;

        if (!this.isInProcess(theValue))
            this.submitRequest(theValue, aRequest);
    }
}

Generally Optimistic Database Updates from a Resonably Rich Client

The problem with having a data model in the client application is that its data might not match the server’s version of that data. Even if the client sends any changes to the server immediately, some other client might have changed the server’s data since the client received it. Even if the server pushes all changes to all clients immediately, you will have cases where updates get lost. Don’t even start thinking about briefcase applications.

This is the old-school Lost Update (remember? from the beginning of database class when they talked about history and transactions). In a nutshell, if two clients start with the same picture of the data (sent from the server) and both make changes and both submit those changes, one of the two changes is going to get lost, at best.

The worst thing an application can do, by far, is lose data silently. Crashing is embarrassing and annoying, but users figure out how to work around it. Getting error messages is only slightly less annoying, but the user knows something went wrong and will check to see if their data is present. If a server does not save the changes that the user thinks it did, by the time the user finds out, they won’t even remember how many changes were lost, let alone be able to recreate them. This will lose that customer, and deservedly so.

Assume that data moves in chunks (e.g.some joined rows) that represent an object in the client data model. The best thing a server can do if it receives an update and detects that the client made changes to an out-of-date version of data is to reject the update loudly: return a fault so the client knows that they have a problem. The classic way to detect this is optimistic “locking”: sending a copy of the original data along with the changes and checking all those values in the SQL UPDATE statement:

UPDATE table T1
SET Column2=:newValue2, Column3=:newValue3,...
WHERE Column2=:oldValue2 AND Column3=:oldValue3 AND ...

If anyone else changes the values on the server, the update will fail (yay). A cheaper way to catch this is to 1) make sure that a LastModified column matches the client’s value when the client updates; and 2) update the LastModified column every time the server database updates a row (some DBMS make this very easy).

UPDATE table T1
SET Column2=:newValue2, Column3=:newValue3,...,
ColumnN=:newValueN, LastModified=:now
WHERE LastUpdated=:clientVersionLastUpdated

Note that this LastModified column must be part of every update and sent down with every object.


The client has to make some decisions when it either gets an update rejected by the server or receives an update from the server to data that the user has changed.

  1. Throw away the user’s changes and do nothing else (this is the Very Bad Thing we talked about above)
  2. Automatically refresh the data from the server and re-apply the user’s changes (blindly overwriting the other changes; also a Bad Thing)
  3. Throw away the user’s changes and tell them to do it over.
  4. Show the user what changes happened to the base data and ask if they want to re-apply their changes.
  5. Have each object’s code look at the changes from the server and re-apply the user’s changes that it determines are compatible. Other changes, see 3 or 4.

Apart from 1. and 2., the options come in increasing order of work, complexity, and user friendliness.

Brumme’s Law of Client Application Performance

Brumme’s Law:

  • Hitting storage costs
  • Hitting the network costs
  • Everything else is free

Haven’s Codicil to Brumme’s Law

  • Maybe updating the screen costs

Chris Brumme was a scary-smart programmer working on Borland’s Paradox for DOS (I assume he is still scary-smart working at Microsoft on the future of OS). He could debug by looking at the instruction stack in hex. He coded the interpreter/compiler for Paradox’s scripting language.

At the time, I could barely understand the issues he was dealing with, nevertheless one day we were discussing how Paradox interpreted/compiled some piece of scripting code, perhaps re-evaluating some control value in a loop. I wanted the code to run as fast as possible (Paradox was in a speed contest with FoxPro at the time). He squinted, sighed, and tried to explain in simple terms why optimizing that particular operation was not worth his time to do (or my time to test).

Just as the difference in storage cost for a single or double-linked list is less than paying the salaries of two people to argue about it for one minute, the saving from optimizing the compiled form of this common action was effectively zero compared to the cost of risking one bug or the cost of maintaining more complex code. Compiled and even interpreted code runs so fast that, apart from absurdities, the code execution itself will not be the bottleneck.

Optimize the slow part, not the fast part

Even in high-level code itself, tactical optimization is rarely worth it. Careful “tuning” might gain 5% to 10% in performance at the risk of de-stabilizing the operation itself. Putting that effort into refactoring and re-designing some core data-retrieval or communication procedure (i.e. avoiding one web service call or bundling several sets of configuration data into one transfer package) can offer ten times that improvement.