Posted on

More thoughts on caching in Flex

As I discussed previously, caching can have it’s advantages.  It makes referencing objects and binding much more straight forward.  Unfortunately, it comes at a performance cost.  Since I’ve been using caching, there are some important things to keep in mind when you use caching to make sure your data sticks around and your performance doesn’t suffer any more than it has to.

If your data coming from the backend is always the same structure and all the properties of your value objects are populated, the following gotchas probably won’t apply.  For me, I’m working with some complex objects that can have a lot of data associated with it.  Because of that, the objects returned from the server can have different amounts of data populated.

Let’s say you’re working with Contacts again.  If your contact table had the following fields that matched to basic properties of your value object, you’d be fine.

contactId, firstName, lastName, phone, email, street1, street2, city, state, zip

But what if your object was a little more complex, like this:

contactId:int
firstName:String
lastName:String
phone:String
email:String
address:Address
notes:ArrayCollection of potentially long Strings
purchases:ArrayCollection of Purchase
referrals:ArrayCollection of Contact

Now, the API for the database might need to have more than a simple getContacts call.  Maybe you need a getSimpleContacts that just populates the id, name, and contact info.  This would be useful for getting the list of your contacts to put in a list.  Then when you select a contact, you could make a getFullContact call so that potentially large sets of data don’t have to be sent if they might not be needed.

If this were the case, you’d make the initial getSimpleContacts call to populate your list.  That would sync the objects to your data cache, with null values for the properties that are ArrayCollections.  Then as you select items, those null values would get overwritten with the real data in the cache.  Here’s the updateProperties method in the cache I’ve been using:

private function updateProperties(itemA:Object, itemB:Object):void
{	
     for each (var property:Property in info.getProperties())
     {
          if (property.readable && property.writable)
          {
               property.setValue(itemA, property.getValue(itemB));
          }
     }
}

It simply copies the new data from the new object (itemB) to the cached object (itemA).  That seems simple and elegant.

If you have the multiple APIs I talked about earlier, this can pose a problem.  Let’s say you open the application, getSimpleContacts is called to populate the basic list, you select a couple which shows all the contacts information so you use the getFullContact API.  The Contact object comes back with all the fields populated.  You sync the contact object using the cache and all the values are copied over to the cached object.  This is good because now, the object in the cache is fully populated so wherever you use it in your application, you’ve already got all the data.  Maybe in the time since you called getSimpleContacts and getFullContact, the phone number was updated, so that is updated in the cached contact as well.

Now, you go back to your list and to be sure you get any contacts that have been added since you last looked at the list, you make the getSimpleContacts call again.  The contacts come back and you sync each one with the cache so any updates will be reflected in the cached contacts.

Do you see a problem with the updateProperties method in this case?  The simple contact objects will still have all the property definitions, but since the API only returns the basic stuff, the new object will have null values for notes, purchases and referrals.  The updateProperties method will copy those null values over, clearing those populated values you had.

As long as the API will never return null values for properties the API provides, you could add a check to the if statement that only does the copy if the new value is not null:

if (property.readable && property.writable && property.getValue(itemB) != null)
{
     property.setValue(itemA, property.getValue(itemB));
}

If the data your server provides has a dateModified field that gets updated whenever any property of the object changes, you could make a custom cache for that dataType that compares the dateModified values of the old and new data.  If the dateModified is the same, you can skip copying over the basic data, since all APIs retrieve that in our example, and just copy the last three properties that might be null.  You could check for nulls as well to further reduce the work involved.  Skipping all that data copying if you know it wasn’t modified might seem trivial for one object but imagine if you retrieved 1000 contacts and synced them all with the cache.  Skipping the copying for the majority of your data would vastly improve the time it takes to process all those objects.

If you’re working on an enterprise application like I am, you’ll most likely appreciate the performance improvement and the caching mechanism I’ve described.  When you’re working with really big data sets, every little bit of processing time saved on each item can translate to noticeable improvements in the performance of your application.  Mobile applications also benefit from any performance improvement you can give it.

Do you have other ideas on caching or performance improvements when dealing with large amounts of data?  I’d love to hear them in the comments.

Leave a Reply

Your email address will not be published. Required fields are marked *