Archive for the 'essay' Category

Why RedBubble kicks ass

I’m always looking for clever t-shirt ideas, and ever since reading Alvin Toffler’s The Third Wave back in 1997, I’ve wanted to make my own custom t-shirts. I’ve made CafePress, Spreadshirt, and Zazzle stores for my own designs, plus a CafePress store for the Neighborhood Project, a Spreadshirt store for Mosuki, and a Zazzle store for my Burning Man camp. All three of these websites suck, in various ways.

RedBubble is the new kid on the custom t-shirt design block, and it kicks these three competitors to the curb1. I’ve moved all my designs there. To explain what they’re doing right, first I’ll explain what these three competitors are doing wrong.

CafePress is dog slow and riddled with quirks. Browsing through my private designs, a few of the product previews show up as broken images. Background images and UI graphics re-load on every page change, slowly. Designing a new product is a complex, multi-step process. First you choose blank apparel or household items and add them to your shop. Then dig through pages and pages of FAQs to find the exact DPI and pixel dimensions for the particular item. Then fire up your image editor and resize your graphic to match. Upload the image to your “media basket.” Then go find your blank item, and add the graphic to it. If you add a graphic of the wrong size — like putting the 200DPI version of your graphic designed for a coffee cup onto a 300 DPI t-shirt instead — there’s no warning and no visual feedback. You, or your customer, will just get a badly pixelated product. And worse, if you upload an image that’s too large — it will be badly down-sampled, and look almost as bad as an image that was too small. They added support for dark apparel at least as far back as 2006 — yet their product previews still don’t look right. This is basic image manipulation, not rocket science.

Spreadshirt has two different printing techniques. The better-quality one, “flock print,” can’t print designs that are too detailed, so they require you to wait several days for each design to be approved by a human at Spreadshirt. Like CafePress, creating a shirt involves first uploading a design, and then adding it to a product. Their shirt designer is a pure flash widget in a pop-up window which takes over a minute to load on my fast net connection and has all the standard Flash problems; high CPU usage, no keyboard navigation, no scroll wheel support, etc., etc. It has a bunch of controls and widgets, some of which I have never needed and others which I don’t understand. I ordered this shirt from Spreadshirt, after their customer service confirmed that the black in the image, around the diamond with rounded corners, would not be printed. The shirt had a salmon color in place of red — that’s #ff0000 red — and the design’s edges had been sloppily cut, totally ignoring the rounded corners. It was so hilariously bad that I didn’t bother asking for a replacement. Each shop even has a bunch of settings and fields, including “title,” and “shop name,” (only one of which actually appears inside your <title> tag — the other appears to be ignored), two different “description” fields (one of which also appears to be ignored) and the cryptic “Product choice-Display category type.”

Zazzle replicates the multi-step product creation process of CafePress and Spreadshirt. Their product design UI is, thankfully, AJAX and not Flash, and you can upload an image to your “gallery” inside the product design process, although it takes three clicks and about two minutes of waiting for the UI to load before you actually get to the HTML file upload widget. Like Spreadshirt, their product designer has a suite of widgets to position and transform your image, and it takes several clicks to get the final product up on your store. I’ve ordered three shirts from Zazzle - the first I sent back because it was printed at such low quality I assumed their printer was running out of juice. I was wrong; when I received the replacement, it was just a tad bit better. The second was a retro design; I was planning on the poor printing adding to the retro charm, and it did.

So what makes RedBubble so much better?

RedBubble’s print quality is superior. If all these sites are screwing it up so bad, full color, digital printing on fabric must be a really difficult problem, right? If it is, RedBubble has solved it. I bought two designs on RedBubble that were too good to pass up, despite the poor print quality I’d come to expect from design-your-own t-shirt sites. And guess what? The shirts look great — you have to look really close to see that they’re not actually silk-screened in five different colors.

Maybe designing t-shirts on the web is just a complicated, difficult process? Nope. RedBubble’s t-shirt design process is extremely simple and quick. You select a 2400×3200 image to upload, and click save, and you have a t-shirt ready for sale. What about positioning, scaling, adding text, and compositing multiple images, like you can do on these other sites? RedBubble doesn’t provide any on-site UI to help you do these things. And they shouldn’t. People who design t-shirts — especially the good designers — are using Photoshop, Illustrator (or GIMP & Inkscape) and their ilk, to begin with. Those programs are going to do a much better job at tweaking your image than some Flash or AJAX web app coded by that nerdy intern from last summer with a 250×250 product preview window and a bunch of buttons with icons your users haven’t seen before. Rather than maintaining their own inferior design and preview widget, RedBubble gets out of the user’s way.

In RedBubble’s shirt design process, you can also pick the default shirt type, the available colors, and the default colors, and add a title, description, and tags, but all those items are optional. You can design a t-shirt in three clicks.

The theme here is that RedBubble’s superiority is distinguished as much by things that it does better as by those it doesn’t waste time with. There’s no “store,” and no concept of multiple stores on a single account, just a bare-bones profile. There’s no site-wide marketplace in addition to your store. There’s no way to customize your product list’s colors, logos, or background. Custom layout is not necessary, since (unlike it’s competitors) RedBubble’s default site colors are clean, simple, and don’t detract from your designs.

RedBubble doesn’t let you make hats, sweatshirts, panties, aprons, mousepads, buttons, magnets, coffee mugs, dog t-shirts2, baby aprons, pet bowls, or light switch covers. Just t-shirts, posters, prints, and calendars. Their interface, and the underlying code, is vastly simpler because of this — there are no “choose product” or “add products to store” steps. And I bet t-shirts, posters, prints, and calendars make up a very large percentage — like 70% — of CafePress’, Spreadshirt’s, and Zazzle’s revenue. Doing less gets RedBubble to market quicker, gives them a simpler product, and makes them a more agile competitor.

RedBubble has also built a community, and channels to keep users on the site and bring them back. You can give people positive feedback for their work by “favoriting” it or by “watching” them. You get summary emails with new work by people you’re watching, comments related to your work, and so on, drawing users back to the site over time. I was overwhelmed when I got even one comment on the first design I posted. I’ve now got thirteen comments on sixteen designs; compared to just two comments on my entire Zazzle store. And the comments, favorites, tags, and watchlists mean there are more users and t-shirts on every page to click on, making their site almost annoyingly sticky.

There’s only one thing that RedBubble is missing. They need to let you print on the front and back of a shirt. And I bet they’re working on that.

RedBubble is following all of those pithy little maxims for building a successful website:

  • Keep it simple — your product, your message, and your interface.
  • Do one thing and do it well.
  • Get out of the user’s way.
  • Build a community and keep it happy.
  • Always have something cool for the user to click on and look at.

So long, CafePress! Farewell, Spreadshirt! See ya later, Zazzle! Me and my custom t-shirt designs will be hanging out over here on RedBubble from now on.

  1. Threadless and Oddica, although good sites with very good printing, live in a different neighborhood because they both only print a small set of submitted designs. And my designs are generally too weird to win any beauty contests.
  2. What kind of person buys a custom dog t-shirt, anyway?

The third flavor of focus-follows-mouse

Steve Yegge’s excellent Settling the OS X focus-follows-mouse debate explains why OS X’s application-centric paradigm, with its application-global menu bar, doesn’t work so well with focus following the mouse but no automatic window raising. Background windows, attached to background applications, can’t, and aren’t expected to, listen for modifier+key events, because the application’s menu isn’t active.

The lack of focus-follows-mouse on OS X is one of the biggest reasons that I stick with Linux and Xorg on my main machines. Whenever I use one of my Macs for an exended period of time, I feel like a marathon runner who’s had to trade in his sleek running shoes for a pair of swimmer’s flippers. If there was a third-party tool to provide focus-follows-mouse on OS X that worked properly, I’d install it in a heartbeat.1

Yegge also points out that the auto-raise flavor of focus-follows-mouse is a taste only an epileptic could love. Set the auto-raise delay too low, and moving your mouse across big windows towards a smaller target window, or moving it too slowly, causes a cascade of ugly, annoying window raises and destroys your carefully crafted window tabbing order. Set the auto-raise delay too high, and you’re waiting too long for windows to focus once you’ve got the mouse there. In my experience, there’s no delay setting that works — every setting is too high, too low, or both.

But there’s another flavor of focus-follows-mouse, that, as far as I know, is only available via a third-party plug-in to the semi-abandoned and deeply buggy Sawfish window manager. It’s a flavor that is evocative of ripe nectarines and raspberries on a summer afternoon. And it’s so good it’s kept me using Sawfish despite its abandonedness and bugginess.

It’s called stop-focus, and it works like this:

  1. While the mouse is moving, don’t raise windows.
  2. Once the mouse has stopped, raise the window it stopped on.

“Stopped” is defined as below a certain configurable velocity (ten pixels per second works for me), and windows are only raised after a short (200ms) delay. Stop focus lacks the cascading window raising behavior of auto-raise. Moving the mouse across slowly across several large interim windows doesn’t raise them or screw up window tabbing order. Starting to move the mouse to another window, and then stopping and moving it back to the currently focused window, which you and I do more often than we care to admit, doesn’t cause any window raises at all.

So, while focus-follows-mouse without raise-on-focus (Yegge’s preferred autofocus), may not be feasible on OS X right now, there is a variant on focus-follows-mouse, with sane rules about when to raise the window under the pointer, that might make all us old focus-follows-mouse Unix relics happy.

If I were an OS X hacker, I’d probably just go code this up right now. But I’m not, because, among other things, OS X’s mandatory click-to-focus bugs me too much. Chicken, meet egg; Egg, meet chicken.

  1. One of the other big reasons I don’t want to switch to OS X is that, for reasons I won’t get into here, the global menu bar really bugs me. Funny that these two gripes of mine turn out to be intimately connected.

Ruby’s not ready: comments, corrections, and clarifications

Some good discussion on this one. It’s nice to see Ruby people saying things like this (5th message from the top, from Song Ma):

Interesting. But what I am thinking about is not the attitude of the author, but the points he was trying to make. The deep review and discussion will benefit the language insights.

Or this one (from Trans, on the same forum):

Why is everyone getting so worked up? It’s a critique. Biased it may be, but that in itself does not make it worthless. In fact, it can be very constructive b/c it uncovers “attack points” with the language. With each point we can ask ourselves objectively is this a misconception or a fair point? In either case we have an opportunity, to address misconceptions in our Ruby evangelizing blogs and to work to improve Ruby where a point has merit.

Bias can work both ways. But I think the Ruby community can rise above it, and Ruby will be all the better for it.

And from Peter Cooper at Ruby Inside:

As it is, I think he’s missing the point a lot of the time (he tends to think Python’s better because he likes its conventions more than Ruby’s - not a compelling argument), but it’s an interesting read none the less. Anything that keeps our minds open to the fact that Ruby != perfection is worth a look.

And a comment on the same post:

Let’s take his best points and incorporate them into future versions of Ruby.

Sounds like a plan.

I saw a few counterarguments like this:

Everything he’s saying is well known.

Just because a problem is well known inside a community doesn’t make it any less of a problem.

Everybody who mentioned documentation, even those who disagreed strongly with the rest of my post, agreed that Ruby’s documentation is seriously lacking. In fact, a lot of the mistakes in my original post are due to me not being able to easily find an explanation of something on the various Ruby doc sites. Which leads me to…

(more…)

Ruby’s not ready

Introduction

A few weeks ago, I learned Ruby and Ruby on Rails to compare them head-to-head against Python and Pylons, in preparation for a new project. When I began, I knew nothing about Ruby or Ruby on Rails. I have tried to be as objective as possible: before beginning this project, I wrote in email on March 5th:

I promise we’ll be as objective as humanly possible; if Ruby and Ruby on Rails truly is better, we’ll happily use RoR and never look back. I want to know that I’m using the absolute best tool for the job.

Since then, I have reimplemented one complex nine-hundred line Python library, PottyMouth, in Ruby. Another team member has also reimplemented parts the Pylons web application Spydentify in Ruby on Rails.

The best tool for the job is Python & Pylons. While Rails and Pylons are similar, shortcomings in Ruby compared to Python make Python & Pylons the clear choice. I make three basic arguments against using Ruby:

(more…)

If programming were like building a house…

I’m always coming up with metaphors to explain to non-technical people what I do. The point of this one was to explain to people why I prefer Python:

  • Programming in C is like building a four-story mansion out of 1×2 Lego bricks.
  • Programming in Python is like building a house out of Lego Technic parts.
  • Programming in Perl is like building a house with duct tape, a flat of cinder-blocks, some left-over lumber, pipe cleaners, crazy glue, fishing line, and chicken wire. You also get a bunch of re-bar that you can bend into whatever shape you want, and truck full of spray-on concrete.
  • Programming in PHP is like building a house with just chicken wire, coat hangers, and aluminum foil. Luckily, if you use enough aluminum foil, it will shield your brain from the alien transmissions from outer space, so you don’t have to wear your aluminum foil hat while you’re at home.
  • Programming in Java is like buying a one-piece, hyper-modern, injection-molded plastic house unit, and then having your lawyer write a letter to the house manufacturer asking for permission to cut a one-meter by two-meter hole in the living room wall into which you’ll install the front door, since the house doesn’t come with one. Your lawyer promises in the letter not to sue the house manufacturer for problems with the door.
  • Programming in Ruby1 is like building a house out of two different brands of cheap knock-off Legos, made of flimsy, low-quality plastic, which don’t fit together quite snugly enough. You also get a handful of puke-green pipe-cleaners left over from Perl.
  • Programming in JavaScript is like building a house out of Jell-O that has to stand up on three different lots, one flat, one downhill, and one uphill. Just when you’re finished building the house, Bill Cosby rides up on a stallion, ready to start filming a Jell-O commercial.
  • Programming in XSLT is like hiring an architect who speaks only Icelandic, an engineer who speaks only Bantu, and a bunch of Nepalese sherpas as the construction team. The architect thinks you’re building a supermarket, and the engineer thinks you’re inventing a new kind of refrigerator, and the sherpas think you’re doing performance art. The engineer builds a catapult to fling 2×4s into the air while the sherpas fire high-powered nail-guns at them, and when it’s all done you’ve got an ordinary two bedroom suburban house that’s completely upside-down.

That’s all! Happy April Fools!

  1. I’ll be posting a larger article about my recent experiences learning Ruby in a few days. Subscribe here if you want to read it when it’s posted.

SuperCache not so much with the “Super”

In reaction to the more than 34,000 visitors that Why your Flash website sucks generated (and is still generating) Jeremy enabled WordPress’s SuperCache for me.

Turns out SuperCache does a less than super job with non-ASCII characters, failing to encode them to HTML entities, and instead writing them out as multi-byte UTF-8 sequences:

Alphabet Soup ported to Inkscape/SVG

I got this email Tuesday from Joel Holdsworth, announcing that he had ported my Alphabet Soup pseudo-letter-generator from a bitmap to a vector model, and turned it into an Inkscape plug-in. He tells me that the extension will likely be included with Inkscape v0.47.

I cannot begin to express how phenomenally awesome this is. This is the kind of news that keeps me writing, and releasing, little free software projects. Six years ago I wrote Alphabet Soup as a little art project; it was fun. I released it under an open source license, and then never got around to improving it to output a vector format. Then somebody I’ve never met comes along, and not only improves it, but integrates it into a bigger free software project and it will soon be available to thousands of users in a greatly improved form.

You can pull the extension out of Inkscape’s SVN here. You’ll need these files:

share/extensions/render_alphabetsoup.inx
share/extensions/render_alphabetsoup.py
share/extensions/render_alphabetsoup_config.py
share/extensions/alphabet_soup/*.svg

Thanks Joel. Thanks Inkscape. I’m feeling pretty damn freetarded right now, and it feels good.

The two ugly faces of HTML generation

There are two quite different reasons for implementing HTML generation on a website. The first reason is to insert dynamic content, content that comes from a database or is algorithmically generated, into pages. The second reason is templating; to ensure that standard, site-wide parts of the HTML, such as headers and footers, are pulled from a single source. The goal of the first is to have a dynamic, database-driven site. The goal of the second is to avoid having to edit tens, or hundreds, of HTML files when the site design changes, and to avoid copy-and-paste coding.

(more…)

Why your Flash website sucks

your_flash_website_sucksThis all-Flash interface (screenshot) is a complete reimplementation of the WordPress blog interface; One single Flash widget fills the entire browser page, and implements not only the home page, but categories, comments (including posting), and article pages. It sounds like the author intends to use it to replace the HTML interface to his blog entirely. It’s a great example of why you should never build an entire website purely in Flash.

(more…)

Defaulting to customizable

In Java, many of the the standard library’s objects have configurable settings, like timeout settings, boolean behavior flags, and so on. Sun’s documentation never says what these are set to by default. Does the timeout default to infinity? Zero? Thirty seconds? One hour? Is a new connection set to accept input, or output, by default? What’s the default buffer size of this object? Am I expected to write a little test program to figure out what the defaults are? Am I expected to grep through the Java standard library source code to find out?

On top of this, lots of the configuration values have getters, setters, and a method to set the default value for all future instances of that class for the lifetime of your application. This must have taken some time to implement. But did Sun bother to put the factory defaults in the documentation? No.

This is a classic example of over-engineering; Instead of focusing on choosing a reasonable default and writing complete, useful documentation to make the user’s (coder’s) life better, they focused on a level of configurability that is only rarely (if ever) necessary.