Flow Synchronization

Synchronize screens with an underlying model based on the flow of the user interaction between the screens.

15 November 2004

This is part of the Further Enterprise Application Architecture development writing that I was doing in the mid 2000’s. Sadly too many other things have claimed my attention since, so I haven’t had time to work on them further, nor do I see much time in the foreseeable future. As such this material is very much in draft form and I won’t be doing any corrections or updates until I’m able to find time to work on it again.

Applications often contain multiple screens that display the same data. If the data is edited in one screen, then the other screens must be updated to reflect the changes.

Flow Synchronization does this by having the screen code explicitly re-synchronize at the appropriate point in the work flow of the screen.

How it Works

Flow Synchronization is a very simple approach to explain. Essentially each time you do something that changes state that's shared across multiple screens, you tell each screen to update itself. The problem is that this means, in general, that every screen is somewhat coupled to the other the other screens in the application. If you have a lot of screens that are working in a very open-ended way, this can be nasty - which is Observer Synchronization is such a strong alternative.

Flow Synchronization thus better with simple navigation styles.

One common style is a root and child style. Here you have a root window that is open for the whole application. When you want more detailed information you open a child window, which is often modal. In this situation it's easy to use Flow Synchronization, all you need to do is to update the root whenever you close a child. If you do this in the root screen the child doesn't need to be aware of the root.

If the child is non-modal, this can get become more difficult. It's straightforward if you follow the approach of only updating the data (and thus the root) when the child is closed. If you want updates while the child window is still open then you are moving towards the territory of Observer Synchronization. It's also problematic if data is shared between the children.

Another simple style is a wizard style where you have a sequence of screens in order. With a wizard each screen is modal and movement from one screen to another involved closing the old screen and opening another. So in this situation Flow Synchronization is easy to do: update the data on closing a screen and load the fresh data when opening the next screen. You can have a wizard sequence of modal children with a root screen where closing the last child updates the root.

When to Use It

Flow Synchronization is an alternative to Observer Synchronization for synchronizing screens with domain data. It is, in many ways a more explicit and straightforward way of doing things. Instead of implicit Observer relationships which can be hard to see and debug, you have explict synchronization calls clearly laid out in the code.

The problem with Flow Synchronization is that things can get very messy once you have an unconstrained amount of screens that may share data. Any change on any screen needs to trigger other screens to update. Doing this through explicit calls to other screens makes screens very interdependent. This is where Observer Synchronization is so much easier.

Despite its limitations, Flow Synchronization does have its place. It works well providing the navigational flow of the user interface is simple and only one or two screen are active at the same time. Examples of such situations are sequences of screens (such as wizards) and a root screen with modal children. Observer Synchronization will also work with these cases but you may find the more explicit approach preferable. Web user interfaces are effectively a sequence of screens and thus work effectively with Flow Synchronization, this is an example where the protocol of the client/server connection makes Observer Synchronization very difficult to do.

Example: Root and Child Restaurent List (Java)

With example I hava couple of simple screens. The root is a list of restaurents. To edit the list you click on the restaurent entry to edit the details. If you change the name, then the list needs to update itself, both in the contents of the name and also to preserve alphabetical order.

The restaurent class is so boring I won't repeat it here. There are just string fields corresponding to the fields on the UI and the attendent getters and setters. Not much of a class, but it's not the focus of this discussion so I can permit its sad, pathetic existance.

The form that edits the restaurent details is also rather simple. I have a single flobal update listener that I attach to each field, so any change in a field causes a global refresh of the underlying domain object and the form - this is coarse-grained synchronization.

class RestaurentForm...

  public class FieldListener extends GlobalListener {
     void update() {
         save();
         load();
     }
  }
  private void load() {
      nameField.setText(model.getName());
      placeField.setText(model.getPlace());
      favoritesField.setText(model.getFavorites());
      directionsField.setText(model.getDirections());
  }
   private void save() {
       model.setName(nameField.getText());
       model.setPlace(placeField.getText());
       model.setFavorites(favoritesField.getText());
       model.setDirections(directionsField.getText());
   }

The restaurent list needs to be updated at two points, on initial creation of the form and whenever a child window closes. I put the code to update the list in a method.

class RestaurentListForm...

  void load() {
      sortModel();
      list.setListData(getRestaurentNames());
  }

  private String[] getRestaurentNames() {
      String[] result = new String[model.size()];
      int i = 0;
      for (Restaurent r : model) result[i++] = r.getName();
      return result;
  }

  private void sortModel() {
      Collections.sort(model, new Comparator<Restaurent>() {
          public int compare(Restaurent r1, Restaurent r2) {
              return r1.getName().compareTo(r2.getName());
          }
      });
  }

I then call it from the constructor of the form and from an action listener attached to the edit button.

class RestaurentListForm...

  public RestaurentListForm(List<Restaurent> model) {
      this.model = model;
      buildForm();
      load();
      window.pack();
      window.setVisible(true);
  }
private class EditActionListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        new RestaurentForm(window, selectedRestaurent());
        load();
    }
}

Comparing to a custom List Model

An obvious alternative to this approach is to use a custom list model. The implementation above uses a built in list model which takes a copy of the data from my list of restaurents. An alternative to a copy is to provide my own list model implementation that is just a wrapper on the underlying list of restaurents.

private class RestaurentListModel extends AbstractListModel {
    private List<Restaurent> data;
    public RestaurentListModel(List<Restaurent> data) {
        this.data = data;
    }
    public int getSize() {
        return data.size();
    }
    public Object getElementAt(int index) {
        return data.get(index).getName();
    }
}

Now I create this wrapper on the list of restaurents and supply it to the list widget when I create it. This way the list uses the underlying list of restaurents as its model, rather than a separate list of strings. Any changes I make to the restaurent name is automatically propagated through to the screen, so I don't have to write or call the load method.

A more tricky question is what to do about the sort order of the list. If the sort order makes sense for the domain classes, then I can simply sort them there, as long as I re-sort the restaurent list when I change a name. Often, however, sort orders are particular to a screen, in that different screens may have different sort orders. In this case triggering the sort scheme can be more of a problem. An alternative is to sort the list each time it's asked for - but that may make the UI unresponsive, particularly if the list is large.