Posts Tagged “data management”

Hi Everyone,

This is not exactly a “Soma release”, but I would like to share with you my last work so we can talk about: A new AS3 MVC Framework with its own design philosophy.

Why another AS3 MVC Framework?

I’ve been working with different Frameworks in the last years, such as PureMVC, Cairngorm and Mate for the well-known. I’ve always knew that I would write my own “MVC design philosophy”, without taking big words, because I would have some needs that existing Frameworks wouldn’t completely fill.

That’s what happened. I needed a Flash lightweight framework, not DI, event based, working both for Flex or Pure AS3. The biggest inspirations have been PureMVC for the proxies and mediators, and Mate for their event system.

I’ll be starting an interesting AIR Modular app and I needed something that will easily allow me to have views and models free of Framework code, without creating tons of files or use any injection. I also wanted a Framework very flexible, so I can use it even for smaller project, being sure I’ll be effective in terms of development time.

Free the views and models

First problem, free the views and models of Framework code (loose-coupling). It seems there’s a wave of DI Framework but… I’ve never really been into DI Framework, because they tend to control the way you’re doing things. If you stick to it, it is fine, but I’ve always felt more freedom with framework like PureMVC. I might be wrong, it is just an opinion and not even entirely true as I didn’t felt that problem with Mate.

So, to solve this problem, I used the events Mate concept. A basic Flash Events that has a bubble property set to true can become Commands when they are mapped to a Command class. Those events can be intercepted, stopped and processed by the Framework (execute Commands). The great thing is, views and models are free of Framework code and can use Commands because they are just Flash native events.

Wires introduction

Second problem, was to “update” data or states in the views and models. PureMVC is using proxies and mediators and I like that approach. However, you end up by creating tons of files for the sake of loose-coupling pratice. So I’ve created something that I call “Wire”. Now software engineers or PureMVC adept might say that what I’m doing is wrong. I have no idea, I’m no computer scientist, I do what I feel and I’m sharing it with you.

Wire are classes that can contain Framework code and they will be the links between the models, the views, the Framework and… whatever you like. Wire can be proxies, they can be mediators, but they can also be both and handle more than one view or model.

Basically, they are as free as you want them to be. They can even be optional if you don’t care about good practice or loose-coupling programming. Wires have easy access to all the framework, models, commands and views. They can register create models, views, register commands or create other wires.

Update from comment:

So far I saw two ways to inject/update information into views without having framework code inside:

- Dependency Injection
- Buffer classes (such as Mediators and Proxies in PureMVC for the analogy, respectively for Views and Models). I mean “buffer” by classes that act as steward of other classes.

I’ve chosen the second way, and I’ve created a “buffer” class that I called a Wire.

Wires are completely free classes. I won’t tell you how to use them (because that’s up to you) but I can tell what you can do with them. Wires can be used to update views and models but they are not tight to anything. They are not even only tight to one tier. To create a wire class you extend Wire and implements IWire, and here are the roles they can take:

- a wire can act as steward of a view (such as Mediator in PureMVC)
- a wire can act as steward of a model (such as Proxies in PureMVC)
- a wire can manage both a view and a model
- a wire can manage multiple views and/or multiple models
- a wire can be considered as a subdivision of the framework and create its own views, create its own models and register its own commands. Much like you would create a specific package to hold a specific matter.

When I build something, I always try to keep a good level of freedom to handle problems how I like but most importantly, how they should be. If you like to have the framework telling you (or forcing you) how to build your application, fair enough but you won’t like it.

The wires are the free elements that will let you built your application the way you like or the way it is required to be. They can make your application rigid, segmented, flexible or centralized, depending of the role you are going to give them. They are so free that I believe remove (or lesser) what I call “Framework Fight”.

Let’s take an example, the Cafe TownSend below.

There are 2 wires: the LoginWire and the Employee Wire. They both register their own commands to control their views and models.

The Login Wire only handles a Login View.

The EmployeeWire handles 2 views: a list of employees and an employee details. But also 1 model (the employees data), all of them only related to employees matter.

SomaCore

I temporarily named this framework SomaCore and it has nothing to do with the Framework I released on this blog (Soma). However, this framework might become the core of what will be Soma v3.

I post this code hoping to get your feedback or point of view of what might be great or wrong in this framework.

Here is a diagram:

SomaCore MVC Diagram


Click here to download a zip file containing the Framework sources code (classes and SWC).

And here are some demos. I made a Flex Cafe TownSend demo and a pure AS3 demo.

SomaCore Flex Cafe TownSend SomaCore Flash AS3 Demo
View Demo
View Source
Download Source
View Demo
View Source
Download Source

This is a very early state, this Framework has not been used yet in a real project beside the demos above. Have a look and please comment what you feel is good or wrong in the core concept.

Romu

Vote in HexoSearch

Comments 11 Comments »

This is not Flash related but I had to post something about as I’m really annoyed. I’m now working all the time on Mac, I believe I couldn’t bear anymore spywares and other Windows annoyances.

Anyway, I’m almost fine on the Mac but there’s one thing I can’t understand is that they didn’t implement a “merge folders” capability when you copy and paste something. On a Mac, if you copy a source folder containing folder and files to paste it to a target folder, if you choose replace, the content of the folders will disappear and be replaced by the source. meaning if you have files on the folder target that doesn’t exist in the source folder, they will just disappear. On Windows, it asks you if you want to overwrite or not because anyway, it is always going to merge.

I could use the Unix command ditto and the terminal, but wow, how is it possible something as simple as that is not implemented? People from windows will know what I’m talking about. Actually, there’s a lot people complaining and tons of app that does the job.

So I tried to find a simple and quick app, which actually wasn’t really easy as they all want to merge the content of the files. I don’t want to do that at all, that’s more a code matter to merge the content of a file. I found 2 or 3 that does the job but kind of heavy for such a common task, I want to do that as quickly as I could do on windows.

The best I found is: Merge Folders

You select the source, the target, if you want to overwrite and that’s it. Perfect? Almost…

My problem was mostly related to SVN, copy file from local copy to other local copy, or whatever. This app would have been perfect if I could choose “include hidden files, yes or not”.

So I need first to export a package not to have the hidden folders .svn and then merge my exported copy to a repo or local copy. That’s ok but again, on a Mac, things are not that easy when it comes to development, maybe I passed too much time on Windows? I’m sorry but Windows and tortoiseSVN is kind of wonderful compare to a what I get on the Mac. So as I can’t make an export with the “SVN-finder-integrated” (scplugin), I use mostly SynchroSVN, great but still a lot slower than on Windows. When you have some delicate actions to make like merging branches, tortoiseSVN on Windows is really great.

I’m sure some of you have the same problem, what are you solutions? What do you use? Is there something simple and quick that I missed?

Romu

Vote in HexoSearch

Comments No Comments »

I made some experiments on how to easily access to data in a Flash site. It is probably a mix with good and bad ways but I think it is worth having a look.

What I’ve done here is get data with syntax that is similar to what you get using E4X in AS3. For example with XML and E4X you can use syntax like that:

xml..item[2].author.name.text();

I’m not saying that this experiment is a good practice but I want to show you what you can do by extending the Array class and extending the Proxy class in AS3. The Proxy class is the replacement of the __resolve we were using in AS2.

Let’s say we have a website that will load data from a database at the start, for example using AMFPHP or whatever, and we are going to fill this data at run-time.

In my example I have a kind of tree with countries > cities > people.

I would like to be able to loop easily through the data, as well as getting them with a friendly/readable syntax if needed.

In my example, I have a Singleton class that contains all the data. I don’t load the data in my example, I statically fill the class. I will access to the data like that:

Content.data

This will return me a array of data, which will contains an array of countries, each instance of the country array will contains an array of cities, which will contains an array of people, etc…

So I’d like to access to my data like this:

To browse the countries:
Content.data[0]
Content.data[1]

To browse the cities in the countries:
Content.data[0][0]
Content.data[0][1]

To browse the people in the cities:
Content.data[0][0][0]
Content.data[0][0][1]

That’s nice to loop through with a “for each” or whatever. An Array is a pretty nice tool to store data as you get some functions to manage it like push, splice, reverse, etc.

But these arrays have a problem, what if I need to get more info on my countries, like the weather, an ID or the surface of the country? I would like access to more data like that:

Content.data[0].name
Content.data[0].id

This is possible with an Array as it is one of the few classes in AS3 that are dynamic. It means you can set any property at run time. For example MovieClip is dynamic and Sprite is not, try to add properties at run-time on these classes to see the result. Some people are saying that is it a good and bad things. It is easy to use but you don’t know what kind of properties will be added in your Array at run-time.

So you don’t want that, and better, you want to control what kind of data they are going to put in your Array. We will get that by extending the Array class.

There’s a nice explanation here to extends an Array, as well as control the data type your custom Array class will accept.

So far it is not bad, we can easily access to our data, we can have properties on these arrays and finally we know that we will have the right type of content inside.

The other thing I want is access to my data with a nice E4X-like:

Content.data.France.name
Content.data.France.Paris.name

Easy, we just need a property France on this array and it is done. Well, the thing is we don’t know yet what this array will be filled with, so we are talking about dynamic properties. These dynamic properties will have to be added to the array when we create it because we said we want to control and we don’t want people adding their own properties.

How do we do that?

We’re going to use the Proxy class that make able us able to handle dynamic properties and dynamic calling.

We will have a class that will be an array (what you get when you call Content.data), a class for the countries, a class for the cities and a class for the people. The people class won’t be an array.

So we have the classes DataArray, CountryArray and CityArray that are extending the Array class. We will also have a Proxy class (a class that is extending the Proxy one) for each of the Array. I choose to a Proxy class for each Array class as it is easier to understand.

Let’s see a bit of code.

The Singleton Content class

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.    
  16.     public class Content {
  17.        
  18.         //------------------------------------
  19.         // private properties
  20.         //------------------------------------
  21.        
  22.         private static var content:Content = new Content();
  23.         private static var _data:Data;
  24.        
  25.         //------------------------------------
  26.         // public properties
  27.         //------------------------------------
  28.        
  29.        
  30.        
  31.         //------------------------------------
  32.         // constructor
  33.         //------------------------------------
  34.        
  35.         public function Content() {
  36.             if (content) throw new Error("Content is Singleton and can only be accessed through Content.data");
  37.             if (_data == null) buildData();
  38.         }
  39.        
  40.         //
  41.         // PRIVATE, INTERNAL
  42.         //________________________________________________________________________________________________
  43.        
  44.         private function buildData():void {
  45.             _data = new Data();
  46.            
  47.         }
  48.        
  49.         //
  50.         // PUBLIC
  51.         //________________________________________________________________________________________________
  52.        
  53.         public static function get data():Data {
  54.             return _data;
  55.         }
  56.        
  57.     }
  58.    
  59. }

The Data and DataArray class

The DataArray is extending the Array class. To be able to extend the Array class you need the dynamic keyword before the class.

dynamic public class DataArray extends Array {

We have a private property type Class used to control the Data we will push in our extended Array.

private var dataType:Class;

To control the type pushed we have to overwrite 4 functions: push, concat, splice and unshift, as it is nicely explained in the AS3 documentation.

Here is the code:

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.    
  16.     dynamic public class DataArray extends Array {
  17.        
  18.         //------------------------------------
  19.         // private properties
  20.         //------------------------------------
  21.        
  22.         private var dataType:Class;
  23.  
  24.         //------------------------------------
  25.         // public properties
  26.         //------------------------------------
  27.                
  28.         //------------------------------------
  29.         // constructor
  30.         //------------------------------------
  31.        
  32.         public function DataArray(...args) {
  33.             dataType = Country;
  34.             for (var i:int=0; i<args.length; i++) this.push(args[i]);
  35.             length = length;
  36.         }
  37.        
  38.         //
  39.         // PRIVATE, INTERNAL
  40.         //________________________________________________________________________________________________
  41.        
  42.         //
  43.         // PUBLIC
  44.         //________________________________________________________________________________________________
  45.        
  46.         AS3 override function push(...args):uint {
  47.             for (var i:* in args) {
  48.                 if (!(args[i] is dataType)) {
  49.                     trace("Error: you must push an Object type Country");
  50.                     args.splice(i,1);
  51.                 }
  52.             }
  53.             return super.push.apply(this, args);
  54.         }
  55.         
  56.         AS3 override function concat(...args):Array {
  57.             var passArgs:DataArray = new DataArray();
  58.             for (var i:* in args) passArgs.push(args[i]);
  59.             return super.concat.apply(this, passArgs);
  60.         }
  61.        
  62.         AS3 override function splice(...args):* {
  63.             if (args.length> 2) {
  64.                 for (var i:int=2; i<args.length; i++) {
  65.                     if (!(args[i] is dataType)) args.splice(i,1);
  66.                 }
  67.             }
  68.             return super.splice.apply(this, args);
  69.         }
  70.         
  71.         AS3 override function unshift(...args):uint {
  72.             for (var i:* in args) {
  73.                 if (!(args[i] is dataType)) args.splice(i,1);
  74.             }
  75.             return super.unshift.apply(this, args);
  76.         }
  77.        
  78.     }
  79.    
  80. }

To create a new DataArray instance, we actually don’t use the DataArray class directly but his Proxy, that will handle the dynamic properties.

I named the class Data, it is what you get with Content.data.

To extend the Proxy class you need to import the class itself and its namespace:

import flash.utils.Proxy;
import flash.utils.flash_proxy;

Proxy is also a dynamic class:

dynamic public class Data extends Proxy {

We have our private var that will be our DataArray instance:

private var _item:DataArray;

To control the properties and method called through our Proxy, we need to override 3 methods (with the namespace flash_proxy):

override flash_proxy function callProperty(methodName:*, ... args):* {
override flash_proxy function getProperty(name:*):* {
override flash_proxy function setProperty(name:*, value:*):void {

When you will call an unknown method, the Proxy class invoke callProperty, and when you will call or set a property (like Content.data.France), the Proxy class invoke getProperty and setProperty.

In my example I trace an Error if you try to set your own property, this is our control. When you get a property, I loop through the DataArray instance to see if I’ve got an item with that name. We could do it with the id or any property of your choice (that is in the DataArray class), and if yes I return it. This is the instance you get by using Content.data.France.

So in brief, when I call Content.data.France, I’m going through the Proxy that is basically managing the dynamic properties added at run-time. The DataArray class is extending the Array class to control the properties and data type.

Here is the code of the Data class:

Actionscript:
  1. package com.soundstep.data {
  2.  
  3.     /**
  4.      * <b>Author:</b> Romuald Quantin - <a href="http://www.soundstep.com/" target="_blank">www.soundstep.com</a><br />
  5.      * <b>Class version:</b> 1.0<br />
  6.      * <b>Actionscript version:</b> 3.0<br />
  7.      * <b>Copyright:</b> Free to use and change (except to include in a framework), an notification email will be welcome for a commercial use (just for information).<br />
  8.      * <b>Date:</b> 05-2008<br />
  9.      * <b>Usage:</b> Manage a Section
  10.      * @example
  11.      * <listing version="3.0">
  12.        
  13.      * </listing>
  14.      */
  15.  
  16.     import flash.utils.Proxy;
  17.     import flash.utils.flash_proxy;
  18.    
  19.     dynamic public class Data extends Proxy {
  20.        
  21.         //------------------------------------
  22.         // private properties
  23.         //------------------------------------
  24.        
  25.         private var _item:DataArray;
  26.        
  27.         //------------------------------------
  28.         // public properties
  29.         //------------------------------------
  30.                
  31.         //------------------------------------
  32.         // constructor
  33.         //------------------------------------
  34.        
  35.         public function Data(...args) {
  36.             _item = new DataArray();
  37.             for (var i:int=0; i<args.length; i++) _item.push(args[i]);
  38.         }
  39.        
  40.         //
  41.         // PRIVATE, INTERNAL
  42.         //________________________________________________________________________________________________
  43.        
  44.         private function getString():String {
  45.             var s:String = "";
  46.             for (var i:uint=0; i<_item.length; i++) {
  47.                 s += "index:" + i + ", id:" + _item[i].id + ", name:" + _item[i].name;
  48.                 if (i <_item.length-1) s += "\n";
  49.             }
  50.             if (_item.length == 0) return _item.name + " is empty";
  51.             else return s;
  52.         }
  53.        
  54.         //
  55.         // PUBLIC
  56.         //________________________________________________________________________________________________
  57.        
  58.         override flash_proxy function callProperty(methodName:*, ... args):* {
  59.             var res:*;
  60.             switch (methodName.toString()) {
  61.                 case 'clear':
  62.                     _item = new DataArray();
  63.                     break;
  64.                 case 'list':
  65.                     trace(getString());
  66.                     break;
  67.                 default:
  68.                     res = _item[methodName].apply(_item, args);
  69.                     break;
  70.             }
  71.             return res;
  72.         }
  73.  
  74.         override flash_proxy function getProperty(name:*):* {
  75.             for each (var i:* in _item) {
  76.                 if (name == i.name) {
  77.                     return i;
  78.                     break;
  79.                 }
  80.             }
  81.             return _item[name];
  82.             throw new Error("ERROR: Property " + name + " not found!");
  83.         }
  84.  
  85.         override flash_proxy function setProperty(name:*, value:*):void {
  86.             trace("ERROR: You can't set your own property!");
  87.         }
  88.        
  89.         public function toString():String {
  90.             return getString();
  91.         }
  92.     }
  93. }

Basically the cities and countries classes are doing the same, the dataType and properties are different, a country is asking a City type and the a city is asking a People type.

For example the CountryArray class asks an id and name to create the array, you have to use a syntax like:

var france:Country = new Country(0, "France");

As it is an Array extended you can still pass more arguments (but they have to be the right type), the type here is City, that is also an Array extended but a city instance is asking an id, a name and weather as parameters:

var france:Country = new Country(0, "France", new City(0, "Paris", "As bad as London!"), new City(1, "Marseille", "More sun than Paris"));

Here is how I fill the Content with some examples:

Actionscript:
  1. //country
  2. var france:Country = new Country(0, "France");
  3. Content.data.push(france);
  4. var uk:Country = new Country(1, "UK");
  5. Content.data.push(uk);
  6.  
  7. // city
  8. var paris:City = new City(0, "Paris", "As bad as London!");
  9. france.push(paris);
  10. france.myvar = "qwe";
  11. var marseille:City = new City(1, "Marseille", "More sun than Paris");
  12. france.push(marseille);
  13. var london:City = new City(0, "London", "Quite bad!");
  14. uk.push(london);
  15. var liverpool:City = new City(1, "Liverpool", "Even worst than London");
  16. uk.push(liverpool);
  17.  
  18. // people
  19. var franck:People = new People(0, "Franck", "Dupont", 29);
  20. paris.push(franck);
  21. var stephane:People = new People(1, "Stephane", "Durand", 42);
  22. paris.push(stephane);
  23. var john:People = new People(0, "John", "Doe", 35);
  24. london.push(john);
  25. var david:People = new People(0, "David", "Doe", 37);
  26. london.push(david);

And finally here is some example to access to your data:

Actionscript:
  1. Content.data.length
  2. Content.data.France.length
  3. Content.data[0].name
  4. Content.data.France.name
  5. Content.data.France[0].name
  6. Content.data.France.Paris.name
  7. Content.data.France.Paris.Franck.name
  8. Content.data[0][0][0].name

I didn’t optimize/clean the classes and as I said, I’m not saying that it is a good way of accessing data in Flash, but it shows you how to control data type, how to extend an Array, how to extend the Proxy class and how to handle properties and methods of a class at low-level.

Download the source.

Vote in HexoSearch

Comments No Comments »