For the last few weeks I've been working on a project built with Adobe Flex on Adobe AIR. A quick rundown - Flex is Adobe's (well, Macromedia's really) solution to make building form-based apps in Flash (as opposed to animations) easier, and AIR is Adobe's way of expanding its influence off the web on to the desktop by allowing Flash and HTML/JS/CSS apps run as if they were desktop apps.
This is my first foray into the world of Flex, and might as well be a first into Flash and ActionScript (the last time I fiddled with this stuff was ages ago, and it was nowhere near as in-depth as this project). I chose it for this project because I was bored of HTML/CSS/JS and its quirks, and how rough it is when it comes to building apps without the HTTP model. My main need was that it need to support spiffy, animated interfaces out of the box. The alternatives were WPF, which isn't cross-platform... and, that's about it (Java's ugly and clunky).
I approached this project as if it were a desktop app, and had those expectations in mind. I had nothing against Flex/AIR prior to this - in fact, I was even excited to use it initially. And even now, Flex/AIR still holds a unique set of capabilities that others do not have, so there are definitely cases where I would still consider using this combination.
All that said, there is clearly a bit of work to be done to make this combination work better, and be a lot more appealing, unique capabilities aside.
The constructor and casting syntax is very similar and hence can be confusing. But to be honest, this didn't bother me too much, and there is alternative syntax for casting, however it does work slightly differently.
var ac:ArrayCollection = new ArrayCollection(a);
var ac:ArrayCollection = ArrayCollection(ac);
Properties must have the same visibility. This was a big one for me - there were plenty of situations where it made perfect sense to have a public getter, and a private setter, but no, this can't be done in ActionScript(AS) 3. One workaround is to use a method instead, losing the advantages of the properties syntax.
The this keyword, combined with dynamic anonymous classes can lead to insidious bugs. This isn't really a fault of AS3, but the combination of the two means your intention is easily mistaken.
public class ThisTester
var _testValue:Boolean = false;
public function get testValue():Boolean
public function set testValue(value:Boolean):void
_testValue = value;
public function test():void
var f:Function = function():void
this.testValue = true;
If you called test(), then did trace(testValue), you will see that the testValue still == false. Yet, if you add a trace right after the this.testValue = true line, e.g. trace(this.testValue), it will return true.
Why? Because when you declare an inline function, a new scope is given to it. By explicitly specifying using the this keyword, you are in fact specifying the scope to be the new one, rather than the enclosing ThisTester scope, and when it can't find a testValue member in the new scope, it defines a new one as a dynamic member.
No block-level scope. This is weird, but one I can deal with I guess. In AS3, variables defined inside a for loop, if block, try-catch block, or some other block, is accessible outside of that block as well (but within the same function). So if you define the same variable in different for loops in the same method, the compiler will warn you of declaring a variable twice, something different to C# and Java.
No generic types. Maybe I'm just spoilt with C# and Java, but if AS3 wants to be a typed language (and it does), it really needs generics so types can be checked at compile time.See update at the bottom.
Tries too hard to be a typed and untyped language. AS3 would've been better if they could just decide on what it should be. Right now, you can use it as a fully typed language, or as an untyped language. However, judging by the libraries, it seems Adobe is pushing developers to the typed route. That said, it is missing some of the things that make typed languages good (e.g. generics), and personally, I think the untyped nature of AS was one of its strengths, yet Adobe seem intent on taking dynamic/untyped language features away from it.
Has language features only usable by internal classes. For example, abstract classes are not supported, yet some classes are inherently abstract, e.g. flash.display.DisplayObject (see here). The E4X XML syntax is another, e.g. xdoc..name. To be fair though, it isn't the only language to have in-built support for something that cannot be replicated by developers (VB.NET's literal XML support is another). It would be nice if it was possible though.
Classes and constructors cannot be private. Prevents the use of the singleton pattern without ugly hacks.
The so called CSS support is subpar. It doesn't support binding, only works with certain properties (e.g. width and height can't be set in CSS), and one of the most annoying issue - you can't refer to items in MXML using their ID in CSS. The one good thing about the CSS in MXML is that you can apply the same set of styles to multiple elements, and it is a neater syntax than specifying the attributes in MXML (less angle-bracket tax).
There is no threading support even though the Flash Player itself is threaded apparently. Not entirely impossible, but there are times where synchronous behaviour is desired, and it makes it difficult. Also, because it is single-threaded, long-running intensive operations may hold up the UI thread, even with callbacks.
The in-built libraries are, to say the least, lacking. Among other things, there is no reflection API at all, even though all the bits for it are there, and hence there are some excellent third-party libraries out there (Spicelib is one example). There is no method to round numbers to a certain degree of accuracy either - only round to the nearest integer. The workaround is to raise the number to a certain power first, use the in-built round, then reverse the initial operation (credit here), but this is just basic stuff that should be in-built.
There are plenty of libraries out there that fix these shortcomings and more, but at the end of the day, it all just adds bloat to apps when the functionality should just be in-built. Don't go all out and implement obscure functionality that few people would use, but I think it is time to consider widening the in-built libraries. I'm pretty sure users would rather a once-off larger download, compared to a longer download every time they load the app (obviously less of an issue with AIR apps, but more so with Flex in browser apps).
Some methods have weird quirks. This is probably not an AS3 thing, but rather part of the ECMAScript spec, but still - why does the date method assume months are zero-based, but other parameters (day, year etc.) are not?
The lack of local system APIs in AIR apps is ridiculous. Why can my app have full access to the filesystem (to the extent that the user does), yet it cannot run another app on the desktop? I suspect Adobe are trying to prevent the whole ActiveX debacle, but there are much better ways of doing that than restricting the ability for your platform to do what it should be able to. Or maybe cross-platform issues; hopefully something they have resolved in AIR 2.0.
The organisation of the in-built APIs are annoying and confusing. I understand the need to separate Flash and Flex namespaces (hopefully, this won't be an issue in the future if/when Flex is integrated into the Flash distribution), but it really doesn't help the discoverability of classes when you have to look in multiple places for things, e.g. the flash namespace, and the mx namespace. From my perspective, they're the same thing, so put them together. Also, sticking things in the utils namespace is the same as sticking them in the miscellaneous namespace - what's wrong with giving them their own namespace?
There is also a lack of open-source libraries for common desktop app tasks, like data objects management and persistence.
The AIR security restrictions are still not documented well. I have yet to find a document that explains when a cross-domain policy file is needed for URLLoader requests, and when a socket policy file is needed for Socket requests. There are also apparently sockets that I can't use, even if there is a socket policy file (below port 1024 I think). I understand there is a difference between the AIR app running from the AIR package, as opposed to code loaded from the net (e.g. another SWF file). All I want is a nice table describing what remote request APIs I can use in what situation.
Javadocs-style docs suck. Admit it. I know AS3 and Java have a close relationship, but I hope you are not blind because of that. In case you are, I'll tell you - Javadocs are useless, and the ASdocs, while they're slightly better, they could be much better.
- There is no information about which version of Flex the particular API is available in, the differences if any, or which one it was introduced in. This is important, particularly if you're just searching for APIs on google, and stumble across something, or need to use a certain version of Flex/AS. The way that MSDN does it with .NET Framework APIs is one way. This is one thing that has irked me to no end when I was using Java, and needed to know if a certain method was available in a certain JRE version.
- The constructor is not highlighted in the docs. It is there, under methods, but given its particular importance, I think it should be given its own section.
- There are still many areas that are missing examples and detail, and links to the Programming ActionScript 3.0 or the Flex 3 Help site with more information, e.g. http://livedocs.adobe.com/flex/3/langref/mx/rpc/xml/SimpleXMLEncoder.html - how is it encoded, what does it look like, any metadata tags to control serialization?
- The 'comments' section doesn't have enough direction. There are many pages where the comments are people asking for help, rather than the intended purpose, which is to add to the content on that page.
- The pages on Flex visual components lack visual diagrams. In fact, the entire API docs set is lacking in diagrams, but it is most needed in visual component pages. I know the books and help site have them, so maybe better linkage is one solution, but is there much harm is visually describing concepts in the API docs?
- There is a tendency to use big convoluted words to describe things, just because you can.
LiveDocs search is crap. If I am on a Flex 3.2 API page, and I run a search for XML, I expect the results to be for Flex 3.2, not Flex 2.01, which all the results on the first results page are. Sure give me an option to widen my search, but I think that is a reasonable assumption.
LiveDocs is slooooow. I don't know why, but being new to Flex, and having to look up so many pages on it has gotten me quite annoyed at the delay. Any chance you can make it Google speed?
There are no coding guidelines (that I can find). Where are they?Found them - http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions. Not complete, but quite extensive, although some reasoning in certain areas would be nice.
Of all the sections I'm complaining about, this is the BIGGEST PAIN POINT. If there is a better IDE out there, with similar support for Flex features, I would dump Flex Builder in a heartbeat.
Eclipse is sloooow. I have never experienced good performance with Eclipse-based IDEs, and this is no exception. The startup time is ridiculous. Other IDEs (Visual Studio, Komodo) all load and work faster. Maybe I need to tweak my Java settings...
The compiler is very, very, slow. Because I'm using a few open-source components from the SVN trunk, I don't have the compiled SWC, and I haven't found a handy way of compiling them into SWC without having to do -include-classes and listing all of them manually. No thanks. So every compilation of my fairly simple app takes at least a minute. It drove me up the wall until I found the 'build automatically' setting and turned it off - it took minutes every time I saved a file. Again, maybe my Java settings need to be tweaked...
Apparently, improvements are in the pipeline for Flex 4 (Gumbo).
The code checking mechanism seems to be dependent on the compiler, which is slow as I have already mentioned. This means that any errors (or warnings) in my code are not picked up until I compile the project, which takes minutes. Why can C# and Java IDEs detect these things without compiling, while Flex Builder can't? And I'm not talking complicated things here, but simple things like including the var keyword in a catch block (why it shouldn't be there, when it is needed in for each loops is another mystery).
Classes that the compiler doesn't think are referenced, are not compiled. I can understand the rationale here, but I use an IoC container (Parsley to be precise) that uses XML for configuration, and it is very annoying to have to use -include-classes (which is long and annoying), or use a useless class to hold references just so all the classes compile. There should be an option to make all classes within a folder compile.
Eclipse is too imposing. Why do I have to specify a workspace? I like to have my projects all over the place, in my own perfectly organised world, who are you to tell me where I should put them? I should just be able to open any project I have, in any instance of Eclipse. It took me ages to discover that I apparently had to 'import' projects into my workspace before using them if they were in a different location. Why can't I just open them? To make things worse, apparently Eclipse is so cool it can rewrite the meaning of the word 'import' - import doesn't necessarily mean it will copy the project into the current workspace, as it does in every other program. Oh, and did I say that the Import dialog is confusing as hell? What's the difference between importing a Flex Project, and an Existing Project into Workspace?
No refactoring support (renaming a file doesn't count). Adobe, I'm sick of typing all the boilerplate property getters and setters. Why can't your IDE do them for me, like all other IDEs, and while we're at it, how about extracting interfaces, extracting methods, promoting variables, converting between loops, and all the other convenient things other IDEs do out of the box (although they do it even better with commercial addons).
Does not offer fixes for errors it can determine potential solutions for. If I forget to implement an interface method, I expect to be able to click on the red X and select 'implement method' and have the method signature added to the current class, ready for me to implement. If I forget to import a class before using it, I expect to click on the red X and be able to select which class I mean, and have the import declaration added for me automatically. Eclipse Java does all this and more.
Find does not wrap around. I don't know about anyone else, but most of the time when I'm searching for something in a class, I generally want to search the whole thing. There is no such option in Flex Builder, and worst of all, the search does not know how to wrap. So if you're expecting it to wrap if it does not find any results in the selected direction, as you are quite allowed to expect given most other apps do it, you will be surprised, then annoyed after you realise.
Code completion is very hit and miss. I don't know how to replicate this because it is very random, but it is extremely frustrating when you need code completion to appear and it doesn't, particularly when you're still learning the APIs and using code completion to discover APIs. This is in both AS3 and MXML, although MXML is much better. If they could add support for code completion before the dot is entered, I would be over the moon, e.g. if I type in Simp, code completion should show me matches including the SimpleXMLEncoder and the SimpleXMLDecoder. Alternatively, because I use _ for instance variables, I would like them to show as soon as I type _.
There is no code completion for CSS attributes. What were they thinking? Too difficult?
There is no ASDoc or Flex doc integration for code completion. Apparently they think their methods are so descriptive, that even a one-liner describing them are unnecessary. Seriously guys, take a look at Visual Studio, where one-liners are given for each member of a class, and when you use a method, one-liners are given for each parameter in the signature. Even better, take a look at Eclipse Java or Netbeans, where a shortened version of the Javadocs is shown, with full working links. I was very impressed when I saw that.
Properties don't have type information in code completion, but everything else does. WTF?
Object Browser anyone? I have missed this every time I leave the .NET universe. Why does no one else think it is useful to have the entire API (and any loaded libraries) shown in your IDE as a tree, so you can browse through it, find methods, and get basic information on them? This is so much better than browsing through the web-based API docs. You can even browse through the current project's classes. Even better would be the class view in .NET Reflector, which shows all inherited types, and classes that inherit from it, among other useful bits.
I know my errors are important, but really, I don't need to be told twice. For some odd reason, every error and warning I get in Flex Builder is repeated twice.
Where are my inherited members? Why doesn't the Outline panel give me the option of showing inherited members? Sometimes it is useful to know what they are, to know what I should call or whatever.
Custom code folding regions, please. Another thing I miss when I leave the .NET universe. I like being able to define regions in my code, e.g. for properties, overridden methods, private methods, etc. and be able to shrink and hide them when I want to.
If I don't want the debug perspective, I don't want it. Sometimes when I debug code, I would rather do it in the Flex Development perspective. Yet Flex Builder get angry, and when I step through code, it asks me on every line, if I want to open the Flex Debugging perspective, even if I had already clicked No. Why don't I click the 'don't ask me again' box? Because I want it to, but the next time I start debugging, not this debugging session. Oh, and it would be nice if it would return me to the Flex Development perspective when I've terminated the debugging session.
Anti-aliasing in the editor. All my usual coding fonts look funny in Flex Builder, except the default Courier New, which sucks.
More precise context menus, less hidden keyboard shortcuts. The right-click menu for a doc is way too big, and some things are not applicable. Run As, Debug As, Profile As? They belong in the Run/Debug menu, or the right-click menu of the project, not the current coding file.
More surprises. I want to right-click somewhere, or do something, and have an option to do exactly what I was thinking, like the first time I discovered the 'generate getters/setters' option in Eclipse
Ok, I think I'm done. There's probably more, but this is plenty. Just needed to vent all that steam that has been building up over the last few weeks.
But seriously, Flex/AIR is a platform with a promising future, and maybe I am being unfairly harsh on it, given it is relatively new. It still has some way to go before it will be the slick desktop app platform that its marketing material proclaims it to be, but the momentum is definitely there. Indeed, it definitely has a passionate developer base that is willing to overlook and workaround the shortcomings of Flex, and still produce stunning stuff. This experience has just told me though, how important every part of the link is in the platform, and the weakest link really drags it down.
At the end of the day, do I regret using Flex/AIR for this project? No. In hindsight, would I pick another set of tools? No. Would I consider Flex/AIR for a project in the future? Yes. Would I be a happier camper if they fixed all the above and more? Definitely .
And if anyone knows of solutions to any of the issues above, I'd love to hear them.
P.S. I'm running the free educational version of Flex Builder 3 Professional (available at http://freeriatools.adobe.com), and unlike other student editions of stuff, Adobe allows users of this version to create commercial apps too. Nice one.
UPDATE (31/12/2008): I stand corrected - Flex 3.2 has a some kind of in-built generics support in it for Vectors (the java.utils.Vector type of Vector, i.e. a typed ArrayCollection in AS3 terms). Unfortunately, it doesn't seem like you can use it in your own code though.
UPDATE (03/01/2009): While I'm complaining - it would be nice if AIR apps defaulted to an icon, say the AIR icon, if no icon is specified, instead of the default OS no-icon icon, which in Windows, is not the prettiest icon out there, particularly the icon in the start bar, which for some reason is different to the others.
UPDATE (04/01/2009): What, there's no dispose event? How the hell am I supposed to do cleanup? The removedFromStage event fires when I minimise the app, or if I move the component around the display tree; very helpful.
And the accordion doesn't fire the CHANGE event if I change the selected panel programmatically, only if it was changed the user in the UI. I really fail to see the logic here. Apparently we're supposed to use the ValueCommit event, which is very helpful, because it only tells me some value has changed on the Accordion control, not which one - not.
UPDATE (09/01/2009): Found the coding conventions. See entry in post above.