Well that sucks, what else you got?

Posted October 16, 2012

The Conversation

It was getting towards the end of the breakfast hour on the second day of Business of Software, and people started getting up to refill their coffee before the first session, leaving only Jason Cohen and me to chat while we finished our meal.

"So what do you do?" he asked me. I explained that I used to work for Fog Creek, but now I was off on my own, trying to start a company that provides photo backup for serious photographers. He asked the questions I've come to expect from people in the tech industry. "How is it different than Dropbox/BackBlaze? Where are you storing the files?" And so on.

Then he asked the key question. "How's it going so far?"

"Well, to be honest, very slowly." I proceeded to describe how we'd gotten a strong showing of interest by being featured on betali.st, only to have to drastically restructure pricing in a way that significantly cut our margins. Then, how, even with the new pricing, conversion rates were dismally low. I explained who our competition was and how we were having trouble explaining to our users why we were better. I repeated an observation that a former coworker had made, that the photography market is inverted, amateurs have plenty of money but don't care (that much) if they lose their photos, while professionals, whose businesses could be devastated be losing a single shot, don't have a lot of extra money to spend. Lastly, I pointed out that an effective marketing campaign would almost necessarily rely on convincing people that something bad (i.e. losing all of their photos) will likely happen to them sometime in the future, a particularly unappealing proposition to me.

Jason listened patiently while I explained all of this, and then summed it all up.

"Well that sucks, what else you got?"

The Realization

It had slowly been occurring to me over the past week. Snaposit was probably done. My co-founder, Jeff and I had already put it on the back burner to focus on Jeff's photo deblurring software, Blurity. Further development was becoming harder to justify.

Over the course of Business of Software, I became more open about talking with people about the problems we were running into. The hope was that the more experienced entrepreneurs I was talking to would be able to provide some reassurance. But reassurance was not forthcoming. If anything, I was hearing more reasons why it would be a tough sell.

My talk with Jason gelled it all together in that single phrase. "Well that sucks, what else you got?"

I realized it at the time, but it took me another few days before I could admit it. Keeping Snaposit going just didn't make any sense. Sure, it wasn't hemorrhaging cash, but it did have a slow leak. More importantly, it was still demanding enough attention to be detracting from other projects. To keep it running in the hopes that it might miraculously take off at some point in the future was unrealistic. It was time to shut it down.

The Causes

Poor Conversion Rates

While we were thrilled with the response from betali.st, the subsequent conversions were abysmally low. With those numbers, we would have to find traffic sources ten times larger than betali.st, every week for two years before we would even reach the level of "lifestyle business". Of course, we could hope to improve the conversion rate or the incoming traffic, but the numbers were still pretty poor. More realistically, it would take us much longer to hit the sort of revenue levels we were looking for.

Misunderstanding Our Market

In hind sight, there was a disconnect between what people said they thought was a good idea and what they would actually pay for. Almost everyone we talked to said something similar: "That's a really good idea." We heard it enough times that we really thought we were onto something. But there were two problems with this feedback: First, we were talking to more software developers, friends, and family than actual photographers. Second, we were just getting feedback on the idea itself, not on whether people would pay for it or not. Of course people think an automatic backup service is a good idea. It's like flossing, one of those things that everyone knows they should do, but the majority of people still neglect actually doing.

We also didn't fully understand what photographers wanted and needed. One of Snaposit's big features was that it backed up your entire library faster than a general backup service. It did this by compressing the photos to full resolution, high quality JPEGs, which saved anywhere from 50%-90% of the size. The downside of this, of course, is that photographers who shoot in RAW would only have a JPEG copy backed up. We figured this was a reasonable compromise. In a catastrophic event, wouldn't a photographer rather have a JPEG copy than nothing at all? It turns out the answer was no. But we didn't ask that question, because we thought the answer was so obvious.

Lastly, we wrote the first version of the Snaposit desktop application for Windows. We figured, "We're photographers who use Windows, we'll be able to find beta testers for this version and we'll get to the Mac version once all the bugs are ironed out." Nope. We couldn't find a single beta tester who used Windows.

The Loss of a Founder

For various reasons, the amount of personal runway Jeff and I had differed greatly. At a point, it became very clear that Snaposit would not be pulling in revenue before we reached the end of Jeff's runway. He decided that, in order to remain financially secure, he would shift his focus to Blurity, which was much closer to having a reliable revenue stream. I fully supported his decision, but it meant that the majority of the Snaposit work fell to me after that point. While this seemed feasible at the time, in retrospect, it did cut the chances of Snaposit's success. Unfortunately, there wasn't really any other way around it, it was just the reality of the situation. To this day, I still fully support Jeff's decision.

The Lessons

Of course, the experience was not a total loss, by any means. We learned a lot from failing. Below is a quick list of what we learned about:

  • How to apply for Y Combinator and Tech Stars.
  • How to integrate Stripe's subscription plans.
  • Python on the desktop with WxPython.
  • Mac development and deployment.
  • How to organize and form an LLC.
  • A better look at the backup industry.
  • That Jeff and I work well together.
  • How to run an effective 99designs competition.
  • Twitter's Bootstrap framework.
  • Desktop deployment and installers.
  • How to ask better questions about our market.

All told, we actually did quite well. For this experience, we spent less than $1,000. Compared to an entrepreneurship class at any college, that's quite cheap!

The Next Step

Jeff is continuing to work on Blurity. The recent press he's gotten has kicked Blurity into overdrive and he's continuing to knock it out of the park.

As for me, there are a few small side projects that could use some attention. I'm also getting back into writing. A few larger ideas are percolating, but nothing's quite finished brewing yet.

Comments for this post can be found on Hacker News.

Gatekeeper: Using FUD to get Developers to Pony Up

Posted August 29, 2012

A new user comes to your site and downloads your installer. They extract the disk image and fire up the PKG file. They're greeted with this message.

Corrupt

"Hmm," they think to themselves, "maybe something went wrong with the download." So they download it again, extract the disk image and run the PKG file again. Same error. The file is damaged. Now running late to pick up their kids from school, your new users leaves, likely never to come back.

This is their first introduction to Gatekeeper, a new feature of OS X 10.8, a.k.a. Mountain Lion. Intended as an anti-malware feature, Gatekeeper prevents downloaded applications from running, depending on their source. Similar to the SmartScreen in Windows, Gatekeeper presents the user with a warning when they are trying to run unsigned applications.

However, there are two important differences between Gatekeeper and SmartScreen.

First, with SmartScreen, the user has the option to continue running the application, despite not being signed. However, the default option for Gatekeeper provides no option to continue.

Gatekeeper dialog

(Note, for applications, unlike PKG files, the warning dialog is somewhat more helpful, though it still does not allow the user to actually run anything.)

This causes problems for any developers who have not paid Apple $100 for the Mac Developer Program, as the users are not left with any obvious way of continuing past the warning. This includes many developers who have chosen not to release via the App Store. Jeff and I have run into this problem already with users of both Snaposit and Blurity.

The second, and possibly more troubling , is that Apple is the only source for developer certificates. With SmartScreen, there are a wide variety of certificate authorities and brokers to choose from, each of which offers different pricing options, so the developer has a chance to comparison shop, which yields prices on the order of a third of the cost of the Mac Developer Program. But for Mac developers, Apple has created an artificial barrier instead of using existing and well established signing practices in order to make themselves a monopoly for developer certificates.

Is there any way around it?

Yes, but you're going to have to educate your users. Each and every one of them.

There are two options:

The first, and easiest, is to instruct your users to Control-Click (or right-click) the application once they've downloaded and installed it. From the context menu, the'll need to choose "Open".

Context menu

When they start the application this way, they'll be presented with a slightly different warning dialog, which allows them to continue.

Gatekeeper dialog

The next time they launch the application, they shouldn't see any warnings.

The other option is to have them disable Gatekeeper entirely. To do this, have them go to System Preferences and choose Security & Privacy.

System preferences

Once there, they'll need to click the lock in order to make changes. Once they've unlocked the preferences, they'll need to choose "Anywhere" from the list of options under "Allow applications downloaded from:"

Security preferences

This will essentially disable Gatekeeper, reverting their computer's security to a state similar to OS X Lion. Obviously, this isn't ideal, but if it's something they might run into often, it might be the best choice.

Snaposit is Live!

Posted August 02, 2012

As I wrote about a few months ago, we applied to Y Combinator's summer class this year. We got an interview with Paul Graham himself, but ultimately we were not accepted into the program. But we didn't let that stop us.

So what are we going to do?

We're going to grab our bootstraps and pull hard.

I'm proud to announce that, after several months of hard work, our product and company, Snaposit has officially launched!

We flipped the switch yesterday, moving all of our beta users onto actual subscription plans. (Heavily discounted, of course, to thank them for their help.) As with all launch days, there were a few small bugs that cropped up, but overall the day was pretty quiet, which is always a good sign.

But we're not done yet. In fact, it might be safe to say that the past few months were the easy part. Now we have the task of making people aware of Snaposit and convincing them of how useful it is.

So with the celebratory drinks out of the way, it's time to get back to work. We've done a good job of pulling our own bootstraps so far, but there's a good bit more that needs to be done before we're fully on our feet.

Go Lock Your Laptop, Right Now

Posted June 14, 2012

My father's home was burgled today. Fortunately, everyone is okay and everything that was taken can be replaced. As with most burglaries, the list of items taken is a little strange and the list of items not taken is even stranger.

One thing the burglars did get was my dad's laptop. It's a first-version MacBook Air, probably of little value at this point. But, it did have a wealth of information on it.

My first question to my dad was "Did the computer have a password?". He didn't remember, which probably means it didn't. Of course, requiring a password to log in by no means guarantees that someone can't get in to the computer. But it does pose a significant road block to most people, and that's the point of any type of security: make it difficult enough that it's no longer worth someone's time or effort to break into it.

Consider for a second what sort of data someone would have if they got a hold of your computer. If you're like most people, your browser knows most of your passwords. That means access to your email, which means access to everything else. Speaking of email, they'd probably have access to every email you've ever sent or received, especially if you use a desktop email client like Outlook or Thunderbird. And then your files. Pictures of friends and family. Financial documents.

Now consider how easily your computer could walk off. As humans, we tend to have a flawed belief that it will never happen to us, but it has to happen to someone. Laptops are designed to be portable. And desktops are pretty easy to pick up and carry off.

So consider this a reminder to at least make sure your computer have a good password. It will act as a solid castle wall, if your computer is stolen. Also, get all of your passwords into a password vault, not your browser. Personally, I like LastPass, but there are many good ones out there. (If you do choose LastPass, make sure your sessions time out after a certain amount of idle time, so the passwords are harder to use.) If you have any sensitive files on your computer, consider encrypting them with a tool such as TrueCrypt.

Lastly, make sure you secure all of your computers. Especially that one in your pocket. It's the easiest to lose, and contains as much information as any of your other computers.

Update: I forgot to add this part, but you also may want to consider installing a lojack. Personally, I use Prey, which will send you location information, screen shots, and pictures from the webcam. You can either pay them for service, or set it up yourself, which is pretty easy to do.

Update 2: A reader wrote in suggesting that I also mention using full drive encryption. If you're using Windows, BitLocker (built into some versions of Windows 7) or TrueCrypt can do this for you. On Mac, use File Vault. Full drive encryption would completely prevent an attacker from gaining any access to the data on the machine.

Multiple Django and Flask Sites with Nginx and uWSGI Emperor

Posted May 16, 2012

I like Python, a lot. I'm one of those people who would use it all the time if they could, especially for web development. Which is convenient, since I'm currently working on my own company.

One of the drawbacks of using Python, though, has always been getting it to play nicely with web servers. I've never been completely happy with the options out there: mod_python, mod_wsgi, FastCGI, and uWSGI. They've all had some instability, performance issue, or other problem.

But this past weekend, while doing some server upgrades, I came across a relatively new feature of uWSGI that seems to be the ideal solution for hosting Python sites: Emperor mode.

When you start uWSGI in Emperor mode, you give it a directory to watch that contains all of your uWSGI config files. If a new file is added, the emperor process reads it and spins up loyal worker processes to handle requests. If a config file is touched or modified, the emperor will gracefully restart the associated worker processes. And if a config file is removed, the emperor will kill the relevant workers.

Installation

First, you'll need to install the latest versions of Nginx and uWSGI. I'll assume an Ubuntu install, but you should be able to modify this if needed.

$ sudo apt-get install nginx uwsgi

If you're on a recent version of Ubuntu, this should get you Nginx 1.2 and uWSGI 1.04. If not, you might need to add the PPAs:

$ sudo add-apt-repository ppa:nginx/stable
$ sudo add-apt-repository ppa:uwsgi/release
$ sudo apt-get update
$ sudo apt-get install nginx uwsgi

Upstart and uWSGI

Next, you'll need an Upstart script for uWSGI:

/etc/init/uwsgi.conf

description "uWSGI"
start on runlevel [2345]
stop on runlevel [06]
respawn

env UWSGI=/usr/bin/uwsgi
env LOGTO=/var/log/uwsgi/emperor.log

exec $UWSGI --master --emperor /etc/uwsgi/apps-enabled --die-on-term --uid www-data --gid www-data --logto $LOGTO

You may need to create the appropriate directories:

$ sudo mkdir -p /var/log/uwsgi
$ sudo mkdir -p /etc/uwsgi/apps-available
$ sudo mkdir -p /etc/uwsgi/apps-enabled

Now you should be able to get uWSGI started:

sudo service uwsgi start

The emperor process's logs will go to /var/log/uwsgi/emperor.log, so if you run into any errors, check there.

Getting Flask Running

Now we need to set up the configuration for one of our sites. First we'll do a Flask site, since it covers most of what we need to know for Django, as well.

Let's assume the directory structure looks something like this:

/
  var/
    www/
      flaskapp/
        static/
        templates/
        venv/
        app.py
        models.py
        settings.py

(Where venv/ is the virtualenv for this app.)

Let's start with the uWSGI config.

/etc/uwsgi/apps-available/flaskapp.ini

[uwsgi]
# Variables
base = /var/www/flaskapp
app = app
# Generic Config
plugins = http,python
home = %(base)/venv
pythonpath = %(base)
socket = /var/www/run/%n.sock
module = %(app)
logto = /var/log/uwsgi/%n.log

Conveniently, uWSGI allows for variables in its config files. In this case, we're using three variables, %(base), %(app), and %n. We define base to be the root directory of our app, app to be the module name where the WSGI application is defined (uWSGI will expect it to be called application. If it's called something else you should specify callable = foo in the config.), and %n is already defined for us as the basename of the config file, in this case, flaskapp.

We'll enable that config in a bit, but before we do that, let's get the Nginx config ready.

/etc/nginx/sites-available/flaskapp

server {
    listen 80;
    server_name mygreatstartup.com;
    server_name www.mygreatstartup.com;
    root /var/www/flaskapp;

    location /static/ {
        alias /var/www/flaskapp/static/;
        include /etc/nginx/gzip.conf;
        expires 30d;
        access_log off;
    }

    location / {
        include uwsgi_params;
        uwsgi_pass unix:/var/www/run/flaskapp.sock;
    }
}

That should be all we need to get set up. uWSGI and Nginx are already running, so let's enable the app and the site.

$ sudo ln -s /etc/uwsgi/apps-available/flaskapp.ini /etc/uwsgi/apps-enabled/flaskapp.ini

The uWSGI Emperor will see the new file (a symlink to the real config file), spin up new processes, and point it at that config.

Next, we enable the Nginx site.

$ sudo ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/flaskapp
$ sudo service nginx restart

(Nginx requires a reload to pick up config changes.)

If the DNS entries are properly configured, we should start serving our new site.

Getting Django Running

Fortunately, getting Django to run under WSGI is very easy, so we just need a couple of tweaks. First, the uWSGI config.

/etc/uwsgi/apps-available/djangoapp.ini

[uwsgi]
# Variables
base = /var/www/djangoapp
app = wsgi
# Generic Config
plugins = http,python
home = %(base)/venv
pythonpath = %(base)
socket = /var/www/run/%n.sock
module = %(app)
logto = /var/log/uwsgi/%n.log

You'll notice that the only real change is that we've called our app wsgi. This is just a convention that seems to be prevalent with Django apps; the WSGI app is put in a file called wsgi.py inside of the project directory. A simple version would look like this.

/var/www/djangoapp/wsgi.py

import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

Aside from replacing flaskapp with djangoapp in the rest of the config files above, everything else should work as specified.

Restarting Apps

If you ever need to restart a single WSGI app (Flask, Django, or anything else), which is usually necessary after any changes to the code, just run the following:

$ sudo touch /etc/uwsgi/apps-enabled/flaskapp

The emperor process will notice that the file has been touched and gracefully restart the process serving flaskapp.

That's it!

Comments are starting over at Hacker News

Update: Reader Jason emailed with a recipe for nested WSGI sites. In case you want to set something like that up, he's posted it on his blog.

You should follow me on Twitter. If you have any questions, shoot me an email.