Tuesday, February 26, 2008

Dancing Gophers: Amazon Your Video Widget

Fellow Amazonian Russell Dicker reposted his customer video review of the Caddyshack dancing gopher doll on his blog using the new Amazon associates Your Video Widget.

The Your Video widget lets Amazon affiliates annotate their videos with Amazon.com products and share them on their website. Check out this video for an example:



Since this widget is part of the Amazon associates platform, the creator of the video widget earns a referral fee for all Amazon purchases made by viewers that click through on the links in the video. This is true even for embeds of the video on other websites: Russell is going to make all the associates cash for purchases made from the video on this post.

I think this widget has great revenue potential for associates. If you create a popular viral video and publish it as a YVW, you can end up with thousands of your associates links all over the internet. It's ideal for publishing product review videos or for trying to monetize all of the funny videos you have laying around.

Disclosure: I'm an SDE on the team that developed the Your Video Widget. This is not an official Amazon message. All opinions expressed are my own and not of Amazon.

Labels:

Friday, February 08, 2008

Actionscript 2 is terrible

I've been doing a some flash development for work recently. It mostly involves adding features to an already existing flash project, which means its written in Actionscript 2.

I was really excited to learn AS2. Javascript is already one of my favorite languages, but it's sometimes a pain to deal with because of cross browser API and language differences. Since actionscript is an ecmascript dialect as well, I hoped that working with AS2 would be just like writing JS, but without the JS headache.

The reality was totally different: Flash 8/AS2 is the most painful to use development platform I've ever had to deal with. No joke. Here are some highlights:

1. In any sane dynamic language, what would you expect the output of this to be?

var x = undefined;
x.doIt();

I'd expect it to kick and scream. What does AS2 do? absolutely nothing. It just proceeds happily along as if nothing happened. You can imagine the silent failures and the hard to debug problems this can cause.

2. Speaking of debugging, if you were hoping to see a stacktrace anywhere, you can forget about it. This is also one of the most annoying things about working in javascript as well.

3. setTimeout is a pretty useful function. In fact, its so useful that it was added in the AS2 standard library. However, if you try to call it from an actionscript class, it'll fail to compile: it was just left out of the namespace! Thankfully, it's still callable if you tell the compiler to bugger off:

_global.setTimeout(function () { ... }, 300);

I'm amazed Macromedia's QA let this product launch with this bug. I'm even more amazed it was never fixed in any flash 8 player/compiler updates.

4. When the Flash CS3 compiler detects an error, it adds a line of text into a "compiler errors" window, which by itself isn't too bad. However, it still outputs a SWF and tries to execute it anyway. Not only does this slow down the development cycle, but it also squashes your perfectly good SWF from your previous compile.

5. AS2 doesn't include regular expressions in it's standard library. Awesome.

There's a lot more I could whine about: combo boxes that stop working once your SWF is dynamically loaded in another, buttons that stop responding to click events once you give focus to a text entry box, tedious manual merges of FLA files, strange delayed initialization issues, etc. Overall, it's really terrible. It's pretty clear to me that Macromedia didn't really care about flash as a development platform, and were happy with it just being used for animation.

Thankfully, AS3 seems to be much more pleasant to work with. I don't know if this due to Adobe's influence, or if Macromedia finally started to take flash as a dev platform seriously after flash 8. If you are starting a new flash project now, don't bother with AS2, just do it in AS3. Flash 9 already has 96%+ penetration in the US, the upgrade process is relatively painless for most flash 8 customers, and your developers will be much happier.

Labels:

Tuesday, January 22, 2008

HAppS Experiences

Last year I was working on a series on how to use HAppS, a haskell web applications framework, to build simple webapps. I was basing that series on my experiences developing the new version of the Openomy apis, which we finally launched a few weeks ago!

HAppS is a pretty nice framework.. even though its meant to be for generic web apps, I really think that building REST apis is its sweet spot: it's really good at generating xml out of your haskell types, and the HaXml xml parsing library is one of the nicest ones I've ever used (using combinators really beats hand rolling a SAX parser or hammering out an XSD).

Unfortunately, HAppS is moving very very quickly. The posts I wrote last March are almost completely obsolete now. We ended up having to rewrite a sizable chunk of the API service when we upgraded to the much nicer HAppS 0.9.1.

Ian wrote up some more details about our experience on the Openomy blog.

Labels: , , ,

Tuesday, March 27, 2007

Building a Haskell Web Service, Part 2: The "Hello,World" Service

This is the second post in a series about implementing the next major revision of the Openomy external API as a web service written in Haskell. Instead of focusing on the problems we faced getting started as I mentioned in the last post, I figured it would be more useful to show some code instead. I'll leave the rants for some other time ;)

HAppS is a web container in Haskell. Along with HTTP, it supports receiving emails via SMTP, has libraries to make DNS requests, has code to add ACID capabilities to your arbitrary in memory data structures, and apparently they are implementing integration with Amazon S3 and EC2: very awesome. At first glance it does seem to be a slightly bloated framework -- there is a Google Summer of Code project proposal out there to implement a more lightweight web framework -- but in practice all of that extra stuff doesn't really get in your way if you don't want to use it.

My only real beef with HAppS is that the documentation could use some major updating-- it seems that the API is changing so quickly that the HAppS tutorial isn't keeping up. Thankfully, the authors of the framework all hang out on #happs on irc.freenode.org and are really helpful. The tutorial does have some working examples and the general concepts are still accurate, but some of the code samples don't even compile. Here is the working the "Hello world" web service in HAppS, that I wrote when trying to learn the framework.
From now on I'm going to assume basic knowledge of working in Haskell and that you're using HAppS 0.8.8.

HelloWorld.hs:
module Main where

import HAppS

-- define the data type you will be returning from your handlers.
-- for simplicity, we will just use a File, which is represented by
-- its filename and its id number.
data ServiceValue = File String Integer

-- a handler that just responds with a File named test.txt
getFile () () = respond $ File "test.txt" 1

-- since our web service will return XML, we need to tell HAppS
-- how to convert a ServiceValue to XML. This is done by creating
-- an instance of the ToElement typeclass. HAppS provides
-- a few XML primitives that makes generating XML pretty simple.
instance ToElement ServiceValue where
toElement (File filename fileId) = listElem "file" [] [
textElem "id" [] (show fileId)
, textElem "name" [] filename
]

-- we also dont want any stylesheets attached to our returned XML.
-- HAppS uses the ToMessage type class to convert values to
-- the actual message sent down the wire. this calls
-- the default toMessageM which knows how to use ToElement,
-- and adds other things such as the right content-type and
-- an XML prolog
instance ToMessage ServiceValue where
toMessageM = toMessageM . XML NoStyle

-- glue it all together: make the getFile function listen to
-- the GETs to the /file url. noState tells the type system and
-- HAppS that this service is stateless.
main = stdHTTP [ h ["file"] GET $ ok getFile, noState ]
The comments should give a basic overview of how it works. To compile this with ghc, run:
ghc -package HAppS -o helloWorld HelloWorld.hs
Running it starts serving our simple requests from http://localhost:8000/file.

HAppS models the handling of web requests as a list of filters, which are passed into the stdHTTP function which implements the server's main event loop. The "h" function lets you bind a particular handler to a URL and HTTP method, in this case our simple getFile function. The rest is telling HAppS how to turn your internal values into XML, and generating these values based on the requests being received. The use of type classes makes the framework extremely flexible: returning other formats is just a matter of creating your own instances of ToMessage (HAppS also includes support for JSON out of the box).

In the next post of the series, I'll show how we're using HAppS' filters to validate incoming service calls and handle user authentication.

Labels: , , ,

Monday, March 26, 2007

Building a Haskell Web Service

This is the first post in a series about implementing the next major revision of the Openomy external API as a web service written in Haskell.

One of the cool things about having a website outside of your normal job is the ability to experiment with different technologies. We've done this pretty successfully with Openomy: it started out as a monolithic C# mod_mono + mysql application that stored files on the local disk and has now evolved into a much smaller mod_mono frontend, 4 services (3 in rails, 1 in java) and backed by Amazon S3 storage.

The next part of the original application we wanted to reimplement was the handlers for the Openomy API. The current implementation was inflexible, hard to extend, and was poorly suited to our new backend infrastructure.

We chose to implement the API bridge in Haskell for a few reasons:
  1. You can model the external API as two functions: one that maps the client's input to the XML we send to our services, and another for our services return XML to our external output. This made us think that it may be fun to do it in a functional style.
  2. We were worried about library support, but it turned out that Haskell had all of the libraries we needed: a web container, a powerful and flexible way to transform XML, an http client, and simple cryptography libraries.
  3. After reading the paper on HaXml, I was really looking forward to using their combinator library to produce the XML mapping functions we needed. It seemed like a very powerful and flexible framework, without being as tedious and error-prone as working with other XML libraries in other languages.
  4. Most importantly, it would be the most interesting: I've been wanting to learn Haskell for some time now.
However, there were also a few arguments against picking Haskell:
  1. It's one of those languages that will stretch your mind, especially if you're coming from a mostly object-oriented programming background. Picking it for a major project is a large risk and may delay getting the new service out the door.
  2. Haskell is mostly a research language: the community isn't very large and we didn't know any people that had successfully used it for a mainstream application.
  3. The API bridge is heavily IO dependent (making service calls over HTTP). Haskell's monadic IO system takes a little time to get used to and understand.
About a month ago, I bought a copy of the Haskell School of Expression and started learning the language. Shortly afterwards, I convinced Ian to start learning it as well, and soon we had started. We were both a little nervous about it-- the day we started working on it, we observed that this may be the beginning of the worst software project in the years we've been working together. We've also been tracking how many times we've said "we're f*cked" during development. I'm sure we're well into the double digits by now :)

After a few initial bumps on the road, the project is moving along nicely now. The problems we had getting started will be the subject of the next post.

UPDATE: Part 2 has been posted.

Labels: , , , ,

Wednesday, September 06, 2006

Long time no see

It's been a couple of months since I've last written, but I assure you there will be much more to read here soon. Some updates and short thoughts:
  • The Ruby Cookbook was just recently released. It's huge, and has a lot of useful recipies for all-around ruby hacking. I contributed an adaptation of this old blog post of mine as one of the recipies entitled "Enforcing Software Contracts" on page 367. Hope it helps you all add some metaprogramming sauce to your programs.

  • I recently moved out to Seattle, WA to take a job as a Software Development Engineer for Amazon.com as a member of the Community Content team. I'm really enjoying the switch so far, and I'm looking forward to becomming a regular to the seattle.rb events soon as I become more settled. An update to the "About Me" post is coming soon.

  • While signing in to write this blog post, I stumbled upon the new Blogger beta. It looks like blogger is finally catching up to the state of the art in blogging platforms. However, the beta still doesnt support publishing to other domains, which is a total dealbreaker for me for now. Hopefully that feature is coming back soon. On another note, the beta supports a new GData powered API.

That's it for now-- more coming soon.

Thursday, June 29, 2006

Google Checkout will not kill Amazon

The blogosphere is going nuts about Google Checkout today. The most controversial opinion comes from Rafe Needleman over at CNET, which calls Checkout an "Amazon Killer"

He couldn't be more wrong: People don't shop at Amazon just because you have your credit card information saved there-- almost all major e-commerce sites let you save your credit card info. People shop at Amazon because of low prices, huge selection, cheap/free shipping and great reliability. Google checkout provides none of this-- it is not a store, just a system to store credit card info. It is merely the Google version of Yahoo Wallet. Amazon and eBay have nothing to worry about. In fact, there's nothing stopping them from supporting Checkout themselves (aside from potential not-invented-here reasons).

Checkout is certainly significant, but not for the reasons Needleman mentions: The best part about Checkout comes by integrating it with Google advertisements. Forget cost-per-click, it's now cost-per-sale! This change makes click fraud is no longer something to worry about, which was one of the thorns in Google's side, at least in terms of Wall St perceptions of their business model.

I think Needleman's post is just another example of people gaming the blogosphere, as Richard MacManus ranted about the other day-- just write any "XYZ vs Google" post with an sensationalist headline and watch the hits roll in (this is the #3 post on techmeme right now). For this, Needleman gets a "nofollow" on my link-- this type of stuff shouldn't be encouraged.

amazon