Barcamp/FOWA Miami 2009

February 26th, 2009

I had a great time at FOWA and Barcamp. I met a lot of people, saw some awesome presentations and demos, drank more in 3 days than I usually do in 3 months, and generally had a great time running around Miami with my Grooveshark peeps (@skylerslade, @boxmonkey, @hotspacejustice, @vishalagarwala, and @efuquen).

I’m still pretty beat (Gainesville/Miami - long drive, but *way* too close to justify flying), so here’s a quick rundown on my experiences:

Thoughts on presentations in general:

Know your audience:
This paragraph particularly applies to some of the BarCamp talks, since BarCamp tends to be more targeted at dev-types and FOWA has a broader scope. You need to know your audience. The same sorts of things that will make money- and marketing-types drool in excitement can send geeky dev-types reeling in horror. Example: data collection/information selling vs privacy issues. This came up in a few places, but none so glaring as the Mozilla Add-ons talk at BarCamp. Is the Mozilla Foundation really encouraging us to use our add-ons to track user behavior across multiple sites (not just interactions with your own product) in order to sell this information later as an monetization scheme? If not, then they need to take a hard look at how they’re presenting this stuff, cause that’s certainly one of the messages I took away from the talk.

Decent slides:
I know not everyone is a designer. I’m certainly not. But if in doubt, keep it simple. I’d rather see plain black text/white background slides that are easy to read than colorful low-contrast slides that are impossible to read on a projector. I’d rather see a short list of big bullet points than a hugely complicated graph that requires to the text to be tiny (and once again impossible to read on a projector) to fit. I guess basically what I’m saying is, projectors can be finicky and often wash out color and in a large presentation, some of your audience is far away. Just keep it in mind.

So now some specifics. Honestly I had almost zero sleep going into BarCamp and it’s all mostly blended together now. So most of this is FOWA related.

Ubiquity:
We saw a brief mention of this in the Mozilla Add-on talk at BarCamp. My first impression was kinda, “Eh, looks vaguely like Quicksilver for Firefox, but I could probably either do/script those things for actual Quicksilver if I really wanted them anyway. Wake me when Firefox stops using 50-70% of my cpu all day, and it might actually be useful.” After seeing the demo at FOWA though, I’m more like “Wow, it looks vaguely like Quicksilver for Firefox! This could make my browsing as seamlessly awesome as the actual QS makes my OS!” The demo certainly seemed pretty snappy, though I haven’t gotten the chance to try it out personally yet. For me, it’s ultimately going to depend on if it grinds my browser to a halt whenever I use it or not. I have enough performance problems with Firefox on my little G4 iBook as it is.

Jason Fried:
I think saying that the culture of free is ultimately harmful is sensationalistic, and I definitely do not agree. Neither do I think that everything should be free. Like most great questions, the answer is somewhere in the middle. Some services should be free, subsidized in some other manner. Some services should cost money, and if they do what people need, they will gladly pay for it. Deciding which category your product fits into? Well that’s the hard part.

Also, do that many people actually think that “Fail early, fail often” was meant to be applied to business models? I’ve always considered it to be more applied to actual code creation - ie, rapid prototyping to try out ideas so they can be thrown away with minimal loss if they suck.

I do agree with his thoughts on flow and the productivity-killing nature of interruption.

Multiple projects are harder to maintain? Um, yes? That nearly seems a tautology.

Dion Almar and Ben Galbraith:
Nifty presentation, though I think HTML5 is still a few years from having enough penetration to be viable for real products. Magic IE compatibillity wrappers sound like a great idea on the surface, but will your users install them? (I’m totally biased, but) Flash already has 99% penetration. And as long as Youtube requires Flash, I’m not too worried about that changing.

I would have liked to see more about newer Javascript interpreters and just why they are so much awesomer and faster than current JS. They just sorta skimmed over that part with a ‘well it’s a bottleneck right now but soon it won’t be’.

Adobe AIR love, but still no love for Flash. I know they’re pushing HTML5, but I really felt like they were just pretending Flash didn’t even exist during this whole presentation.

Dan Theurer
Ugh, first incidence of epic slide FAIL. I felt really bad for him. YQL sounds like a really nifty concept that I’m going to have to look into, though I really hope it doesn’t wind up like SOAP (Awesome concept that just winds up being bulky and inflexible in real life).

Kristina Halvorson:
Grooveshark could definitely use more process for coming up with copy. Right now it’s all by the seat of our pants, and some extra care and consistency could make a huge difference in the user experience. Really cool talk.

I have a lot more to say about women in tech, but that’s going to have to be a whole other post - look for it in a day or two once I’ve gotten all my thoughts collected.

Dave Morin:
Eh, I don’t know. Facebook Connect really doesn’t excite me that much. We’ll see how it takes off.

Joel Spolsky:
This was why I came to FOWA. Joel is one of my heroes. Talent-based model = Yes. Importance of not killing flow = YES. Desire to someday work for Joel = all-time high.

Alex Hunter:
Certainly the prettiest presentation, slide-wise. I’m not sold on the company-specific social network thing, but I’m also not Virgin’s target audience, so I wish them luck.

Fransisco Tolmasky:
I’d heard about Objective-J and Cappuccino in passing before, and had mentally filed it away as something interesting to take a look at someday when I had some time. But WOW, that Atlas demo just blew everyone away. If it’s really as awesome as it looks, Atlas combined with faster Javascript engines might actually get me worried about the future of Flex. Definitely going to keep an eye on this.

Spolsky/Fried interview:
I wish it had been longer.

Gary Vaynerchuk
I don’t know what to say. Gary was awesome. “If you don’t know where you want to end up, you’re broken.” I’ve got some thinking to do on that one. I definitely know my passion, but I don’t know where I want it to take me.

Parties:
The Abbey (especially) was great. I’m a huge beer fan (despite a hops allergy that sadly limits my options unless I’m willing to risk a really uncomfortable face rash that lasts like 3-5 days). At all the various parties, I really enjoyed meeting so many new people, and catching up with people I haven’t seen in a while. I’m a real lightweight when it comes to alcohol, so to all the random women I accosted and drunkenly explained my mission to find another female coder at the event, I apologize. I never did manage to meet one.

And on that note, I am exhausted and this post is really long. Look for another post about women in tech (and my failure to find any fellow girl-coders at the bars) sometime in the next couple days.

Here at Grooveshark, we’re using SWFAddress for deep linking/browser history support in our flagship product.

It’s been working great, except for one of our developers on Arch Linux using Gran Paradiso. We hadn’t been getting any user complaints, so that particular bug pretty much fell to the bottom of the stack. Until a few days ago, when we started get the same complaint from users on Debian/Iceweasel.

Now, since SWFAddress says that it officially supports Firefox v1 and up, I had pretty much assumed it would work fine on all Gecko browsers. In fact, since Iceweasel technically *is* Firefox (and wow, is the history behind *that* an interesting tale), there shouldn’t have been any reason for it to fail.

So off I went to poke about in the SWFAddress source, where I found that Firefox detection is made by matching the string ‘Firefox’ in the user-agent string. Also, when SWFAddress cannot identify the browser, it will refresh the page with the hash removed, which is probably a great fallback for a lot of Flash/Ajax sites, but winds up causing some problems for us.

Well Iceweasel doesn’t have ‘Firefox’ in it’s user agent string. It has ‘Iceweasel’ instead. Same with Gran Paradiso. So, I’ve written a patch for SWFAddress to fix the problem. If SWFAddress doesn’t match either Firefox or Camino (the two Gecko browsers that it officially supports), it will fall back on navigator.product to detect any other Gecko browser, regardless of what it calls itself in its user-agent string.

We’ve got it up live on http://listen.grooveshark.com now, and it seems to be working fine.

I’m going to email asual to see if it can get added to the actual trunk, but in the meantime, if you’re using SWFAddress and would like to use my patch, you can grab it here SWFAddress Gecko Patch.

Just check out the SWFAddress trunk at https://swfaddress.svn.sourceforge.net/svnroot/swfaddress/trunk. I wrote the patch off of Revision 702.

EDIT
So my first version of this didn’t work in Chrome/Safari. Apparently WebKit reports its navigator.product as “Gecko” despite the fact that it’s, you know, WEBKIT. I’ve uploaded a new version of the patch, so if you grabbed it before 11:20 am eastern on Feb 4, grab it again for the fix.

So we finally tracked down just how Jay broke Grooveshark Lite the other day.

He apparently managed to trigger a very obscure language bug, that no one has really posted about, though if you dig deep enough into Adobe’s bug tracking system, you can find some reports of, though it’s supposedly fixed as of some version of the compiler that I have no idea if it’s in production yet.

This is all it takes to break Actionscript with a nasty runtime error:


private function breakIt():void
{
    var arr:Array = [];
    for each (var obj:Object in arr) {
        switch ('s') {
            case 's':
                if (null) {
                }
            //break;
        }
    }
}

The key here is the nested for/switch/if and that the expression for the if statement evaluates to false, and that there is nothing in the case after the if.

Uncommenting the commented break statement will prevent the bug. Even a variable declaration on that line will prevent the bug. Removing the switch from inside the for loop will prevent the bug. Notice in this case the loop shouldn’t even be executing: the array is empty. Doesn’t matter, it crashes anyway.

The runtime error this triggers is “VerifyError: Error #1068: CLASSNAME and CLASSNAME cannot be reconciled.” where CLASSNAME is the name of the class that contains the above code.

So if you’re getting the above error in your code, check around for any constructs like the above.

Consider this situation:

You have an MXML component with multiple states. Each of these states has an associated error state that’s based on one of the other states. The overrides for each of the error states is identical - all that’s different is which state each error state is based on. Instead of duplicating the overrides for each error state, you can declare the overrides in an <mx:Array> tag, and use data binding to set the overrides property of each error state to the same array.

Alright, talking about this abstractly is kinda confusing. It will make perfect sense as soon as you see an example:

<mx:Array id="errorOverrides">
    <mx:AddChild relativeTo="{msgWrapper}">
        <mx:Label text="The following errors occurred:" styleName="popupMessageError"/>
    </mx:AddChild>
    <mx:AddChild relativeTo="{msgWrapper}">
        <mx:VBox paddingLeft="15">
            <mx:Repeater id="errorRepeater" dataProvider="{errors}" recycleChildren="true">
                <mx:Text width="{msgWrapper.width-45}" text="{errorRepeater.currentItem}"/>
            </mx:Repeater>
        </mx:VBox>
    </mx:AddChild>
</mx:Array>

<states>
    <mx:State name="twitterBroadcast">
        <mx:SetProperty target="{this}" name="bodyContent" value="{twitterBroadcastBodyContent}"/>
        <mx:SetProperty target="{this}" name="title" value="Broadcast to Twitter"/>
    </mx:State>

    <mx:State name="facebookBroadcast">
        <mx:SetProperty target="{this}" name="bodyContent" value="{facebookBroadcastBodyContent}"/>
        <mx:SetProperty target="{this}" name="title" value="Broadcast to Facebook"/>
    </mx:State>

    <mx:State name="shareError" overrides="{errorOverrides}"/>
    <mx:State name="twitterError" basedOn="twitterBroadcast" overrides="{errorOverrides}"/>
    <mx:State name="facebookError" basedOn="facebookBroadcast" overrides="{errorOverrides}"/>
</states>

This solution seems obvious as soon as you think about how you would go about declaring these states in Actionscript, but in MXML it’s really easy to feel like you would need to declare the overrides over again inside each <mx:State> tag.

Maybe I’m late to the party and everyone else figured this out already, but if not, hopefully this post will help you think about MXML in a new way.

The devil’s in the details…

November 10th, 2008

…says Chris of Grooveshark’s rather disappointing entry for the “Bug of the Beast”:

Bug 666

So one of my bug reports this week was that Lite took an insanely long time to populate the list of playlists when you clicked the “Add to Playlist” button on a song’s info panel. We’re talking like, click the button, lightbox opens, 4-5 seconds later your playlists appear. This was happening even for accounts with a small number of playlists.

At first I thought it must be something with the service call to the backend to fetch the list of playlists, but it was returning long before the list rendered.

So then I thought perhaps it was the class I wrote for paging lists of stuff from the backend, but no, parsing the data wasn’t taking that long either.

So I went to make sure I hadn’t done anything silly in the view, like, manually removed and replaced all the children in the box every time the list changed instead of just using a Repeater. But no, I was using a Repeater. Jay says, “What’s this recycleChildren property on the Repeater class?”

I said, “That shouldn’t matter, this is the first time that Repeater’s been rendered. There’s no children created yet *to* recycle. But I guess I’ll set it true anyway.”

And sure enough, now it renders in more like 1 second, as opposed to 4-5. I understand how recycleChildren increases performance when the data in the dataProvider changes. I think it’s silly that it defaults to false - I’d think that most common uses of the Repeater class would benefit from defaulting to true, and if you have a case where you need it false, then you can specify. But I still don’t understand how it’s faster when it’s the first time it’s created any children at all.

So if your Repeaters are slow - set recycleChildren to true!

And if anyone can give some insight into how it’s faster even on the initial creation of the component, let me know. I’m curious.

And for you Grooveshark Lite fans - that change is live, so if you were frustrated by long lag times on the “Add to Playlist” lightbox, the “Share” lightbox, or on opening a playlist or song info panel, it should be much better now.

Just found this today, and thought it was really interesting:

Syntax Comparison of Java 5 and Actionscript 3

A couple weeks ago I needed to easily convert HTML entities in a string back to their normal representation, but I didn’t really find anything nice, and wound up just using str.replace(/&/g, "&").replace(/'/g, "'"); since those were the only characters I was having a problem with at the time.

But today I went searching again for something better, and found a really great way to escape and unescape HTML entities. Not sure why I didn’t find his post the first time, I guess my Google-fu was weak that day.

Anyway, I’ve wrapped his methods up in a little helper class, and it works great:

package com.grooveshark.utils
{

    public class HTMLEntityUtils
    {
        import flash.xml.XMLDocument;
        import flash.xml.XMLNode;
        import flash.xml.XMLNodeType;

        public function HTMLEntityUtils()
        {
        }

        public static function htmlEscape(str:String):String
        {
            return XML(new XMLNode(XMLNodeType.TEXT_NODE, str)).toXMLString();
        }

        public static function htmlUnescape(str:String):String
        {
            return new XMLDocument(str).firstChild.nodeValue;
        }
    }
}

Hope it helps someone else!

Welcome to Grooveshark Lite!

April 15th, 2008

Grooveshark Lite is now officially live.

Grooveshark Lite takes all the long-tail P2P musical goodness of Grooveshark.com and distills it in a handy quick interface to find and listen to whatever you want. Unlike the main Grooveshark site, you don’t have to have an account or install our Sharkbyte client in order to listen to music. However, signing up for an account (it’s super easy!) allows you to save playlists, and your login will work for both Lite and the main Grooveshark site.

We’re hoping that you’ll find Grooveshark Lite to be the easiest way to listen to whatever you can think of.

We have tons of things planned that didn’t quite make it into this iteration, so keep an eye out for exciting new features over the next few weeks. And if you have any comments, suggestions, ideas, wishlists, problems, or just want to say hi, drop us an email at feedback@grooveshark.com. Or you can leave me a comment here and I’ll do my best to answer you personally.

We just upgraded a few other systems at the same time, so if things are a little shaky, just give us a little time and things ought to smooth out.

I’d love to talk more about Grooveshark Lite, but I’ve been here at the office for over 18 hours straight now, trying to make sure my baby gets off the ground right, so I’m not entirely lucid anymore.

Enjoy the music!

Flex and Fonts

April 15th, 2008

This was extremely frustrating, so I’m posting in the hopes that I can save others the same frustration.

So as you may know from my recent posts, I’ve been working on a huge Flex app for Grooveshark. We’re getting ready to launch it (probably in the next few hours actually), and our lead designer John and I were going through the app for some final visual tweaks. Button labels and input boxes were lovingly pushed a pixel here, a pixel there, until they looked just right.

Then we saw the app on Linux. It looked HORRIBLE. Half the text was far too low. You couldn’t even see the tails on letters like ‘g’ and ‘y’. Suspicious, we checked it on a Windows machine. The text was also lower than on my Mac, though not as bad as on Linux. Windows only was only lower by about 4 pixels, Linux more like 10-15. I was baffled. Flash is Flash is Flash, right? The font was an embedded OpenType version of Helvetica that we bought just for this purpose. Why would the font render differently depending on the operating system?

I read about Flash’s different font managers, and thought perhaps the issue was that using an OpenType font forces the use of the AFEFontManager instead of the BatikFontManager. So I tried embedding a TrueType font instead, but it made no difference. The text was still just as skewed in Linux and Windows as it was before.

Eventually I found this blog post and decided that embedding the font via SWF was worth a try. I had originally decided to embed via a font file instead of swf because swf seemed to add more bulk to the compiled app, and honestly, this app is already huge.

Anyway, I embedded Helvetica via SWF instead of OpenType, and it worked! The application now renders identically cross-platform. So if anyone else out there is having trouble with cross-platform font rendering in Flex, try embedding your fonts via SWF.