Wednesday, January 9, 2008

why adobe flex makes me want to cry

Adobe Flex can be used to create some impressive UIs that can be delivered over the most established plugin in the universe. For this and other reasons, I am forcing myself to use it on my current project. It is a love/hate relationship, with very little love.

For a moment, let's ignore the pain of super-verbose static typing, and the crushing weight of a class hierarchy that makes the Java class libraries seem thin . . . let's focus on the basic inconsistencies in the API. We'll start with some of the widgets that you would use on an edit form: TextInput, DateField, NumericalStepper, and ComboBox.

You may have noticed that TextInput and DateField lack some basic naming symmetry. And if you forget, and use a TextField, well that is a Class too, but it's not at all what you want. Why they couldn't call it DateInput is a mystery to me. But it gets worse...

All of these edit controls have properties (or functions) to set the value that shows up in the UI control. It seems like we could take advantage of a little ad-hoc polymorphism and name the property something like: "value" for all those different classes. So, then it wouldn't matter if I had a TextInput or a DateField, I could just call:

uiComponent.value = something

Instead they've given us:

DateField.selectedDate
TextInput.text
NumericalStepper.value
ComboBox.selectedItem

. . . awesome. But we are not done yet. I've saved the best for last, because this one just bit me . . . again.

Since we are dealing with UI classes, hierarchy abounds, and we need to get at the parent and children of most objects. Well, if we are using any of the UI containers we call getChildren(). If we are using a class like CompositeEffect, we need to call the children property. And if we want to get the children of an XML node we need to call the children() function, not the children property!!!

I just wasted 20 minutes (plus another 30 on this rant) because I was calling .children instead of .children(). And now for the best part . . .

The super-strict compiler, with all the help from the carpal-tunnel-inducing variable-typing information that I had to hammer into the code, didn't even throw a warning.

Are you @&#$ kidding me?!?

So, I write a rant that no one will read, say 'calm blue ocean' a couple hundred times, and dream of a day when I will be back in the comforting embrace of languages like Ruby.

By the way, Ruby has a solution so simple (and elegant) to the "is it a property, or is it a function?" problem: There are no public properties. It's always a method. But, the parenthesis are optional.

xml.children
- or -
xml.children()

. . . it's all good in Ruby-land.

Here's my guess as to why we ended up with XML.children():

  • Flex dev #1: an XML object has to be dynamic to allow traversing the names of the nodes, so we can't do any compile time checks on properties.
  • Flex dev #2: yeah, if someone had xml like this:

    xml = <root><foo>hello_world</foo></root>

    . . . then xml.foo should refer to the "foo" node.

  • Flex dev #1: so we'll have to make children a function call instead, otherwise it will get confused with the node name in xml like this:

    <root><children><foo></foo></children></root>

  • Flex dev #3: Wait, if xml.children will return the "children" node, isn't that the same as calling the children method? But more importantly, if it's going to be a function shouldn't we rename it to getChildren() so it's clear that it's a function call and not a property?
  • Flex dev #1: shut up, rookie!

Ugh.



Paul B - January 9th, 2008 7:10 am

I was thinking about moving to Flex from Flash 8. Now I'm not so sure. I'm not the best developer in the world to begin with, so fighting through this chaos may not be a good option.

Thanks for the insight.

BTW, Flash 8 has it's own set of frustrations as I'm sure you know. Maybe someday Adobe will get on the ball and clean up this mess.

Tom - January 9th, 2008 7:13 pm

based on your example and some googling, it looks like flex implements e4x, so you can blame more than just adobe engineers for children().

I think you were on the right track with your theoretical conversation between flex engineers as to why the compiler can't catch your error, too. Flex/ActionScript/JScript.NET/Javascript2 all allow for more strict type checking, but they also must allow for old-style vars and "expando" dynamic properties. That's actually the beauty of e4x:

var el = <foo><bar/></foo>;
alert(el.foo.bar);

You don't need to use the chilren() property, you can just access the XML DOM like a javascript Object.

But sometimes the compiler can't figure out what you've done is wrong at compile time:

var x:XML = read_from_somewhere();
alert(x.foo.bar); // valid????

I think this can only be caught at runtime, if read_from_somewhere() doesn't return xml that matches the properties specified.

And while getChildren() might make it less likely you'll accidentally use it incorrectly, the compiler would still need to allow x.getChildren to be accessed as a property in the event that you define xml like <getChildren/&gt

I definitely hear you on the inconsistency with the "value" properties of widgets though. Nearly all toolkits suffer that.

two bit fool - January 10th, 2008 6:38 pm

Paul,

Flex isn't all bad. It has some very respectable UI components. And the availability of the source code is nice.

But it does have a definite "Java smell".

two bit fool - January 12th, 2008 7:03 pm

Tom,

Good call. e4x definitely deserves some "credit" for my headaches. So much so, that I'll probably write a separate post about it.

mzx - June 24th, 2008 7:30 am

first learn than blame..
flex is working fine for me. When i feel i have troubles with some say DateInput, im welcome to extend and override whatever i need in few lines of code. So add method value() to each uicomponent u need, or create getMyChildren for XML class this is not big deal imho

two bit fool - June 26th, 2008 10:46 am

mzx,

I wasn't saying that we can't "fix" the naming problems. I'm just lamenting the fact that the Flex designers failed to be consistent in such an obvious case -- a "value" property for UIComponents.

As for extending the XML class, you can't. The XML class is final and can't subclassed. Even if you could, it still wouldn't resolve the problem that all property access on an XML object is DOM traversal. So, you can't create a getter called "children" to allow this: node.children

It would have to be a function, called like this: node.children()

Then programmers are faced with the "is it a property or is it a function?" problem because "children" is named like a property but called as a function. This is a problem that I talk more about in another article.

Dylan - June 27th, 2008 10:24 am

Your post actually uncovered some answers to the .value, .text, .children .getChildren() and .children() I was looking for. Obviously I'm having the same frustrations you did and it's reassuring to see that I'm not alone.

Thanks for your post.

two bit fool - June 28th, 2008 7:55 am

Dylan,

It's nice to know that my rant actually helped someone.

ECMAScript v4 derails...finally - August 14th, 2008 9:55 pm

[...] When I first tried Flex, Adobe's poster child of AS3, I was stunned. It felt like I had stepped back into the early days of Java. I was contantly fighting the syntax and the framework, interrupted by frequent "breaks" as I waited for the lathargic compiler. After countless expeditions into the nested maze of class documentation, I gave one final laugh at its ridculous verbosity, and walked away.  Some other Flash developers noticed the same trend, and they wondered if Adobe was headed in the wrong direction. [...]

Mike - October 14th, 2008 11:52 am

...but thats not all: Flex have memory leak issues, too. I thought about develop my next whole project with Flex or just use a component from Flex.

By testing my application, I found out, that there are many memory leaks, so you cant use it for a long running applications.

e.g. the following two line will cause a memory leak:

private function httpServiceResult(evt:ResultEvent):void {
xmlDatasource.removeAll();
xmlDatasource = new XMLListCollection(XML(evt.result).children());
}

Jovi - March 19th, 2009 10:26 am

I am pissed for almost an hour now, that there is no such thing as the JS getElementsbyTagName in Flex. I am probably too confused to see the easy solution, but say i wanna reset all textinputs somewhere, how can I get a list with all of them, no matter how deep they are nested in containers?

I must write my own recursive function for that, i guess.
Unfortunately , I am the total recursion noob and cannot even think the solution in my had.
Meh.

No comments:

Post a Comment