09.04.2008 / The Why, What, and Where of Custom AMF Class Adapters

If you’ve read my article on Action Message Format (AMF) you’ll already know that AMF is a super-duper way to transfer data between a Flex/Flash/AIR application and its server-side counterpart.  Essentially when the client application makes a call to a service, the server can return a Java (or PHP, Python, .NET) object and when it gets back to the Flex application, wallah, its converted into an identical object in ActionScript.  Similarly, if the client application sends an ActionScript object to the server during a service call, it arrives as an identical Java object.

While that’s impressive, when it comes to implementation in a medium-to-high complexity system there are questions that still need to be answered.   In this article, I’d like to address where to translate custom AMF classes.

The Why

When server-side code accesses data from a database, it generally converts the data in the recordset into data objects (sometimes called beans, business objects, or one of many other names.)  These are basic objects that often, though not always, represent the shema of the database.  In other words, if there’s a table named customer in the database, there will likely be a class named customer as well.  One customer object instance represents one customer record in the database.  With frameworks like Rails, Cake, and Django, this is almost always true.

If a Flex application is requesting all customers, the process of retrieving the data is fairly simple: Flex makes a call to the service, the service retrieves all customer records from the database, the service converts each customer record into an customer object, and finally the service returns the array of customer objects back to the Flex application.

In order for the previous example to function correctly, an ActionScript customer class must exist on the Flex client as well as an identical Java customer class on the server.  Considering the most common case, these two classes will have properties that match the fields in the customer table.  In other words, both of these classes as well as the customer table will have properties such as firstName, lastName, phoneNumber, address, zipcode, etc.  With that in mind, what happens when a developer begins to refactor the application and chooses to rename the phoneNumber database field to homePhone?  The phoneNumber property in both the ActionScript customer class and the Java customer class will need to be renamed to homePhone.  This means there is high coupling among the database, the backend application, and the frontend application.  In other words, each part needs to know about the other two parts.  This breaks good programming principles because it results in more difficult maintenance.

This high coupling magnifies itself further if we wish to have the Flex application’s needs drive the design of the data objects.  Lets say we as Flex developers are creating a Flex application and know we want a salesperson’s first name, last name, sales code, and whether the salesperson is a system admin.  Now let’s say the database has already been designed and for whatever reason the salesperson’s firstName and lastName are in one table, the sales code is in a different table, and the system admin rights are in another.  Without some sort of conversion adapter, we will be shipping objects created from three different classes (Class A related to Table A, Class B related to Table B, and Class C related to Table C) from the server to the Flex frontend.  The following diagram illustrates the data flow.

Why does this high coupling present a problem?  Here are a few issues to think about:

(1) If the backend developer chooses to refactor the database table by combining Table A and Table B, the Java classes AND the ActionScript classes must also be refactored.  If we’re talking about production code, that means refactoring ActionScript code and redeploying the SWF.  In the case of an AIR app, the AIR application on each client computer must be upgraded.

(2) The Flex frontend probably does not, and to promote low coupling, should not, care about how the database was designed.  This is more an issue of principle, but if the frontend developer is mentally detached from the database schema, the frontend application’s modeling, logic, and architecture will in general likely also be decoupled from the database schema.

(3) Having three different ActionScript classes to get our salesperson information doesn’t necessarily make sense.  Maybe there was a reason to have the information in three different database tables, but the reasoning may not apply when it comes to the Flex frontend.  Having three different classes means more overhead and maintenance.

(4) Even simple differences such as coding style must be maintained across the database, backend code, and frontend code.  If the database fields were creating using underscores such as first_name, last_name, home_phone, etc., this style must be also be used in the backend code and the frontend code.  Considering most Flex developers use camelCase name styling (firstName, lastName, homePhone,) this coupling presents an inconsistency in style.

The What

So, how do we deal with these issues?  Generally the best solution is to create an adapter or layer that converts objects the backend uses to objects the frontend needs.  The backend and frontend agree on the classes that will be sent across the wire and those classes essentially become a contract–an agreement between the frontend and backend on what will be sent and received.  These classes should be designed without regard to database schema or the classes the backend uses within its own domain.  In our example, Flex needs objects of Class X which includes a salesperson’s first name, last name, sales code, and whether the salesperson is a system admin.  The backend is already using Class A, Class B, and Class C that contain these various properties.  The adapter would take objects of Class A, Class B, and Class C and combine the needed properties into an object of Class X.  Class X is essentially the contract–both the backend and frontend have agreed that Class X is what will be sent and received.

Not only does an adapter allow for the creation of objects that are slim-and-trim and customized for Flex’s needs, but of even greater importance is it provides a point of decoupling.  If the field in a database table gets renamed, the related property in the frontend class does not need to be renamed.  Instead, only the adapter needs modified so the new backend property name is mapped to the old frontend property name.  This adapter also provides for a place to convert programming style (first_name on the backend would be mapped to firstName on the frontend.)

The Where

Now that you (hopefully) understand what adapters are and why they’re helpful, the remaining question is where the adapter should be implemented.  Two possible locations are the most logical: (1) on the backend immediately before sending objects to the frontend or (2) on the frontend immediately after receiving objects from the backend.  The data flow process for each of these adapter locations is illustrated in the following diagrams.

Here are the benefits of each location as I see them:

On the backend immediately before sending objects to the frontend:

  • Database schema changes do not have any affect on frontend code (except for changes fundamental to application logic.)  This means when the database schema changes, the Flex/Flash/AIR application does not need to be recompiled and redeployed.  If the adapter were on the frontend, the adapter would need to be updated, resulting in the need to be recompiled and redeployed.
  • In a team environment, a backend developer can modify the database schema and commit changes to the backend classes and accompanying adapter almost simultaneously. Frontend development remains virtually uninterrupted.  If the adapter was on the frontend, the backend developer would make the change to the database schema and commit the changes to the backend classes.  The backend developer would then need to notify the frontend developer of the change.  The frontend developer would then modify the adapter and commit its change.   Throughout the duration between the backend developer’s commit and the frontend developer’s commit, the Flex application would not function correctly. Because the frontend is generally more concerned with the presentation of data rather than heavy analysis, data mining, integration with ecommerce, and other data-centric tasks, frontend developers will likely require less refactoring of data models than backend developers.  By having the adapter on the backend, less communication between developers will be required when refactoring.
  • Keeping adapter code out of the frontend results in a smaller SWF/AIR file size.
  • Conversion tasks carried out by the adapter require processing.  By keeping processing on the server, processing time is more predictable and manageable than if the processing were performed on the client.

On the frontend immediately after receiving objects from the backend:

  • The backend does not need to know how frontend data is modeled.  In other words, if a frontend developer would like to rename a property in the data model’s class or combine two classes, the backend does not need to be notified.  If the adapter were instead on the backend, the application would be broken during the duration between when the frontend developer commits the data model’s class change and the backend developer commits the backend class and adapter change.  However, like I mentioned previously, it’s been my experience that the frontend requires less data model refactoring than the backend.

As you may have concluded from the analysis, it’s fairly clear the best location for the adapter is on the backend just before sending objects to the frontend.  While having an adapter or at least some level of abstraction in the first place is certainly the most important concept, having an adapter in the right location can also help.

Do you disagree or have a perspective not addressed in my analysis?  Do you have questions regarding the why, what, and where of custom class adapters?  I invite you to join in on the conversation by responding below.

Tags: , , ,


Comments

09.05.2008 / Brian Allred said:

Very well written, Aaron. I agree completely. The first three benefits of putting the adapter on the back end are very powerful benefits.

It could be argued that if you’re not going to put the adapter on the back end then don’t bother doing an adapter at all–just deal with the raw data.

Really, the only valid reason for not creating an adapter and putting it on the back end is that the back-end developers might consider it to be a front end task to develop it, so the back end developers should not have to do it. If that’s their argument, then I think it’s reasonable to request help from the front-end developers in creating it.

09.17.2008 / Nate Ross said:

Nice article indeed. In my experience, the only time the back-end and front-end developers need to collaborate is when the front-end data model is initially created and on certain occasions when the front-end developer needs additional data from the back-end.

The benefits that I see are that if I am a front-end developer, I don’t need to know the database schema! I don’t need to concern myself with why my classes are coming to me in a certain way due to associative classes, one-to-many relationships, inheritance, etc. I can remain blissfully ignorant of the backend, and view it as a black box without having any understanding of databases, or backend coding conventions from Java or PHP. Instead, I can simply focus on Flex or another front-end technology. Due to the increasing specialization in our industry I think this is a huge benefit.

Thanks for the insights!

09.17.2008 / bryce said:

Oh yeah. Make the backend devs do all the work. I hate doing extra work.

09.17.2008 / John said:

A few thoughts:

(apologies in advance if your blog engine hates my HTML)

Seems like any significant database changes are probably going to require a recompile anyway. If you’re changing your data structure, it’s probably for a new feature or something that’s going to require a recompile anyway. If it really is insignificant, chances are you can wait to make it until the next release. For development this can be nice - I agree it’s easier to have it server side in that instance - but I don’t see this being a significant problem in a production setup.

The converse advantage of a small SWF and faster SWF is that when the adapter logic is front-side, the core server-side engine requires less weight as well. Sometimes it even strips off an entire layer. The advantage here is that when you’ve got thousands or tens of thousands using an application, sometimes a fat client is nice because you’re using user CPU time rather than an (already taxed) server CPU that you have to pay for. There may be situations where a server performance boost is more important than a client performance boost.

One other advantage to having client-side adapters in place is that the adaptation process makes more sense because it’s already sitting in context. When you’re typing or structuring data on the server side, classes (and their associated behaviors and attributes) have no meaning and can have confusing side effects due to server-side language constraints. When the adaption is happening client-side, those classes can be used better, and language-specific limitation (can’t have “delete” as a property name, etc.) make more contextual sense.
Generic data (adapted on the client-side for its own use) is more general purpose, and a single API method can serve multiple clients. If I expose a JSON or REST/XML API via the web, it’s easy for a wide array of client applications to consume. Large data houses realize this and it’s why you don’t see a Flickr AMF feed - it’s because *anyone* can use XML. There may be instances where other applications are using the same data, and building a parallel AMF layer doesn’t make sense once you’re already exposing that same data in a more general format (as far as typed data goes, at least).
Finally, I think any Flex framework should have some sort of services/adapter layer, just to make use of a wider array of services available on the web. Sure, an in-house built app can (and often should be) AMF typed server side, but a layer client side will come in handy when you’re integrating with SOAP/REST services from other vendors (Flickr, del.icio.us, etc.) or from a client doing their own services work in a non-AMF format. That way either side can adapt the data if it needs to.

09.17.2008 / Aaron Hardy said:

Hey, thanks everyone for your comments. Here are some of my thoughts on your thoughts:

@Nate
You’re definitely right; however, backend developers can say the same thing about having the adapter on the front-end. They can remain blissfully ignorant of what goes on on the frontend. So there’s a pro and con for each of the possible adapter locations.

@Bryce
You know it! Seriously though, as a frontender I wouldn’t be completely opposed to doing the adapter work myself as long as it meant it was in the right location. It may just mean allocating more backend resources rather than more front-end resources.

@John
Good comments. Some of them require more of a response….

You mentioned that having the adapter on the frontend sometimes strips off an entire layer on the backend. The opposite is true as well. When the adapter is on the backend, it sometimes strips off an entire layer from the frontend.

I agree that if you have thousands of users using an application it can be nice to use their resources instead of your own; however, when you’re trying to cater to the user, using more of their machine might not be the best option. If it’s an internal application your employees are using and you’d like to distribute the process load to their computers it’s probably more reasonable as you’re not necessarily trying to cater to them. Also, keep in mind the user’s CPU may be just as taxed as the server’s CPU…the only difference is we might not be able to purchase more equipment to fix the problem.

You mentioned that an adapter on the client side is already sitting in context. Actually, only half of it is in context: the frontend half. Just as a backend developer creating the adapter has no certain understanding of frontend models, a frontend developer creating the adapter has no certain understanding of the backend models. The same goes for language constraints. If the backend class has a property name supported in the backend language, it may not be supported in the frontend language.

You mentioned a single API can serve multiple clients. This is true, but it doesn’t decrease the number of adapters needed. If two flex applications want to use the same API and they need a different class structure than what they receive, they’re each going to have their own adapters. If the adapters were on the backend, there would likely still be two adapters. You do bring up a great case though of when an adapter should not be on the backend and I should have addressed it. In the case of Flickr, they can’t provide a specific implementation for each one. It’s too expensive and time consuming. What better way to keep costs low than to push them onto the entity building the client application. Instead of building services specific to each need, they resort to a more generic, less optimized API interface. I say less optimized because such APIs ship a lot of extra data back that you may not need (the Bugzilla and iTunes APIs come to mind). They have to send it though because somebody may need it. Similarly, the API sends data in XML not because it’s the most optimized solution but because they have to provide a format that dozens of client technologies will support. If they had a gabajillion dollars to burn and were concerned with the performance of client applications, I’d be willing to bet they would provide an optimized solution for everyone who requested it. They don’t though because development and maintenance costs money and they don’t have a gabajillion dollars to burn. So, if our main goal were to provide an API that supports the widest array of frontend implementations and we couldn’t build a custom service for each, it would be a bad idea to have the adapter on the backend just as it would be a bad idea to use AMF. Why don’t we all ditch AMF and lean classes and replace them with XML that includes every data property? Because in some (most?) cases one entity either (1) is paying for development/maintenance of both the backend and frontend(s) (therefore no costs are cut by creating the adapter on the frontend) or (2) developers won’t/can’t be available to develop a customized service for each frontend client that needs one (whether due to money, resources, time or otherwise). If neither of those cases are true, optimizing the service by creating the adapter on the backend is probably worthwhile. If this weren’t the case, niche technologies like AMF wouldn’t even exist. All services would provide XML loaded with every possibly usable property.

I agree with your last point that a layer comes in handy when integrating with services from various vendors. I just want to clarify that when I said an adapter layer should generally go on the backend, I did not mean it was okay to exclude some form of a service layer from the frontend. It’s not. I can see how that may have been interpreted though because adapter logic can be placed in the service layer rather than a layer of its own. To explain how they relate in such a case, in most service layer implementations, there are interfaces (the object-oriented kind) that specify methods like getUser(), getOrders(), and getCustomers(). These are only the required method signatures, not the logic. The developer then creates service-specific classes that implement those methods. For compatibility with the AMF service, the developer would create a service class that implements the interface by providing logic for each of the required methods. The logic in this class would be specific to AMF and may or may not include adapter logic (mapping a backend class to a frontend class). Then the developer would create an XML service class that likewise implements the interface by providing logic for each of the required methods. The logic in this second service class would be specific to XML and may or may not include adapter logic. The existence of adapter logic in the XML service class is in no way dependent on whether the AMF service class has adapter logic within it. With the service layer in place and the application calls a specific service (if we’re talking about the client) or responds to a specific request (if we’re talking about the server), the service configuration just points to the right service class and all the methods are implemented as expected. So, when you say that any Flex framework should have some sort of service/adapter layer, they generally do have a service layer if they’re in any way related to Cairngorm, PureMVC, or just have a competent developer. The frontend service layer is slightly different than the one I laid out though because its calls are asynchronous and therefore must also deal with result and fault handlers. Other than creating classes to support a new vendor’s service (which may or may not include adapter logic), only small adjustments are needed to ensure flexibility with both. In other words, having the adapter logic on the frontend doesn’t make the application more flexible with new service types, you have to make new service classes either way.

On a related note, almost all frontend and backend applications should have a service layer if they support service-related communication. ASP.NET’s starter kit The Beer House is a fantastic example of a flexible data access layer implementation where you can swap different kinds of databases and it’s seamless. Although it’s for databases, the implementation for a backend service layer would be very similar.

Thanks for joining the conversation! Keep it coming.

09.18.2008 / Ellis Elkins said:

Just like Aaron posted about how there isn’t one framework for all people and all projects, there isn’t one solution here. There are benefits for each of these implementations.

For Flickr or such places like them it is a good idea to have very general services to cater to many front ends.

I think something that hasn’t really been said directly is that most of the applications that we build here at mediaRAIN aren’t general services. The services that we most commonly design, i.e., for AncestryPress, are not for general use at all, so optimization for specific use is the best idea.

So we need to understand the benefits of each solution and analyze our project to see if we need to go more general or more specific.

09.18.2008 / Nate Ross said:

@Aaron - The reason why it is important for the Flex front-end to remain blissfully ignorant of the back-end is because this conforms to traditional MVC architecture. In the Flex world, Flex’s role in MVC is based on the Data Transfer Object (DTO) approach. In the broad view of things, the Flex front-end is seen as the View. The same thing can be said with a Java JSP front-end, AJAX, Silverlight, or whatever front-end you flavor-of-the-month you are choosing.
Most web applications are structured as three-tiered applications, which, to some extent, can be compared to the Model View Controller (MVC) architectural pattern. The MVC pattern distinguishes three parts in the application : the Model, where the data is gathered, the View, which represents the data from the Model graphically and receives user inputs, and the Controller, which processes the user inputs coming from the View to update the Model.
In the case of a Flex RIA, the Controller can take the form of a Service (or business object) on the application server that reads and updates a Database (the Model) when it receives requests from the Flex application (the View) which, itself, represents the DataBase records to the user.
But the Flex application does not have to care about the details of implementations of the controller. The way it deals with requests and responds to it is definetly in Flex’s not-my-problem realm, exactly like a View does not have to care about what its controller actually does. It just has to know how to communicate with it.
The same advantages for any MVC framework can be applied to a Flex application with any type of back-end application and DB. All of the arguments that Aaron made above support these potential problems solved by a true MVC architecture.
Note that this is from a Java background. I am not terribly familiar with CakePHP, but I know that it is similar to Java’s Hibernate and there have been attempts made to make CakePHP adapt more closely to the Flex front-end. See CakePHP’s AS3 Inflector for example.
I just wanted to further explain my previous post now that I have more time to ponder and reflect on the topic :).

09.19.2008 / Flex’s Data Transfer Pattern (Class Adapters) « Nate’s Code Vault said:

[...] a CakePHP environment that have been carefully outlined in Aaron Hardy’s blog post entitled: The Why, What, and Where of Custom AMF Class Adapters.  I have made a few comments as well as some of the other developers at MediaRAIN.  Here are some [...]

01.15.2009 / Flex’s Data Transfer Pattern (Class Adapters) | Nate's Code Vault said:

[...] a CakePHP environment that have been carefully outlined in Aaron Hardy’s blog post entitled: The Why, What, and Where of Custom AMF Class Adapters.  I have made a few comments as well as some of the other developers at MediaRAIN.  Here are some [...]


Leave a Comment

Your email address is required but will not be published.




Comment