ShopTalk Blog

How and why we are building ShopTalk

a = F/m, So Keep Your Foot on the Gas

written by David Shoemaker, on Feb 3, 2010 8:33:00 PM.

Let's say you have a box.

Except your box is in deep outer space.

And you strap a magical engine to it.

This engine uses an inconsumable fuel that allows it to apply a constant force to your box forever. Let's graph the box's distance from its starting point over time.

Suddenly, although its in an expansive frictionless vacuum, people are looking at your box's graph and saying that it has traction. Your box is beginning to attract unwanted attention from venture capitalists on Sand Hill Road.

Many of us entrepreneurs would like to see more graphs like that.

Perhaps we should emulate the magical engine: a constant, unquenchable force, determined to push for years on end without respite.

What can we learn from cutting the graph in half?

Overnight success

takes years.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Death to filesystems

written by David Shoemaker, on Jan 18, 2010 10:02:00 PM.

After writing about The Real Web OS, I was happy to see that Google is getting a lot right with Chrome OS. Naturally, it is easy to focus on what they're getting wrong, but that's another post for another day.

I am absolutely thrilled to see one long-standing feature of desktop operating systems dropped from Chrome OS: the filesystem. From the user's perspective, I see no trace of a hierarchical file system. This is great news for those of us who organize everything in our lives horizontally. We've witnessed an increasing prevalence of fast and effective desktop search in recent years, yet users are still expected to manage a tree of folders and files. That's a vestigial wart that needs to be removed.

Apple's apps generally provide a layer of abstraction on top of the filesystem, so that users don't interact directly with it. You interact with your music via iTunes; iPhoto manages your photos. They can't trust third party apps to do the same, however, so they have the catch-all Documents directory. In fact, they can't even trust themselves. Apparently the iWork team doesn't talk to the iLife team much; iWork still uses the old school model: browse the filesystem to open a file and pick a folder and a name to save a file. If they're clutching to old patterns in the name of easing the switch from Office, they are making a mistake. The best way to encourage switching is to build a new and better product, not emulate old ones. It's always better to usher in the future than cleave to the past. The iPhone is the first popular computing platform to eschew the filesystem, and, if the rumors are true, Apple's tablet will be the next; that's the future.

John Siracusa's excellent review of Mac OS X Snow Leopard contains a section about filesystem APIs. He points out some of the pitfalls and gotchas:

Mac OS X has historically supported many different ways of referring to files on disk from within an application. Plain-old paths (e.g., /Users/john/Documents/myfile) are supported at the lowest levels of the operating system. They're simple, predictable, but perhaps not such a great idea to use as the only way an application tracks files. Consider what happens if an application opens a file based on a path string, then the user moves that file somewhere else while it's still being edited. When the application is instructed to save the file, if it only has the file path to work with, it will end up creating a new file in the old location, which is almost certainly not what the user wanted.

He proceeds to discuss the various file access methods and file metadata options available to application developers. Siracusa also wrote an entire article about metadata madness. It seems simply attaching a few pieces of metadata to a file is a complicated task these days. As a programmer, I couldn't help but think that users aren't the only ones massively underserved by filesystems; we too are hampered by our only interface to persistent data storage.

John Gruber wrote a wonderful article not long ago about some of the pitfalls of filesystems. His primary example is the requirement to name a file before you can save any data to disk. He encourages application developers to solve this problem for users, but I think the issue cuts deeper than the application, right to the OS itself. After all, the application would just have to choose a name for the file if the user isn't expected to do so. Some data just can't be contained by a nice little box with an appropriate label. If we're going to provide users with a better interface to their data, why not give developers one as well?

As my college roommate once said, developers need to persist data objects that have an API other than just stat, open, seek, read, write, and close. I realize that the Unix philosophy is "everything is a file" -- which really means "everything is a stream" -- but in my applications I very rarely choose to use streams except to satisfy Unix I/O APIs. Many years immersed in Python have taught me that a few primitive types can represent most data: int, string, list, dict. I wholeheartedly agree with Scott Jackson that everything should have an API, but I don't agree that we should embrace the part of the Unix philosophy which states "Store data in flat text files." I suppose we should embrace it so long as our operating system gives us no choice, but isn't it time for modern operating systems to move on? Wouldn't it be much easier to share data between applications (which is, after all, the point of giving everything an API) if the data were just stored in sensible data structures? Instead of "my application generates a file of tab-separated columns of floating point numbers encoded as ASCII which can be parsed using regular expressions" you could say "my application builds a list of tuples; no parsing necessary". Instead of using YAML for configuration, which your application parses into dicts and lists, you could just use dicts and lists directly.

There is a ton of innovation in the database space these days. These projects stuff all of their data into a small handful of on-disk streams. They have to use the lowest common denominator API, provided by the operating system, to seek around within the stream and read and write data. It's about time for operating systems to make higher-level APIs like these first class citizens. Filesystems are no good for users and they're no good for developers. I'm starting to see the beginning of their demise, and I say good riddance.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

The Minimum Viable Tree House

written by Christian Wyglendowski, on Nov 11, 2009 5:50:00 AM.

In addition to working on ShopTalk over the summer, I joined forces with my brother-in-law to build a tree house for my kids (ages 5 and 3).

We were going to build the coolest tree house around. It was going to be 10 feet off the ground at floor level and have 120 square feet of space under roof. It was going to be big enough for even adults to stand up inside. There were going to be skylights, a trap door and a covered porch.

You've probably already guessed that we did not, in fact, build the Minimum Viable Tree House.

Like projects tend to do, the scope crept, the expenses soared and the time line stretched. As the project dragged on for weeks, the stakeholders (my kids) began to grow understandably impatient.

"Papa built our last tree house in a day!", my oldest said.
"Yeah, but that tree house was a couple pallets and a ladder", I replied.

You see, we had been working on it all that time and yet there were no tangible results for the kids. It was too high and unsafe before it had walls. Even after we put up the walls, the railing for the porch had to go up. Then there was the issue of the big hole in the floor where the trap door was going to go.

We did actually finish the tree house a couple weeks later. It's been towering over the backyard for the last few months.

Spiders think it's pretty great.

My kids though? They get more into playing in the brush pile from the tree that we cut down to make way for the tree house.

I'm pretty sure I've noticed the squirrels laughing at me.

One of the many mistakes I think I made was making the tree house too big. It comfortably accommodates adults. It's really high off the ground. Meanwhile, my kids are cramming themselves into cardboard boxes whenever they find one, squeezing themselves under the furniture and tunneling under the brush pile beneath the tree house. Kids like small spaces, and the final product doesn't fit the current clientèle. Further proof of this is their actual favorite part of the tree house - the "cramped" little loft area above the porch.

Another mistake was working for weeks and weeks before having something the kids could use. All of us were pumped up about the project at the start. Kids and adults alike sat around drawing up sketches of what it should look like and talked excitedly about what we'd add to it down the road [0]. After construction started though, it just took too long to get it to a point where they could play in it. The excitement wore off as the weeks wore on.

I still have hope that the kids will enjoy it when they are older. Maybe they'll grow into it.

For now though, when working on ShopTalk and other projects, the tree house is a reminder. A reminder to listen to and build for my audience. A reminder to deliver useful features in short iterations. A reminder that next time I need to build the Minimum Viable Tree House first [1].

[0] Be on the lookout for my next post, "The Minimum Viable Zip Line" ... just kidding!
[1] Hat tip to Eric Ries and my late father-in-law and his "two pallets and a ladder" tree house.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Your Users are not Random Variables

written by David Shoemaker, on Nov 5, 2009 8:55:00 AM.

Intuitively, we all know that flipping a fair coin results in heads 50% of the time. But how many times should we expect to flip a coin before the stats converge on that number? I turn to my esteemed statistician friend, Christoffer Perry, with such questions. He says:

In Statistics, everyone seems to think that 95% is a magical number, so let's pretend like we're statisticians (a dubious proposition, at least for myself) and bow down to the mythical sphinxian ninety-five. Conversely, 5% is a pretty good number in the discipline too, so we'll use the fabled feathered five. That is, for those of you not privy to my inner thoughts and schemes, let's say we want the probability of the sum of heads falling within five percent of the average to equal ninety-five percent.

Thanks to R, the Jason (of Rgonaut fame) of Stats, we soon find that you'd have to toss a fair coin about 1,500 times. That is, there's roughly a ninety-five percent chance that the number of heads will be somewhere between 712 and 788, five percent off 750. That's a lot of coin tossing for not a lot of certainty (though you can be certain that rattling off this sort of probability at a party will get you quickly tossed).

To get even more certain, say, 99% probability, you'd need about 2,700 tosses. To be more certain and get a range of one percent, you're looking at somewhere near 66,000 tosses. But hey, at least you got a lot of free drinks at those parties!

A fair coin is a random variable. Your users are not.

At Startup School 2007, Max Levchin advised the attendees to take a course in statistics and realize that a sample size of 30 is too small to produce statistically significant results. That would be true if you were sampling a random variable. Unfortunately, this was his argument against usability studies, which sample human behavior.

In college, I was fortunate enough to study under the wise tutelage of Dr. James D. Hollan. I spent an entire quarter redesigning a pretty unique piece of video viewing/editing software developed at Stanford, called Diver. The first assignment required us to conduct 16 contextual interviews with actual Diver users. Each interview consisted of at least two members of our six-person team sitting and closely observing a Diver user, in their office, for two to three hours. That's a lot of man hours for the first assignment in the course.

The first several interviews were basically shock and awe. All of our expectations about user behavior were shattered. We never could have predicted how these people were using the software. Breakdowns and problem areas in Diver's interface shot out of the screen at us like Captain Eo's lasers. Possible changes and improvements raced through our minds. We had chosen wisely; this software was ripe for a redesign. However, after about eleven interviews we came to a pretty obvious conclusion: all of the users behaved roughly the same. After learning a ton from the first few interviews, we now felt that we weren't learning anything new at all by conducting more of them. We took this observation to Dr. Hollan. His response was that this pattern is entirely typical. He teaches this course every year to hundreds of students, and they all have the same experience. He asks the students to conduct 16 interviews, but that is always more than is necessary. We were allowed to stop at eleven, and we all breathed a sigh of relief.

The lesson learned: human behavior converges on its expected value far more quickly than a random variable does.

Applying this lesson

Reading words on buttons and menus requires a lot of brain power. The image of the words needs to go from the eye to the brain. Then it needs to go to a different section of the brain for language processing. Finally, another section of your brain decides if those words represent what you're currently searching for and whether to signal the hand to click on them. Icons, on the other hand, can be more easily differentiated and can allow users to short-circuit this process. They can notice the icon in their periphery and click on it without putting much thought into it. That means their thoughts can remain on what they're trying to accomplish instead of how to accomplish it. For this reason, the room tabs in the first version of ShopTalk looked like this:

Every single one of the first 5 users was confused by that little tab on the right. Nobody clicked on it. For me, that was already enough data to warrant fixing it. After just 5 tests I already felt close to that 95% certainty that required 1,500 coin flips. I'm willing to bet that you, kind reader, are also confused by it at this very moment. We humans all think alike. Your users, in this sense, are like a gaggle of Lemmings.

Our task as interface designers is to guide those lemmings to safety. You have to put up the proper signs and road blocks so that they think what you want them to think and do what you want them to do. You also have to guide them with such a soft touch that they don't even realize they're being guided. In this case, the fix was rather simple:

Labeling the tab with text and an icon is often a great combination, if you can afford the screen real estate. First time users can read the words to figure out what the icons mean, and more seasoned users can spot that little green plus sign out of the corner of their eye and click on it without even thinking about it. The result: happy users who keep coming back for more and tell all of their friends to check out ShopTalk.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Startup School: Hackers and Salesmen

written by David Shoemaker, on Oct 26, 2009 10:32:00 AM.

There are two types of people in the world: those that put other people into categories and those that don't. While returning to Wheeler Auditorium after lunch on Saturday, I made a comment that put me firmly in the former category. I had noticed a pattern among the speakers at Startup School. Some speakers had apparently figured out a formula for success, and emphatically encouraged us to repeat that formula. Other speakers were quick to point out that they were merely reviewing their experience, which may or may not apply to audience members, because every startup faces unique challenges.

Jamie's response to my observation was that the speakers' values were evident in their talks. Hackers value precision and accuracy. Great hackers have to be precise and accurate, because computers do what you write, not what you intend. Salesmen value confidence. To close a sale and get paid (which is, as we learned, the absolute greatest expression of love), customers have to be pretty convinced that you're right. That's not going to happen if you're not confident. Why should I believe you if you don't seem to believe yourself?

This classification reminded me of one of my favorite math jokes (from Wikipedia):

An astronomer, a physicist and a mathematician are on a train in Scotland. The astronomer looks out of the window, sees a black sheep standing in a field, and remarks, "How odd. Scottish sheep are black." "No, no, no!" says the physicist. "Only some Scottish sheep are black." The mathematician rolls his eyes at his companions' muddled thinking and says, "In Scotland, there is at least one sheep, at least one side of which looks black."

You could probably substitute a salesman, a VC, and a hacker into this joke and it would still work.

Jason Fried was the most conspicuous salesman of the bunch. He spoke almost entirely in absolutes. He raised his voice. He was defiant and confident. He paced around the stage to bolster his stage presence. And if that wasn't enough to convince you that he was right, he threw in a slew of curse words. It's hard to argue with that.

Paul Buchheit stood on the other end of the spectrum. One of his early slides literally said this:

Limited Life Experiences + Over-generalization = Advice

He was relatively timid, yet funny and insightful. He looked at problems from multiple angles. He discounted his own opinion frequently. He offered options, but didn't make any demands.

Technology entrepreneurs need to be half hacker and half salesman. When you're writing code you have to be intimately familiar with the limitations and weaknesses of your product. When you're selling, however, your product is suddenly limitless and indestructible. When you're working on strategies for your startup you need to consider multiple scenarios and outcomes. When you're talking to the press, you only discuss one possible outcome: unmitigated success.

Since Startup School is attended mostly by hackers, I felt a little insulted by Jason Fried's lack of intellectual honesty. I had to wonder if he had deluded himself or if he was trying to delude the audience. I appreciated many of his one-liners and the entertainment he provided, but I felt much more comfortable listening to Paul Buchheit's humble and honest approach.

Mark Zuckerberg is an interesting specimen. At Startup School 2007, he took the stage after Mitch Kapor. Mitch had just given a fantastic talk based on his stellar track record in the industry over the last three decades. Mark got on stage and arrogantly contradicted much of what Mitch had just said. Of course, Mark wouldn't know that, because he couldn't be bothered to sit through Mitch's talk and even showed up late for his own. Brad Fitzpatrick refers to LiveJournal as his "accidental success". In 2007, that attitude was completely absent from Mark's talk. The guy was obviously drinking his own Kool Aid. I lost a lot of respect for him that day. This year, however, he managed to gain a lot back. He attended the entire conference (and even participated in other talks from the crowd ;) ). He was much more humble and honest. He recognized the achievements of others and the viability of a variety of approaches. His first line was, "These are my people," putting himself on an equal playing field with all the hackers in attendance. I only wish he had responded to rms's question about taking PR lessons, because it seems like he's making a concerted effort in this area, and it's paying off. Good on you, Mark.

Salesmanship holds an important place at Startup School. It's likely the facet of entrepreneurship that attendees need to work on most. I appreciated Jason Fried for giving us a great example of how it's done well. I think most attendees are grounded enough to know that there is no silver bullet and that each talk should be consumed as the opinion of the speaker and not as absolute truth. From the variety of styles, experiences, and opinions, we can formulate an approach that works best for us. Thank you, Y Combinator, for putting on a terrific conference again this year, and for teaching this hacker how to become an entrepreneur.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Beautiful Coroutines: Cooperative Concurrency in Python using Diesel

written by Christian Wyglendowski, on Oct 20, 2009 10:35:00 AM.

We've been busily working on the latest iteration of ShopTalk. Our asynchronous networking library Diesel plays a key role in the application. Recently I got the chance to use Diesel outside of its normal problem domain of network applications.

I have been paging through Beautiful Code for a while now and read the chapter on Beautiful Concurrency the other day. In the chapter, Simon Peyton Jones lays out his solution for "The Santa Problem" using Haskell and Software Transactional Memory (STM). He writes that it is a difficult problem to solve with traditional concurrency primitives (threads, locks) that are provided with procedural programming languages.

The problem goes like this:

Santa repeatedly sleeps until wakened by either all of his nine reindeer, back from their holidays, or by a group of three of his ten elves. If awakened by the reindeer, he harnesses each of them to his sleigh, delivers toys with them and finally unharnesses them (allowing them to go off on holiday). If awakened by a group of elves, he shows each of the group into his study, consults with them on toy R&D and finally shows them each out (allowing them to go back to work). Santa should give priority to the reindeer in the case that there is both a group of elves and a group of reindeer waiting.

Diesel is primarily a library for writing non-blocking network applications but you can also use it to write general concurrent applications using Python generators as coroutines. I thought it would be interesting to use it to write a solution to the Santa Problem.

The solution I came up with uses a combination of shared lists (one each for reindeer and elves) and cooperative events to manage state.

import random
from diesel import Application, Loop, fire, wait, sleep

deer_group = []
elf_group = []

The lists contain the waiting reindeer and elves that eventually cause Santa to wake up when they are full (3 elves, 9 reindeer). The events let Santa communicate with the actors contained in each group. Speaking of the Jolly Old Elf, let's take a look at how he ticks:

def santa():
    while True:
        deer_ready, elves_ready = len(deer_group) == 9, len(elf_group) == 3
        if deer_ready:
            yield work_with_group('deer', deer_group, 'deliver toys')
        if elves_ready:
            yield work_with_group('elf', elf_group, 'meet in my study')
        yield sleep(random.random())

The logic for Santa is quite simple. If a group of deer or elves are ready, he works with them, otherwise he sleeps. The order of operations guarantees that if a group of deer and elves are ready at the same time the deer get priority. That is a requirement of the problem.

The reindeer and elves are created via a generic actor function that returns a generator.

def actor(name, type, group, task, max_group, max_sleep):
    def actor_event_loop():
        while True:
            yield sleep(random.random() * max_sleep)
            if len(group) < max_group:
                group.append(name)
                yield wait('%s-group-started' % type)
                print "%s %s" % (name, task)
                yield wait('%s-group-done' % type)
    return actor_event_loop

The elves and deer each "sleep" for a period of time, which actually represents time spent working (elves) or vacationing (deer). They then wake up and attempt to get into a group. They are only successful if the group isn't at capacity (max_group) already. Once in a group, each actor then waits for an event that signifies the group has been ushered in to see the big man. Elves that aren't lucky enough to gain an audience have to wait - they will continue in their loop and try again later.

Once they are signaled with the *-group-started event they do their task, which amounts to printing it to the screen in this case. They then wait until dismissed by Santa when he fires *-group-done.

While working with a group, Santa does the following:

def work_with_group(name, group, message):
    print "Ho! Ho! Ho! Let's", message
    yield fire('%s-group-started' % name)
    yield sleep(random.random() * 3)
    yield excuse_group(name, group)

def excuse_group(name, group):
    group[:] = []
    yield fire('%s-group-done' % name, True)

Santa prints a greeting to the group, and then signals them to start the task at hand. The sleep call represents the time spent cooperating on the task. Finally, the group is cleared and the actors are signaled that the group activity is done. The reindeer return to their vacations and the elves resume work.

This is all easily coordinated since Python's generators, combined with Diesel, perform cooperative multitasking. Each generator gets processing time to do its own thing and then yields control back to the Diesel core so it can wake another another generator. Any actions performed by a given generator are atomic with regard to the others. This makes working with shared structures easy.

It cuts both ways though. The actions performed by a given generator while it is active block the others. Generators should do what they have to do quickly and then yield control back to the core.

Hopefully this little diversion from the norm here at the ShopTalk blog was educational and entertaining. I know it was for me. The complete code is below. Also see here for Haskell and Erlang versions.

import random
from diesel import Application, Loop, fire, wait, sleep

deer_group = []
elf_group = []

def santa():
    while True:
        deer_ready, elves_ready = len(deer_group) == 9, len(elf_group) == 3
        if deer_ready:
            yield work_with_group('deer', deer_group, 'deliver toys')
        if elves_ready:
            yield work_with_group('elf', elf_group, 'meet in my study')
        yield sleep(random.random())

def actor(name, type, group, task, max_group, max_sleep):
    def actor_event_loop():
        while True:
            yield sleep(random.random() * max_sleep)
            if len(group) < max_group:
                group.append(name)
                yield wait('%s-group-started' % type)
                print "%s %s" % (name, task)
                yield wait('%s-group-done' % type)
    return actor_event_loop

def work_with_group(name, group, message):
    print "Ho! Ho! Ho! Let's", message
    yield fire('%s-group-started' % name)
    yield sleep(random.random() * 3)
    yield excuse_group(name, group)

def excuse_group(name, group):
    group[:] = []
    yield fire('%s-group-done' % name, True)

def main():
    app = Application()
    app.add_loop(Loop(santa))

    elf_do = "meets in study"
    for i in xrange(10):
        app.add_loop(Loop(actor("Elf %d" % i, 'elf', elf_group, elf_do, 3, 3)))

    deer_do = "delivers toys"
    for name in [
            'Dasher', 'Dancer', 'Prancer', 
            'Vixen', 'Comet', 'Cupid', 
            'Donner', 'Blitzen', 'Rudolph',
            ]:
        app.add_loop(Loop(actor(name, 'deer', deer_group, deer_do, 9, 9)))

    app.run()

if __name__ == '__main__':
    main()

Do you instant message your coworkers? Try ShopTalk instead. It's better.

The Real Web OS

written by David Shoemaker, on Oct 15, 2009 6:31:00 PM.

Our users frequently request a desktop client for ShopTalk. As with all feature requests, my response is to ask myself this question: what real need is prompting this request? They need ShopTalk to sit in their Dock. They want ShopTalk to visually and audibly notify them when new messages arrive. They want to be able to drag and drop files onto ShopTalk to share them with their coworkers. I think they want The Real Web OS. Let me tell you why.

Right now there is a huge divide in applications programming.

In one corner, we have native apps, the reigning champion. They are built with toolkits provided by the OS. They use standard interface controls and conform to a standard look and feel. They can harness the full computing power of their host machine using things like threads and systems-level languages like C. They get full access to the hard disk. They sit in the Dock or the Task Bar or the System Tray or the Menu. They can notify the user if anything interesting happens within the app. They can use sockets. You can press Alt-Tab to switch between them.

Glaring at native apps from the opposite corner is a formidable challenger called web apps. Web apps are the hippies of computer applications. Everything is free and open. They don't require any installation process or periodic updates. They give their creators nearly unlimited freedom with interface elements and look and feel. They are easily connected to the endless piles of data and vast computing power that live in The Cloud. They are easy to share with friends. They are easy to check out casually and move on if you're not interested. They can be accessed from your computer at home or your computer at work or a friend's computer or an Internet Cafe. They are built using open standards. They are taking over the world.

What does the current trend toward web apps mean? It means people want all that stuff listed in the previous paragraph. They need it. What's the current way that operating systems provide for those needs? We give people one native app, the browser, in which all of these web apps run. That browser is like the Great Wall of China. It protects the computer from these nefarious web apps, and it ensures that most of the resources within the wall are completely inaccessible.

The Real Web OS will tear down the wall.

The Real Web OS is not a suite of native-like applications that runs in the browser. It's an OS that runs web applications natively. All applications running on The Real Web OS will be developed like web apps. They will look like web apps. They will be shared and discovered like web apps. They will combine local and remote data and computing like web apps. However, they will have all of the resources of the host machine at their disposal. They will be able to use the disk and the graphics card. They will spawn threads and processes. They will receive notifications when their host goes to sleep. They will notify the user if they require attention. They will efficiently sync all of your data Dropbox-style so that you can access it from anywhere*. All of the capabilities now ascribed to native apps, which are protected by the Great Wall of The Browser, will be exposed to web apps via JavaScript APIs (for extra points, we could replace JavaScript with Python ;) ).

I read an insightful comment on Hacker News recently:

Desktop applications have shifted to the web. It's only a matter of time before mobile apps are also obsolete.

Actually, it's only a matter of time before the distinction is obsolete.

* If the Dropbox team, or anyone else, is ever game to build The Real Web OS, count me in.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Gold Plating Hamburger Patties

written by Jamie Turner, on Oct 8, 2009 10:00:00 AM.

I knew that being an entrepreneur would involve becoming product-focused instead of engineering-focused. But I've spent so much of my life shaping my brain around the discipline of programming and system architecture that it's requiring a concerted effort to keep the product and its users' interests foremost in my mind. It's just so easy to fall back on old priorities and practices--especially when they're as elegant and easily validated as these particular ones are.

See, problem-solving in the realm of code usually wraps itself up into neat little packages:

  1. A requirement exists
  2. A system design is established/extended to support it
  3. That design is implemented
  4. Validation is done to ensure that the requirement has been satisfied

Make sense? Great. Now, for the sake of clarity, allow me one extended hamburger metaphor. Let's call that nice little endorphin-releasing four-step process the hamburger patty.

If only the world were all patties... no carbs! But it's not quite that simple:

  1. Gather user feedback, do user studies, maybe talk to company stakeholders, weight everyone's priorities, maybe make enemies
  2. Elect and spec some requirements as The Ones We're Going With Right Now
  3. patty()1
  4. Deploy said requirements and desperately try to measure their effectiveness (assuming you actually figured out what their goal was in the first place)

There's a quite a bit of messy, but critical stuff in that bun. When you're all patty, you're missing a lot of the burger.2

"But I'm bought into all that!" Joe Hacker says from his cube at Big-Widget-Co. "I'm sympathetic to the product design part of the process!"

Yeah, in your regular coding gig, you might be in a few bun meetings... but if you're anything like me, you're probably sitting there thinking "arg, this crap is really gonna screw up my patty!"

Well, I'm a bun man now, Joe.3 There are no longer proxies between the user's satisfaction and my paycheck. They have the credit cards, and they don't know or care if my functions fit under one hand, if I used a recursive or imperative approach to that algorithm, or if an armadillo is frantically doing modular arithmetic in the machine room. They just want the software to satisfy some subset of their needs vastly more effectively than their existing methods. And "effective" usually has more to do with UI than OO.

The sad realization is that in most cases the code only has to be good enough to be extensible (we can add features!) and not break publicly (we won't embarrass ourselves).4 But the quality of the product experience has a direct impact on the company's success.

In the well-known essay The Rise of Worse is Better, Richard Gabriel argues that in commercial programming, pragmatism has for all practical purposes won the battle against purity. "The right thing" philosophy is dead or dying--take your pick.

But I'm not sure that's the whole story--it seems to me we now recognize that "the right thing" is better applied in that space where the user actually notices.

[1] Yes, the requirements and associated specs are global. This is an essay, not Haskell

[2] I'd like some credit for at least not invoking lettuce, pickles, condiments, etc.

[3] ...

[4] Granted, many shops would be thrilled with just this much. But there's a lot of breadth hidden behind these basic requirements that great coders are happy to explore, generalize, and framework-ize to crazy excess.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Convince me to ride roller coasters

written by David Shoemaker, on Sep 29, 2009 9:12:00 AM.

Sometimes people just don't know what's good for them.

I can't even count the times I've tried to convince friends and family members of the usefulness of a new product. Whether it's a Mac or a TiVo or an iPhone, I feel like it's my job to try out the new stuff and sing its praises to my not-so-early-adopting cohorts. And I must be a decent evangelist, because I've left a long string of grateful converts in my wake.

Sometimes, I'm the one who needs convincing. As a child, I refused to ride roller coasters. I was afraid of them. No matter what my friends said, there was no convincing me. The resistance finally ended one day when I was in the eighth grade. The mounting peer pressure became too much to bear. I hopped onto an enormous maze of twisted metal, gritted my teeth, and held on for dear life. It was an exhilarating experience. My perspective changed almost immediately. Suddenly, I couldn't get enough roller coasters.

Even if the product in question is spectacular, convincing people to use it is often like pulling teeth. People resist change. They fear it. There might be very little rational risk involved, but there is a ton of perceived risk. Lately I've been thinking about how I might convince people to ride our proverbial roller coaster. I had forgotten what it took to convince me. It goes something like this:

Make your product so life-changing that every user wants to spread the gospel

It's no wonder that my friends spent years trying to convince me to ride roller coasters. Roller coasters are fun. Lots of fun. Much more fun than chatting with your coworkers online. However, we've seen how ShopTalk can transform the way people work. Our job now is to build it so that it reaches its full potential. There are about a thousand features and enhancements in our backlog right now. We'll get to them all eventually. Even more important than filling out the feature checklist is that every one of those features is well executed. We want using ShopTalk to be an absolute pleasure. It needs to be the type of application that just gets out of your way while you use it so that you don't even notice it's there. The user experience should be second to none (including customer service). Only then will our users feel compelled to spread the word.

Fuel peer pressure: everyone's doing it

If all my friends are riding roller coasters and loving it (and surviving it), there must be something to it, right? This line of thinking gradually erodes resistance to change. This is why companies put logos on their products and give them a distinctive look. You want potential customers to notice that a lot of people have already bought into your idea. ShopTalk is intentionally a private service. Your company gets its own host name for its account and everything is nicely partitioned off and secure from the outside world. This creates a problem for us. Even if we had thousands of companies using ShopTalk every day, nobody outside those companies would ever know it! We're brainstorming ways to fix this. One idea is to allow our users to designate one chat room as "public", which would allow anyone to enter that room via a unique URL without login credentials. In an effort to give back to the communities that have given so much to us, we could host public rooms for free for open source projects and events like PyCon. Speaking of giving back, we're not afraid to open source our own software as well.

Create a product whose utility is directly proportional to the number of friends a person can convince to use it

My friends didn't just want me to experience the thrill of roller coasters, they wanted me to go to the amusement park with them. Why? Because amusement parks are much more fun when you go with a group of friends. Fortunately for us, ShopTalk shares some similar characteristics. It's basically useless for one person, unless that person enjoys chatting with himself. It's not really necessary for two people, although it does provide some cool advantages over instant messaging. It becomes much more useful with three people, and it's a real life saver if you have twenty people (or more). We're fairly confident that it can gain momentum quickly within an organization. We've seen it happen. However, getting over that three person hump has often proved difficult. In our latest release we've added a couple of features which make it easier for the initial user(s) to invite their colleagues. We're hoping that will help it reach critical mass.

In Summary

Your future users trust their friends' recommendations; they don't trust advertisements. Give your users something to talk about. And give them a strong reason to talk about it.

Do you instant message your coworkers? Try ShopTalk instead. It's better.

Announcing Diesel

written by Jamie Turner, on Sep 23, 2009 12:06:00 AM.

Here at Boomplex, we're thrilled to see that everyone is excited about async!

We get excited about async too; in fact, the guys at Boomplex have used async approaches in Python for years to tackle many kinds of network applications and protocols. We've dabbled with Twisted, asyncore/asynchat, libevent, eventlet, py's greenlets, stackless, as well as a few iterations/variations of our own thing.

Heck, part of the reason we even made ShopTalk our first product was because we knew it played to our technical strengths and interests--we had learned time and time again how great a match long-polling HTTP and async are for each other. So, we gathered up everything we'd learned and examined it. Then, we tried to design a system that was an amalgamation of the best ideas we'd been exposed to over the years... a system that let us write async the way we really wanted to.

And now, given the community's interest in the general topic, we've decided to open source it. Meet diesel.

It's generator-based to retain a blocking feel, and writing protocol handlers is a cinch. It comes with a complete HTTP/1.1 implementation, so you can get started doing Real Work with it right away.

Here's what an echo server looks like:

from diesel import Application, Service, until_eol

def echo(remote_addr):
    their_message = yield until_eol()
    yield "you said: %s\r\n" % their_message.strip()

app = Application()
app.add_service(Service(echo, 7050))
app.run()

And yes, it's fast; very fast.

The big picture is that we're building a larger framework to make web apps that use scalable, event-driven push behavior, simple and fun to write. What we have right now is just the geeky, low-level core--the "engine".

We plan on rolling out the next two components soon. In the mean time, give diesel a whirl, and drop us a line with any questions, bugs... or just tell us what you're doing with it.

And, like any good Python project, it's in the cheeseshop and on bitbucket.

Do you instant message your coworkers? Try ShopTalk instead. It's better.