Subscribe to feed
Blog | About

Archive for March, 2007

Flex2 Opinions

At work we decided to give Flex2 a lengthy, honest trial run as a replacement of the Html/JS used for an important component of our application suite. It is an intranet sort of application where we controlled the environment and it seemed like a promising place to put Flex2 to work.

After months spent learning and becoming accustomed to Flex2 our team decided it simply is not a technology ready for building enterprise applications. We are now taking a pragmatic approach: continuing with Html/JS but using the Flex-Ajax bridge for charting, graphics, and multimedia. In my opinion these are things Flex2 is great for.

To anyone that may be considering the Flex2 platform, know that you will find large crowds of evangelists (many of them Adobe employees) on the web describing trivial applications and simple examples to make Flex2 sounds like a fantastic way to solve problems. When we starting dealing with hard problems our experience was extraordinarily negative.

My biggest issues with Flex2 are the following. My viewpoint here is largely a comparison of Flex2 against Html/JS for building rich internet applications. Though based on months of nontrivial development these are my individual opinions.

  • It is not production ready. It is not a stable product. We have an internal wiki page titled “Flex bugs & gotchas” and its content has grown to a substantial size. Take a look at the latest hotfix notes to see what sort of nontrivial issues are just being addressed.
  • The community is small and inexperienced. Flexcoders and Flexcomponents are great groups if you have trivial questions. We asked a half dozen hard questions over the last few months and those were met with either complete silence or confirmation from a Flex team member that we had bumped into another known bug with no confirmed fix date. Compare this to the mailing list and forums for Spring, Hibernate, JS/Dojo/Prototype/DWR, or PostgreSQL where your questions are answered so thoroughly that you feel questions far more difficult than the ones you face have already been conquered by people more knowledgeable. Patches to specific issues are also the norm in these communities. Maybe patching the Flex2 SDK is an easy process, I didn’t try it.
  • The livedocs are down more than they are up. These would be pretty helpful if they were reliable.
  • Existing examples of reasonably nontrivial Flex2 applications on the web are really buggy. Go visit the Flex2 search appliance or the golf store that someone made (can’t remember the url right now - will look it up) with a debug version of the flash player installed and watch the errors bubble out.
  • The tools are not established. Flex-Ajax bridge is bugged. ExternalInterface is profoundly bugged (see my earlier post about this). The Flex Ant tasks are bugged (only with the most recent update did a failed compile cause a build to fail and most of the command line arguments aren’t stubbed into their corresponding ant tasks). Want to display some HTML in your application? Get ready to wrap your application in an HTML container, invoke an iframe in that container, and then hack massage it into place over your application so that it looks like it belongs there. Granted, all of these tools are still in Adobe labs so it is fair to expect alpha-ish quality, but I need real tools now to build applications with.
  • Adobe’s priorities with this platform are exceedingly frustrating. They are working on Apollo and Flex3 while huge, show-stopping bugs exist in Flex2 and prevent it from being a viable alternative to more established technologies.
  • Flex Data Services might be a good thing. It might even make the platform reasonable for an enterprise-grade application but it costs $20k per CPU. I can buy a beefed out database server with dual procs, 16gb RAM, and a 16 disk sata raid array for less than the price of licensing one of its CPUs.
  • It is extremely difficult to find talent with Flex2 experience or a desire to obtain it. We want full-time, exceptionally intelligent software engineers. Our efforts to find Flex2 developers brought us contractors that refused to work onsite and people that think knowing individual, popular languages is more important that understanding the concepts that make them the same. We work with area recruiters and the vibe from them was much the same.
  • The evangelists drive me nuts. They are too worried about presenting Flex2 as the slickest piece of engineering ever created to discuss the real issues that prevent real work from being done with it.
  • While not unique to Flex2, the compile cycle is killer. I found over time, as our application grew, it completely crushed my productivity. Compare this to pressing F5 with the alternative.
  • FlexBuilder is worth $10 and not $749 (that’s with charting, but if you are using Flex2 you should take advantage of the charting). No refactoring, no find usages, no code generation, plugin problems (we had a hard time getting subclipse and some other plugins to work with it), awfully unimpressive automatic importing, ctrl-space completion, ctrl-click, etc, etc. Comparing the Java intelligence of IntelliJ/Eclipse to FlexBuilder isn’t fair or applicable, but comparing the Html/JS intelligence of those tools to FlexBuilder is and they put FlexBuilder to shame. The design view, though helpful in some situations for coders, is not a design tool. Our designer hated it. The debugger pales in comparison to a Firefox instance with Firebug and the web developer toolbar installed.
  • Flex2 without FDS does not play well with anything other than xml or web services. I can tell by the search terms used to find this blog that people are interested in using DWR with Flex2. We built an Html/JS container that provided a communication layer between Flex2 and our exposed DWR objects and though it worked for basic calls (did not handle timeouts, call batching, or reverse Ajax/Comet) it meant involving a 3rd debugger in development and it was really just very difficult to work with so many layers at the same time. Regardless I will try to post the code in the future to help anyone else in the same boat.
  • The whole platform feels disconnected. If you pull down the source code for the core Flex2 classes and take a peek, you will find big balls of logic commented out. It is as if they starting commenting out things that are broken until it was stable enough to ship. Also the impression I get from working with Flex2 is that Adobe has a grabbag of developers - some quite good, and some quite junior - and then turned them loose on different pieces of the compiler and FlexBuilder. The result is a language that is far less powerful than a fully dynamic language like Javascript and unawareness in some areas of the platform that other areas exist. A concrete example: Flex2 uses metadata internally ([Bindable], [ArrayElementType], etc) and essentially had a wonderfully powerful metadata construct written and working. You couldn’t use this metadata for your own code until 2.0.1 because they hadn’t thought to expose it. Even now you have to build with ANT and use some command line arguments that aren’t stubbed out in the Flex ANT tasks to make it work. Someone smart wrote the metadata code and it wasn’t leveraged in the rest of the platform. That feeling occurs repeatedly.

That said, Flex2 is great for making pretty things involving charting or multimedia. Our frustration began and grew as we tried to complete the nuts and bolts of a large enterprise application with it. If your application is heavy on the areas where Flex2 shines, then it may be worth the frustration. Perhaps your experience has been different? All I know is we are back to Html/JS using DWR for transport and Xulrunner/Firefox for the environment and getting work done again. Apollo sounds promising, but I am more excited about Xulrunner and Firefox3.

My advice is this: If your team has 1 or more of these following trends in place, I would strongly discourage a move to Flex2:

  • You are building an application for the public (you do not control the environment or user base). Flash player 9 is not ubiquitous and the 96% flash player penetration number that the evangelists trumpet include all versions of Flash player. Flash player 9 is no where near 96%. Though it wouldn’t be fair to not mention that MySpace and Youtube are going to help Flash player 9’s penetration number increase faster than version 8’s.
  • You have solid Html/Css/JS knowledge in place now. While I prefer this stack enourmously over Flex2 I also realize there is a learning curve involved. If you have already conquered that learning curve rest easy knowing you are using the superior tool.
  • You are building business applications or applications that aren’t heavy multimedia. Flex2 is great for multimedia and I don’t hesitate to admit its superiority here. Keep in mind that you can use the ExternalInterface or the Flex-Ajax bridge to use Flex2 widgets inside your Html/JS with relative ease.
  • You are building large applications. For smaller applications Flex2 is fine. Cairngorm helps (and in fact may help you keep your sanity) but it doesn’t solve all of the problems.
  • You don’t currently have nightmares about scrollbars and don’t want to start having them :) This will only make sense to someone who has worked with Flex2.

Needless to say, probably the last Flex-related post for this new blog except for the DWR bit or unless I have something interesting to share related to the charts and multimedia strengths we will continue to use. I tried to keep this post objective; it does represent 6 man months of experience. I love many of Adobe’s products and I recognize that there are several cases where Flex2 would be a great tool. Large, enterprise applications is not one of those areas.

That said, it is a new tool in my toolkit and because it has obvious strengths I can certainly see myself using it for those strengths in the future.

Comments (19)

Generating DWR Javascript Files

I’ve talked about DWR before. It is a mature project that is well constructed and very useful. DWR generates Javascript files at runtime that you can include in your client-side code and use to call exposed Java methods. A few days ago I wanted to generate these files as part of our normal build process so that we could open and read them directly. More importantly (for me at least) I wanted to have them in my project directory so that IntelliJ could index them. This may seem trivial but I am obsessive about letting my IDE aware of as much as possible and I found this to be a huge help when writing client-side Javascript. Now I can ctrl-space complete, ctrl-click, and everything else IntelliJ can do with Javascript on these DWR Javascript files.

I posted my plan to the dwr mailing list and as usual the creator of DWR himself showed me exactly how to accomplish this when using a dwr.xml file for configuration and when not using Spring. If this is your environment I encourage you to search that list. There is a great community there and I have found it extremely helpful and responsive many times.

That said, I wanted to do this in our Spring project using DWR 2.0rc2 with an annotations based DWR configuration. It was pretty easy to take Joe’s example and adapt it to this case. Here is the core of the Java code to get started.

First the imports I am using:

import org.directwebremoting.util.FakeServletContext;
import org.directwebremoting.util.FakeServletConfig;
import org.directwebremoting.impl.ContainerUtil;
import org.directwebremoting.impl.DefaultContainer;
import org.directwebremoting.extend.Remoter;
import org.directwebremoting.spring.SpringContainer;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import javax.servlet.ServletContext;
import javax.servlet.ServletConfig;

Now the code that sets up a DWR Remoter object which we can request Javascript content from:

ClassPathXmlApplicationContext appCtx =
  new ClassPathXmlApplicationContext(”testContext.spring.xml”);

Map<String, String> initParameters = new HashMap<String, String>();
// comma-delimited list of annotated classes
initParameters.put(”classes”, “FooAjaxController”);
// telling DWR to use a different Container subclass
initParameters.put(”org.directwebremoting.Container”, 
  ”org.directwebremoting.spring.SpringContainer”);

ServletContext servletContext = new FakeServletContext();
ServletConfig servletConfig = new FakeServletConfig(”dwr-test”, 
  servletContext, initParameters);

DefaultContainer container = 
  ContainerUtil.createDefaultContainer(servletConfig);
((SpringContainer)container).setBeanFactory(appCtx);
ContainerUtil.setupDefaultContainer(container, servletConfig);
ContainerUtil.configureFromAnnotations(container);

Remoter remoter = (Remoter)container.getBean(Remoter.class.getName());

// do what you want with the Javascript content

appCtx.close();

In the above code, before the appCtx.close() line you can pull Javascript content out of the Remoter object like this:

remoter.generateInterfaceScript("fooAjaxController", "/fake/path");

The second parameter is the path you want the Javascript files to use for accessing corresponding Java servlets and in this case they didn’t matter. fooAjaxController is the Javascript name for the DWR Java class. My preference for naming of DWR classes is that all Java class names end with AjaxController and that the bean name and DWR Javascript name are the same and the camelcase version of the class name.

From here it is pretty straight forward to do whatever you want with this Javascript content from the remoter. In my case I pulled the bean definitions out of the Spring context, separated out all beans with a name ending in AjaxController and then built lists of bean names and class names at run-time to use for the classes parameter and for reading the content back and writing it out to files. This way nothing had to be hard-coded and changes made to the bean configurations in our Spring context were automatically accounted for.

Hopefully someone else finds this useful.

Comments (2)

DWR Annotations & Spring

We recently upgraded DWR in our primary product from version 1.1.4 to version 2.0rc2. The newest version offers a pile of great improvements on an already excellent piece of code. One of my largest motivations for the upgrade was the new annotation-based configuration option and the resulting elimination of our dwr.xml file that had grown to be large and confusing. The signatures block can be completely dropped with Java 1.5 and the create and convert elements can now be represented 100% in annotations.

Our codebase was built with Spring in mind from the start and I hit a small block when trying to get the annotations to work. This page provides a start but doesn’t specifically mention Spring. Here is what an annotated RemoteProxy class looks like with Spring factored in:


import org.directwebremoting.annotations.RemoteProxy;
import org.directwebremoting.annotations.Param;
import org.directwebremoting.annotations.RemoteMethod;
import org.directwebremoting.spring.SpringCreator;

/**
* A Java controller exposed via DWR
*/
@RemoteProxy(
    creator = SpringCreator.class,
    creatorParams = @Param(name = “beanName”, value = “someAjaxController”),
    name = “someAjaxController”
)
public class SomeAjaxController{

    @RemoteMethod
    public int trivialExample(int param1, int param2){
        return param1 + param2;
    }
}

That’s it. As someone who lived mostly in the client-side of DWR I wasn’t familiar with the creator concept and it took me more than a single google run to find the creator/creatorParams being used clearly in the RemoteProxy annotation. In our project we standardized on making the beanName and Javascript name the same but they could be different in the above example.

Hopefully this saves someone else a few additional minutes of searching. I hope to post about Spring and DWR more in the future - they are both excellent projects with experienced, helpful communities.

Comments (5)

Flex2 Resources

I mentioned flexcoders in my last post but didn’t provide a link or more information. I thought it would be helpful to list the Flex2 resources I rely on in one place as I know I struggled to find resources initially and the more places indexed in Google for people to find the better.

Point 1: Don’t use the forums at www.Adobe.com for Adobe Flex2 questions. I had 0 luck here and they are virtually silent.

Adobe Labs
This is a fairly helpful site both because it provides access to tools and utilities (like the Flex2 ANT Tasks, Flex-Ajax bridge, and lots more) and because the wiki pages associated with the various projects are very active.

flexcoders Yahoo Group
Why is Yahoo Groups being used? I don’t know, but this is probably the best place to post questions and look for answers. You’ll want to use Google to search the group though as my searches fail if I use more than 3 or 4 words (a fault of Yahoo).

flexcomponents Yahoo Group
Another good group - focused on component development.

The Livedocs
These can often be better (when they aren’t down) than the help system built into FlexBuilder due to the comment sections for each topic article and the fact that the Livedocs team can fix corrections immediately and keep them more up to date.

Cairngorm Documentation
Cairngorm is a solid framework for building substantial Flex2 applications. If you are working with Flex2 I highly recommend becoming familiar with it.

I have found all of the above to be quite helpful.

Comments

Flex2 External Interface Bug

Lest I lead people to believe I am a complete Flex fanatic with my previous posts, I thought it was time to post about a brickwall that we have not yet been able to conquer (and maybe someone will happen to read it and have an answer).

At work I use and love DWR. One component of our flagship product suite was initially a Javascript/Html interface that used DWR to communicate with our Java 1.5/Spring/Hibernate back-end. We decided to give Flex2 an honest, lengthy trial run as a potential replacement for the interface technology for this component.

When the decision was made to give this a shot, we had man-months of back-end functionality built and exposed via DWR. It simply did not make sense to rewrite this code. Further, there was no alternative to DWR that I liked as much. I refuse to believe FDS is worth its ridiculous price tag (I’d rather save 40k per server for additional engineers, additional disk arrays and more servers thank you) and all of the open source options I evaluated paled in comparison to DWR. We spent a man-week or so and built a communication layer that allowed to us to use DWR much as we were with Javascript inside of our Actionscript. This communication layer used the ExternalInterface API of Flex2 in some clever ways.

Now to the point of this whole post: we recently discovered what appears to be a pretty substantial bug in ExternalInterface. I’ll use JSON notation to demonstrate. It took us some time to realize what was going on.

Inside of the Javascript communication layer I can receive an object from DWR that looks exactly like this in Firebug:


mainObject = {
    id: “1234″,
    name: “mainObject Name”,
    mainControl: “mainObject Control”,
    subObject: {
        id: “abcd”,
        name: “subObject Name”,
        subControl: “subObject Control”
    }
}

Further, I can trace this with Firebug line for line right up through the point at which it is handed off as a parameter to a method exposed on ExternalInterface.

Now on the Actionscript3 side of things I have my breakpoint and debugger ready to stop immediately after reception of this object on the other side of the ExternalInterface. When it arrives it now looks like this:


mainObject = {
    id: “abcd”,
    name: “subObject Name”,
    mainControl: “mainObject Control”,
    subObject: {
        id: “abcd”,
        name: “subObject Name”,
        subControl: “subObject Control”
    }
}

Notice what happened:

  • All same named properties are set to the values of those properties on the subObject. The values on the mainObject were completely overwritten!
  • The differently named properties (mainControl and subControl) retained their correct values.

This a huge deal. To continue down this Flex2/DWR path we would have to refactor dozens and dozens of value objects to ensure no value objects that are nested inside of each other share property names and all future development would have to be done with this awareness as well.

This seems like a show stopping bug and that is why deep down I have to believe we are simply doing something odd with our implementation. Has anyone else encountered this issue or have any idea as to why we would be experiencing it? I don’t have any more code I can run a debugger on to try and figure this out.

I’ve got a post on the flexcoders list but our experience with that list has typically been that difficult questions are met largely with silence.

Comments (5)

Flex2 Custom Metadata

Flex2 has a pretty cool metadata construct that can be a huge feature for development - especially for certain types of tools and common objects. Mark at work put together a clever and very effective XMLNode-to-Typed-Class conversion tool using this technique and I thought I would share some of the bumps encountered to help anyone else with a similar task.

Here is a quick and to the point example. Using your own metadata requires Flex 2.0.1 as a required argument to mxmlc wasn’t added until that version. For this small example, lets say we wanted to use a [Transient] metadata tag to mark properties of a value object as client-side only to let some sort of imaginary persistence manager know that property should not be written to a database. You could use the same technique to specify types for objects in a collection (though this can be done with the specialized [ArrayElementType] tag), to specify types for both keys and values in a map structure, or any number of other scenarios.

With this example, you could have a value object that looks like this:


-----
public class ContactVO{
    [Transient]
    public var fullName: String = “John Doe”;

    // more properties and methods follow
}
—–

Now you can write code that can read this metadata information from these ContactVO objects at run time. Here is a drawn out and hardcoded example of doing this. You basically just use Flex2’s describeType method to obtain an XML description of an object and then use e4x to query that information.


-----
var contact:ContactVO = new ContactVO();

// get the E4X XML object description
var typeInfo:XML = describeType(contact);

// get the property we marked up with metadata
var fullNameInfo:XMLList = typeInfo..accessor.(@name == “fullName”);

// check for the [Transient] tag
if (fullNameInfo..metadata.(@name == “Transient”).length() > 0){
    // do something - maybe exclude it from a commit list
}
—–

Metadata tags can have properties too. Lets say you want to mark up a map structure so that you can determine the type of both the keys and values at run time. Flex2 doesn’t provide a convenient hashmap-ish class by default, so just assume you’ve made one.


-----
public class ContactVO{
    [HashMap(keyType="String", valueType="String")]
    public var phoneNumbers: MyHashMap = new MyHashMap();

    // more properties and methods follow
}
—–

You can access the metadata properties like this.


-----
var contact:ContactVO = new ContactVO();

// get the E4X XML object description
var typeInfo:XML = describeType(contact);

// get the phoneNumbers property we marked up with metadata
var phoneDesc:XMLList = typeInfo..accessor.(@name == “phoneNumbers”);

// grab the “HashMap” metadata description
var phoneMetaData:XMLList =
phoneDesc..metadata.(@name == “HashMap”);

// grab the “keyType” property from the “HashMap” metadata
var metaDataDesc:XMLList = phoneMetaData..arg.(@key == “keyType”);

// finally, grab the value of this “keyType” argument
var typeValue:String = metaDataDesc.@value;

Alert.show(”This HashMap has keys of type: ” + typeValue);
—–

To use your own metadata tag like this, you will need to use a custom argument when building your swfs. For the transient example above it would look like -keep-as3-metadata+=Transient. You can repeat this for as many custom metadata tags as you like. If you are building with Flex Builder, you can add this to the compiler arguments under Project -> Properties -> Flex Compiler. The problem we found was that Flex Builder ignores this entirely unless you are building a DEBUG swf. This was a enourmous headache and I still don’t know how to make Flex Builder use the additional arguments in both DEBUG and RUN mode. Only having DEBUG buildable through Flex Builder is fine for development but certainly not for production. The workaround available now is to use ANT (see my earlier post for an example of setting this up).

Hope someone else finds this helpful. The metadata construct available in Flex2 is quite powerful, you can use it to build tools and libraries that use annotations similar in some ways to those of Java 1.5.

Comments