Tcoz Tech Wire

Discoursing on trends and technologies interesting to Tim Consolazio, sole proprietor of Tcoz Tech Services, specializing in Flash/Flex/Air, iPhone, Facebook, Twitter, and related technologies.

"Technology from an indie software developer's perspective".

Tuesday, February 2, 2010

Flash Builder BUG: Services failing, SWF trying to load crossdomain.xml from localhost:37813?

Oh man this one cost me some time.

I have a swf loading data from some services at IP yadayada. It's working fine, both from the FB IDE, and when I copy the bits to the remote server, pull up a browser, and hit the remote IP.

Then I try it from another machine, same browser, same FP version, same IP address. I see this gobbledy gook:

Warning: Failed to load policy file from http://localhost:37813/crossdomain.xml
*** Security Sandbox Violation ***
Connection to http://localhost:37813/?q=services/amfphp?hostport=[ipommitted]&https=N&id=-1 halted - not permitted from [myswf]

WTF, why, why, why is that request trying to load the crossdomain file from localhost:37813, screwing up everything on all but my dev machine? Yes, I know dev machines aren't the acid test, but I'm not running the project from the IDE, or even the browser the IDE uses, I'm pulling up an "off to the side" browser and hitting the remote address, exactly as I am on any other computer.

I went through all the security settings, found posts directing me time and again to the new meta policy and socket policy documents and white papers: I've read them all, several times in the past, I'm good with Flash security, I KNEW I was doing all this correctly.

So, I abandoned Flash security, assuming I had everything correct. Where else had I seen URLS redirected to localhost:port?

HTTP Sniffers, like Fiddler. They intercept HTTP traffic, channel it to a local port, trace the data, and forward the request along.

Was I running one? No...oh wait, yes.

THE NETWORK MONITOR IN FLASH BUILDER.

IT COMPILES THE REDIRECT INFO INTO YOUR SWF.

So, if you compile your swf with the network monitor active, which you may not realize is the case, you have just told your swf to redirect all traffic to localhost:37813. So you'll deploy it, and guess what? Because no other machine is running the FB network monitor, the calls will fail. GAH.

Turn network monitor off. Recompile your swf. Redeploy. Voila.

GAH. What a pain. Anyway, if you have this problem, hopefully this saves you from the frustrated grumbling and cursing I spent a few hours going through.

As always, thanks for visiting.

Thursday, December 17, 2009

Flash Builder: Spark Skinning Issue to look out for (hopefully they'll fix this)

If you're in the ActionScript world and haven't cracked open the beta of Flash Builder (the latest version of Flex Builder, just rebranded), it's time to hit the Adobe site and pull it down. There's a lot to like about it.


It ain't perfect yet though. Here's a brief post about a couple of things I've discovered that might throw you when you get started.


Spark Skinning

The new Spark components (get ready for the new s: namespace) seem to work great, and have a lot less overhead than the old mx flex ones. For instance, "groups", like s:HGroup and s:VGroup, can be used instead of "boxes", like HBox and VBox. They work the same way, but don't contain logic for scrollbars and such. This somewhat mediates the old Flex issue of nested containers impacting performance. Although you should still always be careful nesting containers, its good to know that, at least to a point, you can be a little more creative about their use without overtly damaging your app's perf. You can also do more with CSS than in the past as far as skinning, fonts, and so forth. Great stuff.


However, it's still in beta, and I stumbled across what appears to be more of an API/OOP design flaw than a bug, but nevertheless still feels like something is broken, so here it is:


When using a Spark List component, you may want to reskin the Scrollbar (let's face it, the default scrollbars are UGLY). To skin the scrollbar, you would implement a new skin class for the part of the scrollbar that you want to alter, then simply apply it to that element of the scrollbar. The easiest way to to this would be to just copy the content of the default skin class, put it in a new class, modify it to suit your needs, then apply it in place of the default one. Note that the Spark documentation says this is the way to go; you shouldn't override or extend skin classes.


However, the default scrollbar skin for the increment and decrement arrows contains an "Arrow" MXML piece. Remember, this is the SKIN class, not the implementation class. Even if I omit the skin class entirely, I would expect the app to still compile and run; a null check would avoid any errors, though you may not see a skin for the scrollbar, or a default system skin would be used; something other than the app completely breaking without any compile-time errors.


You can find the Spark skin classes in [FB Install folder]/sdks/[version]/frameworks/projects/sparkskins/src/mx/skins/spark, which is great; using them as a starting point for skinning you Spark components makes this actually very easy.


Anyway, in those default Arrow classes (the ones I'm interested in are ScrollBarUpButtonSkin, and ScrollBarDownButtonSkin), you'll see this MXML fragment:



<!-- arrow -->
<s:Path horizontalCenter="0" verticalCenter="-1" id="arrow"
data="M 3.5 0.0 L 7.0 7.0 L 0.0 7.0 L 3.5 0.0">
<s:fill>
<s:RadialGradient rotation="90" focalPointRatio="1">
<s:GradientEntry id="arrowFill1" color="0" alpha="0.65" />
<s:GradientEntry id="arrowFill2" color="0" alpha="0.8" />
</s:RadialGradient>
</s:fill>
</s:Path>


Now, I don't want that, because I'm drawing some very custom shape in place of this default arrow. So, I omit that MXML fragment, and replace it with a Graphic object, in which I use the new drawing MXML stuff to create a new arrow.



<s:Graphic width="25" height="20">
<s:Path data="M 0 0
L 25 0
L 25 10
L 12.5 20
L 0 10
L 0 0" >

<s:stroke>
<s:SolidColorStroke color="0x29a094"/>
</s:stroke>

<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xFFFFFF" alpha="1"/>
<s:GradientEntry color="0x7ac8c5" alpha="1"/>
</s:LinearGradient>
</s:fill>

</s:Path>
</s:Graphic>


After making the new class with the Graphic element instead of the old "arrow" drawing path one, I applied it to my Spark List component and compiled; new errors. I ran the program though, and it crashed right away. The error was that the "arrow" property could not be found, and there was no default value, etc. So, out of curiosity (and the desire to get the app running), I just added a public var, "arrow" : Object, and again compiled without errors. Running it though caused another error, and then another, because "arrowFill1" and "arrowFill2" were not found, no default value, etc.


So, I had to add these three public vars to my custom class to get the app to run.



// don't remove these, they are placeholders for the wonky "arrow" mxml that isn't needed here.
public var arrow : Object = { };
public var arrowFill1 : uint = 0;
public var arrowFill2 : uint = 0;


After that it worked.


To me, this is broken; as long as the skin class is properly made, it shouldn't need to contain ANYTHING in order to run properly, as long as any necessary interfaces are implemented (a well built API should be interface based). Implementation of functional objects should not be a concern of the skin class. But it is; you have to put in those dummy properties to get this to work.


I circulated this find, and the consensus seemed to be that yes, this should be fixed; there's no reason a required visual object should be in a skin class, circumventing compile time errors and crashing the entire app when it tries to instantiate a skin for a scrollbar. Evidently, more hacking away found that this is the case in a number of Spark skins.


Insurmountable? Nah, just add the public properties to satisfy the Spark parent component demand for whatever it's looking for. But it's wonky and, as far as the consensus of the people I referred the error to, should be addressed by Adobe before the product is released, for the sake of elegance if nothing else.


As always, thanks for visiting.

Labels: , , , , , ,

Thursday, September 17, 2009

Predictable Irrationality: Project Planning by Reverse Engineering a Concrete End Result

This is one of my greatest challenges as a developer. Everybody thinks they know this already. Almost nobody seems to actually practice it. For the most part, this example doesn't use actual technology project examples, but that's deliberate, because oddly, people don't think real life thinking applies to technology project plans.

Anyway, here we go...a client has an idea for a project; they want this fantabulous application that does this, this and this. They qualify you, and hire you. There you are, ready to look over requirements and wireframes, iterate through them, allocate your resources, get some preliminary milestones approved, and create a draft project plan.

The client hands you a few comps; artist renderings of the end result. "That's what I want".

You're a contractor, so of course, you say "erm...have you considered...". Some internal employee that believes he/she has already foreseen the future is annoyed, but concedes, so they rework the comps. You look it over and say, "hmm...but how about errors and alerts...what about some form of tips or help...what will happen if the user does this..." The designer starts to whine, the client gets tired of hearing you say, "have you considered...", and assigns some internal employee to start pushing you to start dev immediately, believing that because they have shown you a snapshot of the end result, that the plan is ready to go.

I want to throw a chair across the room and shout, "EVEN IF YOU SUCCEED, YOU ARE GOING TO FAIL!".

IMHO, it's why most people are accustomed to failure. They don't work towards visions rationally. They get caught up in working around obstacles and situations that prevent them from following the original plan to the concrete end result they want, so they never get there, and abandon the vision; failure ensues. I see people go through this all the time.

Again, you're probably saying, "This is stupid, it's obvious. You have to be flexible, roll with the punches, redirect as necessary". But like a guy I used to work with at American Express used to say, "in practice, common sense ain't so common."

Here's an example; you want to get to California. Somebody sends you a picture of the state and says, create a budget, figure out the wear and tear on the car, and get to work. Oh and btw, it'd be nice to get some pictures along the way.

You say, "well...", the client says, "there's the state, for god's sake you have a picture of it. My internal guy already planned the route, here it is. Get to work."

Well, ok. The route he gave me is N miles, which means Q wear and tear. Ok sir...here's your plan. This is what I'm going to deliver, based on your route. Nice and neat. The client grumbles; it seems more expensive than "his guy" led him to believe, but he accepts the plan. "See? It doesn't have to be so complicated."

Seventy five miles out, there's a detour. It takes you 20 miles out of the way down some other highway. Hey, you're flexible; you redirect as needed...you fight around the detour, take some other roads, and get back to your original plan. You speed up a little to make up the time. Not so bad; a little acceptable risk, but we're ok.

Two hundred miles later, you get a blowout. You're stuck on the road, and have to wait 90 minutes for the AAA guy. You get patched up, but now you're behind schedule. So YOU SPEEEEEEEDDD to make up the time. You may get lucky and make it; you are counting on it. You may get a speeding ticket; you decide to "incur the cost", because you believe it's your fault. You may get into an accident because you are proceeding recklessly. You know it's risky, even stupid; you're risking complete failure, even unrelated personal obligation, but somehow, you feel the whip is justified, because you have to get the plan "back on track".

What about the pictures the client wanted? You take them at 110 mph. The requirement is met, but poorly.

From a project perspective, this is analogous to having your developers work day and night, beyond the point of diminishing returns, because something went wrong. You push them until they just don't care anymore and are ready to quit...or do so. You hire another resource as fast as you can, incur the cost, and crack the whip the second he walks through the door.

All in all, your plan is in the shitter. You are now proceeding by the seat of your pants. Everybody is tense. You've told the client, "just a hiccup, we'll get it back on track." You feel somehow it's your job to "protect" or "insulate" the client from these details. You haven't slept in two days and the scar tissue on the developer's backs makes them numb to the whip. They stop responding, so you push harder.

At this point, getting to the Golden Gate Bridge is a tossup, even unlikely. The budget was blown five states ago. You're way behind schedule for arrival. The client is angry. You're mindset is "too far to turn back now".

If you're lucky, miraculously, you find yourself going over the bridge. It all seems worth it; you shrug and say, "the unexpected occurred, so I failed to deliver the plan, but I did get to CA. I'm hardcore!".

Now the client wants you to come back. Believing he learned what you tried to tell him, but still not really listening, he provides two routes this time, and allocates a little money for repairs and some more time to get back based on how long it took you to get to CA with the originally blown plan. Off you go. Again.

Nothing has really changed.

How would I do it?

"Ok, so, California. When would you like to arrive? Let's propose a route, taking into account it may change drastically based on traffic, detours, etc. Ok, here's my route, and the one you proposed. Here's the good and bad. Either way, if nothing goes wrong, it should take this much time, and this much wear and tear. I can't predict the future though, so let's try to get to this milestone 200 miles away. At that time, I'll call you and report on my progress, and along the way, I'll let you know if I think we're going to encounter any issues, and we'll discuss how to deal with them."

Some scenarios as you try to get to that milestone:

- You make it on, or ahead, of time. No change in plans. Good news.
- You make it, but learn of some condition that will enhance, or complicate, the next milestone. You propose a redirect.
- You make it, but are a little behind schedule. You say that, at this point, unless one of the two above conditions occurs, you will be a day late. See below.
- You make it, or did not make it (accident, etc.), and are so drastically behind schedule that you know the only way to "get back on track" is to be reckless, which incurs risk. You propose abandoning driving and getting to the nearest airport. Regarding the pictures, well, the point was to get to CA. We can figure out the pictures later if you want them; maybe I can get them from Flickr. MAYBE YOU JUST DON'T NEED THEM TO GET TO CA.

Read those scenarios again. If you're a gambler that couldn't afford to lose, would you put your money on good news, or bad?

You're now managing the client's expectations every step of the way; you're communicating effectively. You get a sense of completion at the milestone, you never incurred unnecessary risk or abused resources, and you got the client what he needed; you achieved his vision by abandoning the concrete end result. If he tells you to speed recklessly, you say no. Miraculously, he accepts this. Surprisingly, you work to a new milestone, and the client seems satisfied.

It seems so logical, so easy. But I'm telling you for a fact that almost nobody works this way because people are afraid to tell their clients that they are setting themselves up for failure.

So do yourself, and your client a favor. Be a pro. Don't tell the team to run a pattern you know will probably fail. Work with your client to get them to look at Milestone One as opposed to the concrete end result. Ensure that redirects achieve the core of the vision; recognize what is important, and what isn't, to achieving the vision.

If you want to get to CA, get there safely and rationally. It doesn't matter if you take the bridge...unless the bridge is actually where you want to go. Even then, if you planned to go over it from one direction, but ended up coming the other way, does it matter?

If it does...well, go over it and turn around.

As always, thanks for visiting.

Labels: ,

Wednesday, September 9, 2009

Put an image (or whatever) next to any character in a TextField that wraps and is multiline.

Somebody on the Adobe AZFPUG (Arizona Flex Programmer's User Group) asked today, "I have a TextField that is multiline, and has numerous wrapped lines. I want to be able to put an image RIGHT NEXT to the last character. How?"

Most of the responses were along the lines of "get the x loc of the textfield, and get the width, then get the y loc, and the height, then put the image".

That'll always put it to the lower left of the TextField. It won't put it next to the last (or any) character within the TextField.

I've dealt with this before, and was surprised to see that this person was really having a hard time finding a solution. So I gave her one: Here it is.

If you're not familiar with getCharBoundary ( indexOfChar ), look it up. It can save your life. It returns a rectangle that bounds any character you specify in a text field. A rectangle has an x, y, width, height. So you get the rectangle, do the math as below, and voila...place your display object.


private function doIt ( ) : void
{
// can be anything, movieclip, combobox, image, whatever
var img : Image = new Image ( );
img.source = "timprofile.jpg";

addChild ( img );

_txt = new TextField ( );
_txt.x = 100;
_txt.y = 100;
_txt.multiline = true;
_txt.wordWrap = true;
_txt.width = 200;
_txt.height = 200;
_txt.text = "Hello how are you I am fine ok that's very nice thank you ok let's wrap some text I hope this wraps let's wrap it up nice ok";

rawChildren.addChild ( _txt );

var r : Rectangle = _txt.getCharBoundaries ( _txt.text.length - 1 );

img.x = _txt.x + r.x + r.width;
img.y = _txt.y + r.y;

}


As always, thanks for visiting.

Tuesday, August 11, 2009

(To Unix guy) Yes, it does...Windows Has Symlinks.

This is one really started to irk me lately, so here we go.

Qualifier: I am not a Windows fanboi at all. My primary machines are Macs, with a Windows box for Windows-only games and testing, and a remote one for development (I have two, one Centos, the other Windows Server). However, I am not a Mac fanboi either. The primary reason I own Macs is that in my field, most people work on Macs. Mac is also ruling the roost of UI-think these days, and I'm a UI developer. If and when the wheel turns, depending on the wants and needs of my clients, I will too. The ability to reinvent yourself is what keeps you viable and current; just ask David Bowie or Will I Am.

That said, to all the Unix guys who wave symlinks in the face of the Windows developer:

WINDOWS HAS SYMLINKS. YES IT DOES. THEY ARE CALLED NTFS JUNCTIONS.

I post this because recently, a friend who runs a business got shafted by some PHP developer, who got in over his head, screwed up his site, and suddenly "wasn't available". He got the entire site zipped up and sent it to me. It didn't work when I just dumped it into XAMPP on a Windows dev box I have running; the pages were requesting directories that didn't exist in the file structure I was sent.

I contacted him, and he responded, "what are you running it on", I said, "oh, a Windows box". He said, "you can't do that, the site uses symlinks".

While I understand the "why" of why he did this (easily point at other directories to try other versions), I don't really think it's in the interests of the client (and therefore, isn't a good idea). You can just rename directories to try alternate versions of a codebase. It also defeats the purpose of the whole "can run on anything" mantra; as far as this developer knew, he had tied a basic PHP site to Unix-based OSs, with the thought that, "you shouldn't run Windows". My friend (the business owner) had no knowledge of this decision whatsoever, as far as he knew, PHP ran anywhere, mySQL ran anywhere, the site was portable.

So here's a pro note: don't tie your websites to a particular platform unless you have to, and inform your client if you do, that "you will not be able to move this to Windows", or ".Net is, in practical terms, Windows technology. Your site will not be directly portable, if at all, to Unix/Linux".

Anyway, I responded, "that doesn't matter, Windows has symlinks".

He responded, and I have heard this from people at a particular startup I did some work for not long ago, who considered themselves superior to anybody that touched a Windows machine, "Windows doesn't have symlinks".

And like I said then:

YES IT DOES. THEY ARE CALLED NTFS JUNCTIONS.

So, either get the Windows Server Resource Kit to get the "linkd" tool, or just get the small, free Junction tool that's been around for a few years. If you have either of them though, it's a breeze.

With Junction (which is what I use), it's as easy as:

- Create an empty directory (your "symlink").
- junction c:\path\simlinkname c:\path\actualdirectory.

That's it. There's also commands to inspect directories for symlinks, delete them, and so on.

Note that, as far as I know, symlinks to directories on remote shares are not supported by Windows. This may not be true on the newer server versions, I dunno.

Here's a list to Junction (which I use now instead of moving around the whole Windows Server Resource Kit, which you can look up if you're so inclined):

http://technet.microsoft.com/en-us/sysinternals/bb896768.aspx

Happy Windows symlinking!

Labels: , , ,

Thursday, July 30, 2009

Flex: Masking Images using other remotely loaded images

I had to do this recently, due to their being a very large number of images in the project I'm working on, which needed the backgrounds knocked out; it was easy to generate the masks in an automated way, it was not easy to alter the images to alpha out the backgrounds.

In Flex, they say one display object can work as a mask for another. This is true of course, but for dual remotely loaded images, properly making sure the images are entirely loaded via load.complete events, and so forth, is the key.

The following little technique shows this, code snippet below. This is proving to be quite a timesaver for the team as a whole, since the graphics guys don't have to worry about altering their entire catalog of images. I've already recommended that a back-end process should generate AND apply the masks so that Flash doesn't have to make 2x the requests for images (every image needs a mask): from a performance standpoint this is a bit of a nightmare, but, it's a solution that is moving the project forward and is easy enough on my end to implement.

Note that the images I'm using for masks are not the standard black/white masks you use in photoshop. They are PNG-8s, with everything BUT the shape you want to see alpha'd out, with 8 colors, not converted to sRGB, no metadata, etc. A roughly 400x400 image mask comes in at around 2kb with this profile.

I'm aware this isn't exactly new, and it's documented, but it's solving such a significant problem I figured I'd make it visible. I actually use this code snippet in an itemrenderer, so that I can just chuck an array of objects at a tilelist, and have the item renderer do the two-step loading.

Notice also:

- I'm combining pngs and jpgs, it doesn't matter it's all rendered as bitmaps by the client in the end anyway.
- I'm using a two-step loading chain; it seems you don't have to do this necessarily, but every now and then, it seems to fail if you don't. The two step ensures the mask is ready to go before the image every time.

import mx.controls.Image;
import mx.events.FlexEvent;

private var _mask : Image;
private function onCreationComplete ( event : FlexEvent ) : void
{
_mask = new Image ( );
_mask.cacheAsBitmap = true;
_mask.addEventListener ( Event.COMPLETE, onMaskLoadComplete );
_mask.load ( "images/testmasks/picturemask.png" );
}

private var _img : Image;
private function onMaskLoadComplete ( event : Event ) : void
{
_img = new Image ( );
_img.cacheAsBitmap = true;
_img.addEventListener ( Event.COMPLETE, onImageLoadComplete );
_img.load ( "images/testmasks/picture.jpg" );
}

private function onImageLoadComplete ( event : Event ) : void
{
addChild ( _img );
addChild ( _mask );
_img.mask = _mask;
}


As always, thanks for visiting.

Labels: , , ,

Monday, June 22, 2009

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework - Day 7: Running on the iPhone...really?

This post covers my progress developing a Twitter client using the technologies mentioned in the article title, but also takes another interesting turn. I've been working on the side with Citrix to understand their latest XenApp Server product, and how a Flash/Flex/Air developer might be able to leverage it. To this end, I decided to branch my Air code base, and use what I've already done to drive forward a version of TcozTwitter that could be delivered on the iPhone...or any mobile device for that matter.

Notice I said “branch”, not “start all over again with a different technology”, and “any mobile device”, not just “iPhone”. Those are the important things to get here. More on that in a minute.

If you're interested in the history, links to all the previous blog articles are at the end of the article.

To summarize, here's the “thin line” of technologies you'll need to be familiar with, if you want more detailed summaries, look at the links at the bottom of this article:

Amazon EC2 Cloud and S3. EC2 is essentially a vast pool of processing power that you can isolate a piece of to run whatever you need. I frequently liken it to a ball of clay; you grab a chunk and shape it the way you want; when you're done, you take a snapshot of the configuration (so that you can “restart” it from where you left off), and put the chunk back on the bigger ball. S3 is “Simple Storage Service”. It's basically a huge pool of storage space that you can access via an API or one of many downloadable clients. When you take your “snapshot” of your “chunk” (or in EC2 parlance, when you “bundle” your “instance” into an “AMI”), the AMI is saved to a “bucket” (essentially a directory) that you've previously created in S3. When you “restart” your instance, you point to the configuration file that gets stored with your AMI data, fire it up, and there ya go.
XenApp Server and Desktop. There's a lot to this technology, but I'm focusing on the iPhone-tweaked version of the product, which you can read about here. Briefly, XenApp and Desktop are server-side software that “virtualizes” applications and allows you to view them over a variety of different clients. You install whatever app on a server—any technology that the server supports is fine—then “publish” it via the XenApp software so that it can be accessed remotely by Citrix Viewer and Receiver clients. Citrix has published an AMI in the EC2 cloud that you can use to experiment with. Remember, an AMI is a saved configuration, ready to go. All you need to do is go the cloud, fire it up, install your app, publish it, and remote clients can access and run it. The Citrix XenApp AMI is a demo that times out in three months; plenty of time to learn your way around.
Flex/Air, and Mate. Flex is an ActionScript 3 component framework used to build applications that run in the Flash player, Mate is a Flex-specific framework, heavily leveraging MXML, to simplify and organize building applications with Flex and ActionScript 3. I'm using Mate purely to familiarize myself with it. I'll say this; compared to other frameworks, it's pretty easy to get your head around, and it does simplify a lot of tasks. I have some concerns, but that's true of any prescribed development approach.
The iPhone. Enough said about that I think, and then some.

You'd be surprised, once you know exactly how it all works, how easy it is to set this all up and get basic applications working. I can publish an app, or an app update in a matter of minutes.

Here's some screenshots of my Twitter client, running on the iPhone, using all the above mentioned technologies:








It really works, even over EDGE on an OG iPhone (as I write this article, I'm actually expecting the delivery guy with my new 3GS 32mb Black. UPDATE, I have the new iPhone, and the Citrix stuff runs great over the 3G network). I leave it up and running on my iPhone while it's docked to see my tweets come in without any page refreshes and whatnot.

I also have to say, Citrix' luminaries Chris Fleck and Ray Yang have been great. When I started my experiments, I pinged them with a few questions, and they've been supporting my efforts with tech info and advice ever since, because they're interested in my perspective on these technologies.

It's that perspective that, perhaps, makes this all interesting, so much so that TechCrunch published a story on my findings that stayed on the front page of their site for weeks and sparked a lot of debate, mostly revolving around “There's no need for Flash on the iPhone,” and “why don't you just build a native app”. Flash is a great candidate for building mobile apps. The industry just seems to have a variety of issues that prevent it from getting out there on mobile devices, and I have good reason to believe they're not primarily technical ones.

Anyways, I'm an independent developer; in a nutshell, that means I go from contract to contract, building various kinds of applications for various kinds of clients of all sizes. I've worked for Microsoft, Viacom, Thomson Reuters, IAG Research, American Express, CitiGroup, IEEE/Spectrum, and a slew of smaller shops and startups. I'm pretty proud of my portfolio, and I work hard to stay cutting edge; I run servers to host all kinds of development environments and server software, like Flash Media Server, TomCat, BEA WebLogic, MAMP, Red5, Blaze, Ruby/Rails, .Net, Air, SVN, FTP, mySQL, SQL Server, Oracle Comm. Edition, etc. etc.

It's a lot of work, and isn't cheap; sure I write it off, but I have to do the cash layout, and admin/maintain them. IMHO, it's necessary; a good independent developer should know how to put together a good development and staging environment in just about any technology.

So, enter the Amazon EC2 cloud. Now, I can spin up instances of virtually any kind of development environment...install this and that software/app/etc...save the configs and shut them down...for about 10 cents an hour. After doing the math, that works out to about half what I pay now for a fully dedicated hosted box at a solid host company, and that's only if I leave it up and running 24/7. It's WAY flexible. For staging and development testing, it's fantastic.

However, most of what I do for a living involves Flash development. I love the iPhone and have learned Objective C, got my business accepted into the dev program—it turned out to be more than a matter of just paying for it to my surprise—and so on. But I've been working with Flash for a decade, and it's a big disappointment that Flash doesn't run on it.

Enter XenApps, which Citrix makes available as a demo AMI config in the EC2 cloud. All I have to do is select the AMI, launch it, and I'm looking at a clean build of Windows Server 2k3 with XenApps, Desktop, and all that; everything I need to work with to see if I can deliver a Flash/Flex/Air application to an iPhone.

I settled on Air, mostly due to the fact that Air doesn't deal with browser security and sandboxes the way that Flash/Flex do; Air is a native runtime, with it's own encrypted data store and access to NativeWindow and other elements that make it a fairly powerful RIA desktop development environment. Crossdomain and such isn't a hassle as well. You can also publish an Air app (which, on Windows, is an .exe) in a very straightforward way from the XenApp environment, as opposed to using AppViewer, which is a .Net app Citrix distributes that you run in lieu of your actual SWF by pointing it at the web page that embeds it. It works and works well, but I figured why bother with web pages and such if I can just run my Flash app in a native runtime environment without the involvement of the browser footprint.

The connection should be evident; there I was developing a Twitter client in Flex Builder, and publishing it to Air, using the Mate framework. So I decided to marry the two efforts, and see if I could branch my slowly developing Twitter app—it's hard to find spare time, but I fit it in now and then—and see if I could tweak it for delivery to the iPhone via XenApps.

Yay verily, it worked; I installed the Air runtime on the Windows instance, installed my Air TcozTwitter client, published it through the XenApps server, and pointed the iPhone Citrix Receiver at it, and there it was, touch enabled and all. True, I had to rethink the UI in terms of the iPhone. I've had people say that Flash apps won't port directly to the iPhone because they use mouseovers and such—think about it, the iPhone doesn't have “fingerovers”, which is interesting—but that's true of any technology no matter what. As a UI developer, you have to look at the device, consider the interactivity, and develop your app, using your given technology, in that context. If you factor your code well and the UI is truly abstracted, this isn't that big a deal though at all, certainly a heck of a lot less work than writing the whole thing all over again in Objective C...and then Symbian...and then Android...and then Windows Mobile...and then Blackberry...and whatever else winds up getting cranked out of BigTech Labs XYZ.

Here's points I found to be VERY interesting about this manner of development:

I'm not an “enterprise”, I'm an independent developer. But, I don't just write code for clients, I build things off to the side to keeps my chops fresh and who knows, maybe make some money. I find that this technology, although created by Citrix which is typically associated with “enterprise”, works for me. The Citrix guys seemed to find that interesting too. A library of demo apps that I can bang off a single EC2 instance is also a powerful demo tool for landing contracts. As I mentioned once before, I could probably get work just by having put all this together.
With just UI refactors, I can roll out the same codebase to any mobile device that Citrix has written a Receiver for. They've covered a number of them, see their website for more info.
The XenApps “tweaked” version I'm working with, via the Receiver, presents your apps as a selectable library; so, the user downloads ONE app (the phone-specific Receiver), and they can access ALL the apps that I publish though XenApps.
Consider the above...all I have to do, to deploy a new app to my entire userbase, or update one, is install it on my EC2 instances, which you access via RDP or the Citrix Receiver desktop app (I use the Mac version). No app store approval iterations. It'll be interesting to see how this shakes out.
Because the app runs on a regular server, I don't have the development restrictions inherent on the iPhone. I can make any number of network connections of any kind, store data in a variety of ways locally, and whatever else I need to do. The available technology I can use to drive my apps is essentially unlimited.
For proving out concepts and getting user reactions, this can't be beat. I can build apps rapidly in one codebase, get them deployed to all kinds of devices, and see what users think. What hits on a Symbian may not hit on an iPhone. Depending on the reaction, I can decide to build a native app, or abandon the effort for a given platform.

There are some things I have yet to figure out, the Citrix guys say they are interested in helping me find solutions:

Encrypted data store in the Air runtime is having some issues; I believe these are probably related to the permissions that XenApp is using to run apps under; some server config will probably solve this, if not, I can always just dump everything to a SQL DB or some such.
iPhone mechanisms, like the auto-complete for text, the new cut 'n paste, and such, don't work, because the app isn't actually running on the phone. Fixable, because I can just build the capability into the application, and just make sure I emulate the iPhone look 'n feel. The investment of time can in fact give me the same look and feel consistently across any device...nice for my end users on different platforms, and of course very useful looking forward to things like NetBooks and touchscreen e-readers.

Will I abandon building native apps for the iPhone, and whatever else I find the time to learn how to build apps for? Of course not. There's money to made out there, and different development technologies is something I'm interested in. So, the Objective C book and Xcode will still take up space on my hard drive, and be frequently used.

But, if I work with a client that needs apps rapidly deployed to a variety of devices, without going through the rigor of building multiple versions and maintaing multiple code trees, will I be glad that I learned how to do this...and, will I continue to ensure that apps I build are constructed in such a way where I can branch and get a version running on the iPhone this way in relatively little-to-no time?

You bet. Citrix has most definitely found a place in this independent developer's toolbox.

I wonder how many other contract Flash developers have said that.

As always, thanks for visiting.

Article Links:

TcozTwitter: A Twitter Client using Adobe Air and the Flex Mate Framework: Day 1, Day 2, Day 3, Day 4, Day 5, and Day 6.

Flash/Flex...on the iPhone? Initial Exploration, Follow up with Citrix.

Why the Amazon EC2 Could and S3 is a great thing for the independent developer, Article Link

Labels: , , , , , , , , , , , ,