RSS
 

Archive for the ‘Uncategorized’ Category

However you succeed, you will die

13 Aug

Mark Cuban recently wrote an article titled When you succeed with Free, you are going to die by Free.

Lets look at the rule that eventually KILLS all freemium based content plays:

There will always be a company that replaces you. At some point your BlackSwan competitor will appear and they will kick your ass. Their product will be better or more interesting or just better marketed than yours, and it also will be free. They will be Facebook to your Myspace, or Myspace to your Friendster or Google to your Yahoo. You get the point. Someone out there with a better idea will raise a bunch of money, give it away for free, build scale and charge less to reach the audience. Or will be differentiated enough, and important enough to the audience to maybe even charge more. Who knows. But they will kick your ass and you will be in trouble.

What’s the difference in this equation between free and non-free services? Does being non-free insulate one from competition?

Let’s imagine a world where search isn’t free. Google search is so good that they have killed off all of their competitors, and they decide to start charging $5 a month for everyone to use it. People pay because hey, Google always finds what they want and what else can they do? In this very imaginary scenario, Google’s black swan would be any other remotely decent search technology provided that it is offered for free. The point of this extreme example is that Google is more insulated from competition by already being free, so the above argument is silly.

The rest of the article goes on to say that no matter what type of service you offer, you should be on the lookout for your black swan and when it arrives, assuming you can’t purchase it, you should take all the money you’ve earned and run, rather than stay and fight an expensive losing battle. (I’m oversimplifying quite a bit, mostly because this isn’t the part that I care about)

That’s…fine, although I don’t necessarily agree on that point either, but Mark attacks some of the commenters in his blog for picking on the “free” aspect of his blog post like I am doing here because they miss the point at the end about how cutting and running. Perhaps if he had stuck with his original intended title “The Freemium Company Lifecycle Challenge” he wouldn’t have caught so many peoples attention and it would have just blown over. But if he really didn’t want these disputes popping up, a better title would have been “Everyone has a Black Swan, the trick is recognizing and reacting,” or something, you know, actually related to the true premise of the article. ;)

 
 

Not giving you the password

06 Jul

Raymond Chen’s post about passwords reminded me of a humorous* java exception I frequently experience when trying to do something in the Palm Pre developer section:

java.lang.UnsupportedOperationException: Not giving you the password
com.atlassian.crowd.integration.acegi.user.CrowdUserDetails.getPassword(CrowdUserDetails.java:52)
org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices.makeTokenSignature(TokenBasedRememberMeServices.java:285)
org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices.autoLogin(TokenBasedRememberMeServices.java:240)
org.acegisecurity.ui.rememberme.RememberMeProcessingFilter.doFilter(RememberMeProcessingFilter.java:104)
org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
org.acegisecurity.ui.AbstractProcessingFilter.doFilter(AbstractProcessingFilter.java:271)
org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
org.acegisecurity.context.HttpSessionContextIntegrationFilter.doFilter(HttpSessionContextIntegrationFilter.java:249)
org.acegisecurity.util.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:275)
org.acegisecurity.util.FilterChainProxy.doFilter(FilterChainProxy.java:149)
org.acegisecurity.util.FilterToBeanProxy.doFilter(FilterToBeanProxy.java:98)
com.jivesoftware.community.web.filter.ApplicationStateFilter.doFilter(ApplicationStateFilter.java:112)

“not giving you the password” — not only is this phrase funny as an exception, but it clearly looks like someone is doing it wrong. No, you shouldn’t be requesting the actual password in order to get a “remember me” type token. Of course, they’re doing a lot of other things wrong too, like showing this error to the user, and apparently not alerting themselves to the error, as I’ve been getting it off and on for several weeks at least.

*and, yes, annoying when I’m trying to actually accomplish something

 
 

Grooveshark has outgrown Gainesville

04 May

We have just about completed moving all of our servers from Gainesville to Colo5 in Jacksonville. Why did we have to move? Bandwidth! We simply could not get a fat enough tube to handle all of your music streaming demands into Gainesville. Why Jacksonville? Because it’s cheap, and close! We were considering moving to a similar facility in Atlanta, but Colo5 came in cheaper, while offering the same sort of bandwidth that we could expect to get in Atlanta. How much bandwidth? We should have room to grow up to about 20Gbps before we will have to consider expanding to other facilities. We’re going to need a lot more servers before that can happen.

Although we now have plenty of bandwidth for the near to mid-term future, there are still plenty of other bottlenecks that are starting to pinch us, so don’t be surprised if playback is still laggy sometimes or results to buffering. The next big improvement we need to make is the “bandwidth” we get from our disks. No point having 20GBps of headroom in the tube if we can’t actually get that much off of our servers. We have several strategies we are applying to this end, and I may post more about them later if I have time.

The transition from Gainesville to Jacksonville was, of course, not as smooth as we had hoped. Everything was going along swimmingly until we went to install our crappy “downtime server” in Gainesville to let users know that we were down and why, while allowing us to take the real web servers with us. The server and router simply would not acknowledge each other’s presence. Our laptops could connect directly to either one just fine, but both thought they had no connection when interfacing directly. The solution? A crappy old Linksys hub, which both the router and server were able to see.

Loading up all of our servers containing all of our data into a UHaul was more than a little scary, but we packed everything very carefully using lots of cardboard, furniture blankets and rope. Not a single server was harmed in the moving process!

Ben got a lot of pictures of the whole event, if you’d like to see more. Big thanks to Ed, Skyler, Joe, Colin and Nate for all working so hard to make the transition as quick and painless as possible, and thanks to Paloma for driving us home and letting us sleep on the way back; we were definitely in no shape to drive after all that.

 
 

Washington

30 Apr

The following song has infected my brain: Clementine by Washington

 
 

Goodbye xampp, hello Portable Ubuntu

16 Apr

For a long time now I’ve used xampp for testing my scripts locally before committing to the codebase and testing in our dev environment. Apache for windows, at least in this configuration, was incredibly unstable: major memory leaks, and it crashed if it received two connections at once. It has been good enough for rudimentary testing, but always a bit annoying. The memory leak issue caused me to shut down apache as soon as I was done testing any script.

I recently discovered Portable Ubuntu or pubuntu for short, which allows you to run ubuntu inside of Windows (yes, I still prefer windows as my desktop environment). I set up apache and php inside of pubuntu, and after following this suggestion (with my own hacks to make it work over the network: see thread), and pointing apache to the mount point for my workspace (also living in windows), everything is working quite smoothly. Apache is both more stable and faster. Ironically, pubuntu with apache running inside of it is more lightweight than the Apache for Windows distribution that came with xampp was for me.

What’s especially cool is that because of the way pubuntu mounts drives, pubuntu is seamlessly accessing my workspace to serve up files. That means I can edit a php file in my windows IDE of choice (notably not Vim), and that change is immediately reflected in pubuntu with no effort on my part.

 
 

Back from FOWA Miami

26 Feb

Several of us Grooveshark developers went down to FOWA Miami this year (and Barcamp Miami too!), which was a fun and educational experience. We got to see my personal hero Joel Spolsky, whom Katy and I briefly met after his talk, and we got to learn about some cool new and upcoming technologies.

There were also, of course, some great pre and post conference parties, so we got to meet lots of cool people and network.

Aside from meeting Joel Spolsky, my favorite experience of the entire trip was being accosted by fans of Grooveshark several times over the course of the weekend. It’s really incredibly gratifying to know that Grooveshark has fans, and they’re real people!

Over the next week or so, if I’m not too lazy, I will be posting my thoughts on the FOWA talks, and about some of the conversations I had while I was there, so stay tuned.

 
 

Serpentine by Chris Bathgate

03 Feb

 
 

Sharing Firefox and Thunderbird profiles across a dual-boot

18 Jan

I’m currently trying to see if WinXP x64 will meet all of my hardware and software compatability needs so that I can fully utilize the 4GB of RAM I got for Christmas, so I am dual-booting between XP x32 and x64, with each install on a different drive. I set up Firefox and Thunderbird, but wanted access to my settings and more importantly, my saved passwords that I have configured on the x32 install.

I could have just copied the profiles over, but the profiles won’t stay in sync without a considerable amount of effort, if I am constantly switching back and forth. What if I bookmark something in x64? When I run FireFox on x32, I want that to show up in my bookmarks. Same goes for my extensions and any other settings. Turns out, it’s not very difficult to do, but it does take a little bit of work:

First boot into the newer of the two installs. In my case that’s XP x64.

Get ntfslink, a handy shell extension that lets you create and manage hard links and junction points through explorer. What we care about is the ability to create a junction point, which you can read about if you are truly interested. The general idea is that a junction point acts like a sort of shortcut, but it makes it look like the thing your shortcut is pointing to is actually there.

Find your original profile. Something like c:\Documents and Settings\username\Application Data\Mozilla\Firefox\profiles\somestring.default
Your new firefox appdata should be pretty similar. In my case it’s exactly the same except with the drive letter d: instead of c:, because that’s where I installed x64.

In d:\Documents and Settings\username\Application Data\Mozilla\Firefox\profiles\ (or wherever your newer OS install lives) create a NTFS junction point to c:\Documents and Settings\username\Application Data\Mozilla\Firefox\profiles\somestring.default (or wherever your older OS install lives) by navigating to the new profile directory, right-clicking in a blank space, and choosing New | NTFS Junction Point. Ntfslink names your junction “link to somestring.default” by default. Rename that to just somestring.default for simplicity.

For completeness, you should do the same thing between d:\Documents and Settings\username\Local Settings\Application Data\Mozilla\Firefox\profiles\ and c:\Documents and Settings\username\Local Settings\Application Data\Mozilla\Firefox\profiles\somestring.default

In d:\Documents and Settings\username\Application Data\Mozilla\Firefox\profiles\profiles.ini you should see something like this:
[Profile0]
Name=default
IsRelative=1
Path=Profiles/25wwypw7.default
Default=1

Copy that and paste it at the end of the file. Change Profile0 to Profile1 (assuming you only had one profile previously). Change Name=default to something more useful. In my case I went with Name=jay Change Path=Profiles/… to Path=Profiles/somestring.default

Save profiles.ini, and then start firefox from the run menu with firefox -p — this should prompt you for which profile you would like to use. Choose the name that matches what you set in the previous step, in my case “jay.”

If you followed these steps carefully then you should now have the same set of extensions, preferences and bookmarks that was on your old install, and changes made on one OS should carry across to the other.

The steps I spelled out here for Firefox profiles are identical for Thunderbird profiles, just substitute Thunderbird wherever you see the word Firefox.

 
 

MySQL Atomic Rename + FK Constraints + Oops!

17 Nov

Here’s a fun issue I ran into a little while ago, while doing DB maintenance at Grooveshark.

MySQL has a handy atomic rename function, where you can do something like this:
RENAME TABLE CurrentTable TO OldTable, NewTable TO CurrentTable
Both renames are done as a single atomic action, so that the table CurrentTable is always there, and Nothing Has To Break*

A few days ago, I took advantage of this feature. I needed to make some schema changes to one table that was being read from but not written to.

CREATE TABLE NewTable LIKE CurrentTable;
ALTER TABLE NewTable DROP COLUMN UnnecessaryColumn;
...
INSERT INTO NewTable SELECT (...) FROM CurrentTable;
RENAME TABLE CurrentTable TO OldTable, NewTable TO CurrentTable;

That way we have a live, selectable backup of the table in case I really screwed something up, not to mention that moving the tables this way meant we could finally get that huge table into file per table, as that table had been around since before we had turned on the file per table setting in MySQL.

Several other tables have foreign key constraints pointing to CurrentTable, and unfortunately MySQL is smart enough to notice that CurrentTable is being renamed, so it “helpfully” updates all the foreign key constraints in those tables so that they are now pointing at OldTable. Without mentioning it. The problem didn’t become apparent until CurrentTable was being written to again, and then the other tables with the foreign keys were being written to pointing to the new data in CurrentTable, except the updated constraints meant MySQL tried to find the rows in OldTable, causing the inserts to fail.

This is definitely one of those cases where being smart and helpful can sure lead to a lot of misery. I had to hunt down every table that had referenced CurrentTable to change them back by hand. If MySQL had been just a little bit smarter it would have seen that CurrentTable wasn’t *really* going away and it wouldn’t have made those changes for me. If it was a little bit dumber, it would have done nothing and things would have just kept working, or it would have blocked me from doing my rename, forcing me to deal with the constraints before they broke anything.

* except when it does

 
 

Sorry about the ads

13 Nov

Sorry about the new ads on Grooveshark Lite, folks. They certainly don’t make me very happy either, but in these tough economic times, we gotta pay the bills somehow!

The good news is that these ads should free up some resources so we can spend more time making Grooveshark Lite even more awesome.

If you have thoughts on the new ads, Ben’s post on the community page has more information about the ads and a couple of ways to get in touch with us. Feedback is always appreciated.