zach pinter - caching and synchronization with flex
DESCRIPTION
In this talk, I'll show how to combine weak references, hashes, binding and item renderers to produce an elegant solution to the problem of keeping objects synchronized and reducing calls to the server.Outline: * The WeakReference class o Allows cached objects to be garbage collected o Briefly explain difference between hard references and soft references * The EntityWrapper class o Gives item renderers an object that they can immediately bind to while potentially waiting for the server to respond * The EntityCache o Central location for all VO objects currently referenced by the application o Used to coordinate updates to client-side data + Recursively scan an incoming object for VO objects that can be used to fill/update the cache + Looks at all properties, properties of properties, etc o When querying for a specific object by its id, first check the cache + A cache hit returns the object + A cache miss queues a call to the server + All cache misses in a given frame are grouped together to reduce server load o Deals with duplicate objects + If an entity is already represented by an object in the cache, update the existing object's properties and discard the new object + Use the cache to make sure there's only ever one authoritative object instance # Everything binds to the authoritative instance # When that instance gets updated, so does the rest of the application * Taking advantage of the behavior of item renderers inside lists o Only the visible rows are fetched, makes the app more responsive o (Optional) Talk about server-side datagrid sorting to make sure the client doesn't have to have all the data fetched locallyTRANSCRIPT
![Page 1: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/1.jpg)
Caching and Synchronization in Flex
1
Zachary PinterSenior DeveloperEffectiveUI360Flex
![Page 2: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/2.jpg)
The ProblemCommon application data shown in multiple views, being manipulated by multiple users at roughly the same time.
2
![Page 3: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/3.jpg)
GoalsFetch entities only once and only as needed.
One definitive instance of a server-side entity.
Update all relevant views when the server sends notice that an entity has changed.
Server-side agnostic.
3
![Page 4: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/4.jpg)
What’s the strategy?Store all fetched entities in a single cache (Dictionary).
Bind the views to the cache.
4
![Page 5: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/5.jpg)
What about memory use?
5
public class WeakReference{ private var dic:Dictionary; public function WeakReference(obj:*) { dic = new Dictionary(true); dic[obj] = 1; } public function getValue():* { for (var item:* in dic) { return item; } return null; }
}
Text
Allows cache values to be garbage-collected if they’re not being referenced anywhere else.
![Page 6: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/6.jpg)
The CacheHow do we add an entity to the cache?
6
public class EntityCache{ public function updateEntity(entity:BaseVO, ...):BaseVO { //... }}
![Page 7: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/7.jpg)
Recurse through properties
UserVO id: 1 firstname: “Zachary” lastname: “Pinter” address: AddressVO id: 2 line1: “4444 W 44th Ave” city: “Denver” state: “CO”
7
EntityCache 1: UserVO 2: AddressVO
Adding a user to the cache also adds its address.
![Page 8: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/8.jpg)
Recurse through properties
UserVO id: 1 firstname: “Zachary” lastname: “Pinter” addresses: [ AddressVO id: 2 label: “home” line1: “4444 W 44th Ave” city: “Denver” state: “CO” AddressVO id: 3 label: “work” line1: “5555 W 55th Ave” city: “Denver” state: “CO”]
8
EntityCache 1: UserVO 2: AddressVO 3: AddressVO
Arrays behave the same way
![Page 9: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/9.jpg)
Finding an object’s propertiesSpring Actionscript (formally Prana)
http://www.pranaframework.org/
9
var type:Type = Type.forName(classname); for each (var accessor:Accessor in type.accessors) { if (accessor.isStatic == false && accessor.access.name == "readwrite") { result.push(accessor.name); }}return result;
![Page 10: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/10.jpg)
Finding an object’s propertiesSource generator
10
public class UserVO extends BaseVO { public var username : String; public var firstname : String; public var lastname : String; public var address : AddressVO;
override public function getProperties():Array { return super.getProperties().concat("username","firstname","lastname","address"); }}
![Page 11: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/11.jpg)
Updating the cacheWhat if the entity is already in the cache?
11
EntityCache 1: UserVO(instance A) id: 1 firstname: “Robert” lastname: “Smith”
EntityCache.updateEntity( UserVO(instance B) id: 1 firstname: “Bob” lastname: “Smith” )
EntityCache 1: UserVO(instance A) id: 1 firstname: “Bob” lastname: “Smith”
Copy the properties from instance B into instance A
Leave instance A in the cache
Discard instance B
![Page 12: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/12.jpg)
Updating the cacheWhat about arrays?
12
EntityCache UserVO id: 1 firstname: “Zachary” lastname: “Pinter” addresses: [ AddressVO(instance A) id: 2 label: “home” line1: “4444 W 44th Ave” city: “Denver” state: “CO” AddressVO id: 3 label: “work” line1: “5555 W 55th Ave” city: “Denver” state: “CO”]
EntityCache.updateEntity( AddressVO(instance B) id: 2 label: “home” line1: “3333 W 33rd Ave” city: “Denver” state: “CO” )
![Page 13: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/13.jpg)
Updating the cacheWhat about arrays?
13
UserVO id: 1 firstname: “Zachary” lastname: “Pinter” addresses: [ AddressVO(instance A) id: 2 label: “home” line1: “3333 W 33rd Ave” city: “Denver” state: “CO” AddressVO id: 3 label: “work” line1: “5555 W 55th Ave” city: “Denver” state: “CO”]
Since we update the existing instance, all references to it will see the update.
![Page 14: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/14.jpg)
Updating the CacheThe flip side
14
UserVO id: 5 firstname: “Zachary” lastname: “Pinter” addresses: [ AddressVO(instance B) id: 2 label: “home” line1: “6666 W 66th Ave” city: “Denver” state: “CO” AddressVO id: 3 label: “work” line1: “5555 W 55th Ave” city: “Denver” state: “CO”]
EntityCache AddressVO(instance A) id: 2 label: “home” line1: “5555 W 55th Ave” city: “Denver” state: “CO”
Your cache already has an AddressVO with id 2 in it, and you add a new UserVO to the cache that references an updated instance of the AddressVO
![Page 15: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/15.jpg)
Updating the Cache
15
UserVO id: 5 firstname: “Zachary” lastname: “Pinter” addresses: [ AddressVO(instance A) id: 2 label: “home” line1: “6666 W 66th Ave” city: “Denver” state: “CO” AddressVO id: 3 label: “work” line1: “5555 W 55th Ave” city: “Denver” state: “CO”]
EntityCache AddressVO(instance A) id: 2 label: “home” line1: “6666 W 66th Ave” city: “Denver” state: “CO”
The AddressVO in the cache is updated and the AddressVO in UserVO.addresses is replaced with the instance from the cache.
![Page 16: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/16.jpg)
Updating the Cache
16
if (obj is Array) { var arr:Array = obj as Array; for (var i:int=0;i<arr.length;i++) { if (arr[i] is BaseVO) { var res:BaseVO = updateEntity(arr[i] as BaseVO,...); if (res != null) arr[i] = res; } }}
Code looks something like this...
![Page 17: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/17.jpg)
Updating the Cache
17
if (obj is ArrayCollection) { var ac:ArrayCollection = obj as ArrayCollection; ac.disableAutoUpdate(); for (i=0;i<ac.length;i++) { if (ac.getItemAt(i) is BaseVO) { var res:BaseVO = updateEntity(ac.getItemAt(i) as BaseVO,...); if (res != null) { ac.setItemAt(res,i); } } } ac.enableAutoUpdate();}
ArrayCollection’s are slightly trickier
![Page 18: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/18.jpg)
18
Now that we’ve added an entity to the cache...
![Page 19: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/19.jpg)
The CacheHow do we get an entity?
What happens if we ask for an entity that isn’t in the cache?
19
public class EntityCache{
public function getEntity(id:String):EntityWrapper { //... } }
![Page 20: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/20.jpg)
EntityWrapperWhen requesting an entity, a wrapper object is returned.
If that object is in the cache, EntityWrapper.entity will have a value.
If the object is not in the cache, EntityWrapper.entity will be null and a call to fetch the entity will be queued.
20
[Bindable]public class EntityWrapper{ public var entityId:String; public var entity:BaseVO; public function EntityWrapper(id:String) { entityId = id; } }
![Page 21: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/21.jpg)
Using the Cache
21
<mx:Label text="Username: {userWrapper.entity.username}"/>
userWrapper = cache.getEntity(userid.text);
![Page 22: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/22.jpg)
Using the Cache - List RenderersBenefits‣ Faster initial query since you’re only grabbing the id’s‣ Rows are lazy-fetched as you scroll
Drawbacks‣ Sorting has to be handled by the server
22
![Page 23: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/23.jpg)
Using the Cache - List RenderersWhat’s the code for the item renderer look like?
23
override public function set data(val:Object):void { if(val != data){ if (!val) { wrapper = null; } else { wrapper = cache.getEntity(val); } super.data = val; }}
![Page 24: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/24.jpg)
Serverside ConsiderationsWhat does this require of your backend infrastructure?‣ Globally unique keys (or a way to fake it)‣ Ability to get an entity by its key‣ Ability to query for entities and only return their keys (used by lazy lists)
Perks:‣ Versioned entities‣ Get multiple entities in a single call by passing multiple keys
24
![Page 25: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/25.jpg)
Dictionary KeysOnly one cache, need to prevent collisions
Some Options:‣ Globally unique sequence across all tables (UserVO with id 1, AddressVO with id 2)‣ UUID’s (great for generating new id’s flex-side)‣ Combine type with id (“UserVO-1”, “AddressVO-1”)
25
![Page 26: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/26.jpg)
26
Demo
![Page 27: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/27.jpg)
27
Questions?
![Page 28: Zach Pinter - Caching and Synchronization with Flex](https://reader037.vdocuments.us/reader037/viewer/2022102922/54b48b2f4a7959da6c8b4629/html5/thumbnails/28.jpg)
Thanks!Zachary Pinter
http://github.com/zpinter/cache-synchttp://slideshare.net/zpinterhttp://zacharypinter.comhttp://effectiveui.com
Twitter: zpinter
28