Open Source Applications Foundation

[Design] recommendations from sister project...

David Jeske Sat, 21 Jun 2003 11:00:25 -0700


I have a personal project called Wintermute which is a sister-project
to Chandler. In the interest of helping the folks working on Chandler,
I'd like to share some lessons that I've learned so far.

Background:

When the first OSAF press went out, I was inspired to install Lotus
Agenda, and what I saw was really neat. I had already been working on
a tool in this space in the past and seeing Agenda inspired some new
ideas. This was last August, between the Vista prototype and the first
Chandler development release.

While I have lots of experience with Python, I like using strong typed
interfaces when software needs to be developed by many parties
(i.e. when it has plug-in apis). I decided to use Java Swing for my
app. I also have a strange death-wish in wanting to know if Java will
ever really work for client software.

You can flip through some screenshots here, although one of the nicest
things about Wintermute is the threaded-interactivity and UI
responsiveness, and that dosn't show on the screenshots.
 
  http://www.neomason.com/wm.cst

Architecture Details:

 - Wintermute uses an object database storage model with propeties
   and relationships between objects, the most interesting feature
   is that all relationships are bi-directional. This means that
   it's always possible to track backward links, and it's easy to
   break links from either side of the connection. This is possible
   because the relationships use a reciprocal naming scheme. If
   adding the "email:contact" relationship on one side, a relation for
   "contact:email" is added on the other side.
 - It uses sleepycat transactional server for the raw storage.
 - With lots of relationships created between items, and all of
   those relationships requiring both backward and forward links,
   the potential to do lots of writing exists. Wintermute minimizes
   the amount of time spent doing this by using a checkpointing
   scheme. All changes occur in memory only. Periodically, one
   transaction is opened and 
 - The user-inteface is defined at a high-level by the objects
   themselves. It's similar in concept to XUL, but only exists in the
   object database, not any flat XML file. This is neat, because
   storing configuration and state data about UI instances is really
   easy. For example, all tables remember exactly where they were
   scrolled, what was selected, and allow the same level of
   configuration.
 - It has some nice general models for synchronizing with external
   datasources. Currently implemented are: UNIX mbox, POP, IMAP, CSV,
   MySQL, RSS, and Yahoo Intellisync (has some bugs). 
 - It has generic table, email, and calendar data viewers
 - It uses lucene to full-text index and search over all data
 - A background "relationship builder" watches all object changes and
   periodically builds relationships, handles full-text indexing etc.

Lessons:

 - Life will be better for everyone if there are separate 'databases'
   for storing (a) user-authored data, (b) remote synchronized data,
   and (c) application configuration.

   Because Wintermute is in flux, we are constantly dropping the
   database and rebuilding to pick up new application UI configuration
   data. This causes a problem because it drops all the user data and
   remote synchronized data at the same time. This issue will also
   exist when new application releases are distributed which have new
   UI metadata options. We really need to support separate
   repositories for these different types of data.

   It is also obvious that in the future it will be important to
   provide a simple backup for the user's originally authored data.

 - bi-directional relationships are good. Wintermute relationships are
   a little too sloppy because their names are totally
   arbitrary. Building names out of the fields which cause the
   relationships is probably more sensible. This would allow the 
   background relationship builder to easily do it's work by merely
   being provided the object and fields which changed. Currently
   the wintermute relationship builder can add new relationships but
   it dosn't have enough information to break old relationships.

 - building everything on the same object storage machinery has some
   really nice consequences. The Wintermute code which maps objects
   and object relations to Swing TableModel and TreeModel interfaces
   was only implemented once, however it is used underneath
   everything. Changing object data anywhere in the UI will instantly
   update any visible occurances of information based on that related
   data.

 - Even though synchronization is important. Too many compromises are
   made when presenting data in it's "natural" foreign format. For
   example, synchronizing with an IMAP server and displaying all the
   IMAP folders is easy, but it forces the UI in a direction of being
   just like old stuff.

 - It's good if objects know their types. I've read interesting
   discussion about whether or not objects should have only one type,
   or have many types based on how they are used. I'm wavering back
   and forth on this. So far wintermute objects have only one type,
   and if you want an email to turn into a repeating calendar event,
   you create a separate repeating calendar event object and just link
   it to the email. However, it seems easier if objects know their own
   types.

 - a strong distinction between raw "external-data" and the places
   where that data is integrated locally simplifies many
   things. Synchronizing with external datasources in wintermute is
   really easy, because we represent all the external data inside
   wintermute in its natural format. In a way, we've divided the
   synchronization process into two steps (a) replication, and (b)
   correlation.

 - checkpointing and transactions make a very powerful combination for
   saving lots of data changes quickly. Wintermute makes tons of changes to
   little objects all the time, yet even when it's synchronizing, the
   checkpoint process is relatively quick. 

 - supporting two "fancy clients" which are synchronized when the
   server is not "fancy" is really hard. (i.e. two Wintermute clients
   with an IMAP server for email) 

 - Java Swing's APIs are nice, but their layout model is wrong for 
   apps like Wintermute. Everything got easier when I started writing
   my own simple layout managers.

 - No matter what anyone tells you, sweeping GC causes random pauses
   which are annoying. Python's reference counting should be better,
   because deref collection pauses will occur during an action in a
   predictable manner.

 - Java Swing is still slow, and Java is a CPU/memory hog.

Hope some of that helps.

-- 
David Jeske (N9LCA) + http://www.chat.net/~jeske/ + jeske@chat.net