Bootstrap Checkpoint Zero

I'm a part-time entrepreneur, and I've referenced in the past how I'm particularly interested in bootstrapping businesses. This fascination has actually come from the experience I've been having working with Justin, Austin, and Hunter on Anchor Tab. Bootstrapping a business is hard, because you've got to make hard choices about what to do and what not to do to get something out the door that people will pay for. From an operational standpoint, we have a very specific advantage over some other businesses out there.

Jesting aside, there's a lot of skill and luck that goes into what I've taken to calling "Bootstrap Checkpoint Zero," which is the point at which your business isn't incurring any additional debt each month. We've reached that point with Anchor Tab.

The first phases of a bootstrapped business are all about learning. You more or less try to validate the broad idea with customers, then you sit down to make the MVP in a semi-vacuum. You debate over what's actually minimally viable, whether or not to hire a professional designer, how much to budget for different aspects, and things are constantly changing.

Towards the end of the construction of our MVP, we entered a pilot stage and started bringing on our first five customers and try to take their temperature towards the product. It was a moment of truth to see how far off track we got in our MVP building. We got some great feedback during that phase that helped us prioritize the packaging that we did for our beta. Then we launched the beta. We gave around 30 users, mostly strangers, access to our product for free. We got more feedback. Some people loved it, some people didn't, but people were talking us, and that's what we needed.

So we went from having only the team poking around the product to 30 people in a short period of time - friends and strangers, doing it live. That can be scary, but it's always needed. Here are some of the things we learned as a result:

  • The first interactions with the site were a bit confusing. You kind of had to poke around a bit and figure out what was supposed to happen next. We introduces a "first steps" section in our dashboard to help address this problem. Users are presented with the steps they can take to get started, starting with connecting an external service.

  • Our first stab at MailChimp integration was unacceptable. We knew it was dodgy because the MailChimp wrapper we were using didn't support retrieving what lists existed on an account at the time or retrieving information about the user you were authenticated as. This meant hoop jumping and confusion for our users. So, we augmented the functionality of that library. As a part of our policy of giving back to the open source community that has so richly supported us, I made those improvements public (here and here) and now anyone can use them.

  • Figuring out how to access the tab embed code for your tab was unclear. This is the code you need to drop on your site for your tab to work, so it's pretty darn important that you know how to get your hands on it. We had people creating tabs and then not having any idea how to use them! We put a pretty big plug in this problem by showing you a screen as soon as you create your tab that shows you your embed code and explains what to do with it.

  • Our messaging is unclear. This is actually a bit of an ongoing problem. As an example, we had at least one pilot/beta user expect our product to behave more like Hellobar, which it intentionally does not. Justin, Austin, and Hunter have been working on refining our messaging. They've been having conversations with customers to identify how the website has fallen short, and will continue to do so. We have new messaging for the landing page in the works as a result of these conversations.

  • We had bugs, lot of em. Our product runs in any number of different environments and has to behave and appear consistent across all of them. That's hard. Things were broken in some cases.

The feedback resulted in a lot of work for me in updating the product, making it more usable, adding those finishing touches that make it feel like a coherent user experience all around. Then, we launched the MVP with a free month of service for all users who participated in the beta at the start of April.

At that point it was a waiting game. We released a whole batch of new features to our users and let them play with it. We just needed to wait and see what would happen. As it turns out, we had enough people enjoy the beta and sign on after the 30 day trial that we're covering our monthly systems operations expenses. We've also continued receiving valuable feedback.

One of the best things at this point is that we're not driving our priority list, our current and potential customers are. So, what tops our priorities at this point?

  • The messaging still isn't completely clear. That's numero uno.
  • We need to expand our services support. We've got two more on deck that should be going live soon, if all goes according to plan.
  • Proper behavior in tablet and mobile environments is clutch.
  • Better analytics.
  • Improvements to our NewRelic error monitoring to preemptively alert us to service failures due to bugs in our code. And fault handling behavior for situations where things have gone wrong.

The actual list of things on deck is much larger, but those are at the top for now. Exciting times are ahead, to be sure.

As always, leave me some comment love below. I'd love to hear from you. You can also comment in and up vote the Hacker News discussion. See you next week, kids.

Polymorphism in the Database: Lift and Mongo

There are a number of reasons I love Lift. I was thinking through some architectural changes that are coming with Anchor Tab soon and I realized that the integration between Lift (the web framework), lift-json (the JSON parsing library), and MongoDB are is pretty sweet. Let's say that you're working on a pet-themed website and you need to store information about some cats and dogs. You would probably define something similar to the following data model.

This is an entirely sensible data model. (Albeit, my naming of classes could probably use some work, but this'll suffice.) So, what would it look like if I wanted to take an instance of one of these objects and turn it into something that could be then turned into JSON? (Let's say, for an API.) That code would look something like this.

In the example above, the jvalueDog is an instance of JValue. You can think of JValues as lift-json's intermediary format between real domain model objects and actual, stringified JSON. (If we were to be proper, we'd say it's a part of the Abstract Syntax Tree, but that's a mouthful.) You're able to query them for their content, manipulate their structure, and do all varieties of fun things with them - including return them as the result of a function that's exposed as a REST API, and have Lift handle the serialization processes for you.

Part of what makes lift-json so beautiful is it's adept use of reflection to automatically figure out what things in a JValue should be named and how things fit together during the deserialization process. But there's a rub with this reflection and our data model. What if we want to serialize and deserialize an entire AnimalInfo object? We'll see that we run into a problem. Take, for example, the following code:

As noted in the comments, the code above will fail to execute. In fact, not only will it fail, it'll blow up pretty spectacularly because it can't directly instantiate an Animal.

The solution to this problem lies in a concept in lift-json called type hints. Type hints are attached to the serialization/deserialization chain of lift-json. During serialization, if a class that is being serialized matches one of the classes that we indicate we want a type hint for, lift-json will add a jsonClass parameter to the JValue as it's being built. To define type hints, all we have to do is adjust our formats definition, and things will start working for us.

The above example will work because on deserialization, lift-json sees the jsonClass parameter attached to the JValues, sees that they fit the interface Animal, and instantiates them correctly without fuss. This functionality sets us up pretty nicely for seamless polymorphism in the database.

Mixing in Mongo

The next step that we'd want to implement in this setup is to mix in MongoDB. Since MongoDB is a document store that (basically) stores JSON objects, lift-json and lift-mongodb end up working pretty well together. Also, unlike a conventional relational database, MongoDB's non-relational nature means it doesn't require that each document have the same fields. We can store our cats and dogs side-by-side in our AnimalInfo with no-fuss even though they don't have the same properties, and without having to drop NULLs in our dataset.

Converting the example code above to a functioning MongoDB representation is pretty simple with lift-mongodb's MongoDocument and MongoDocumentMeta traits. (We, of course, assume in this code that you've already connected to the database elsewhere.)

When you go back into your Mongo collection later and pull out that AnimalInfo, you'll find everything is the correct instance automagically.

Isn't life grand? This was just something that was on my mind today, so I thought I'd share the joy around.

Sound interesting?

This was a whirlwind, isolated example of what lift-json and lift-mongodb are capable of, and how little code is required to get something meaningful happening in the Lift/Scala ecosystem. It's just the tip of the iceberg. If you're interested in digging into these libraries, or Lift, here are some useful springboards:

As always, leave me some comment love with thoughts, errors discovered, or locations of free cookies. See you shortly. :)

If You Do Something, Stand For Something

Startups are a wonderful thing. When startups get to solve a problem that hasn't been solved before or they get to shake the cages of the establishment to spur innovation, they're at their best. When they're playing with a formula that's already been done a hundred times, they're at their worst. Somewhere in the middle is where you find most startup companies.

The problem with the middle is that it's both highly lethal and highly intoxicating. It's highly intoxicating because being somewhere in the middle will usually provide a degree of predictability in terms of profits. It's lethal because hanging out in the middle makes it difficult to recruit excellent engineering talent across generations. The trouble with this mental model is that there are plenty of people who hang out in this space who do fine. (Anchor Tab certainly does to a degree.) Can trying to maintain a balance really be that bad?

This entire post stems from an experience I had in November and December as one of the kickoff members of a startup company. I was the de-facto primary architect for the time that I was there, but I was miserable. I sent in my letter of resignation the day after Christmas. I've battled for a long time over the difference between my experience at OpenStudy, Anchor Tab, and Elemica, and my experience with this company, who I'll call Widgets Inc.

After a lot of internal processing, here's what I came up with: the teams I've loved working for said something. They stood for something. As a quick overview:

  • OpenStudy: Real substantial learning can happen in an online, realtime context.
  • Anchor Tab: An email marketing tool can be a quality piece of software that is beautiful, cross platform, and useful.
  • Elemica: Whether it's official or not, I feel like there are a lot of people on our team who are passionate about going to great lengths to break the negative connotation with enterprise software. I certainly am, and that drive has taught me more about the Scala language and the JVM in the past few months than I could have ever learned on my own.

The result of standing for something is that the priorities are always clear. And let's be clear about this: the thing that your company stands for is not the same thing as the problem your product solves, because if that's all your company stands for you're entirely at the mercy of your customers. If what I stand for is to solve your problem, but I don't solve your exact problem, why shouldn't I change my product to meet your needs? Also, why bother investing two days to invest in the solution that's 800 lines of code less than the original one? It doesn't gain us extra dollars!

My line of thinking, much inspired by 37Signals, is that the product should be made with a vision, made with something that it stands for. Either a feature fits with that, or it doesn't, and that's something to be weighted when considering the addition of new features. And, as the 37Signals guys, if our product doesn't meet your need because it's out of line with our vision, that's fine. I'll happily refer you to some of my competitors who can meet your need. No hard feelings.

At Widgets, we never had a mission communicated to us. We knew what we were building, but our CEO didn't give us something to stand for. So, do you see what happened? Yep, you guessed it. We were in no-mans land.

  • Leadership communication was a disaster: no mission was communicated. As a result, my coworkers and I developed different ideas about what our priorities were and wasted valuable engineering time arguing. We knew the problem our software was supposed to solve, but we failed to agree on what it was supposed to say.
  • Engineering decisions weren't made by engineers: we were sticking with the one formula that had worked in the past above all else. Management dictated a formula that had worked in the past because that provides the most predictability in the terms of profits. We were given very little breathing room to innovate. This stunts the opportunities available to recruit top talent in the young generation because it gives us no more control (and by extension ownership) over the product than we would have at an Oracle-sized company, and stunts the opportunity for recruiting those in an older generation because they won't tolerate the risk of a startup if they don't get to play with the technology side of the equation. It's not worth it to them. Sure, you'll get engineers, but you won't have the truly talented engineers knocking down your door. (Unless, of course, you've got a lot of hype around you after a successful exit.) 
  • Both points above yielded a team with absolutely no mutual trust or respect that was, in my assessment, dysfunctional.

Ultimately I decided to walk out, and it was a spectacular decision. I'm on a great team that I love, and I'm planning on being here for awhile. But, honestly, I decided to completely disengage from the startup community as a result of this experience, because I realized that so few startups in the Atlanta area are actually, as Antonio would say, "Doin' it right." I want a 37Signals of Atlanta - a group of code bandits who are serious enough about building a quality product instead of profiting off of the ignorance of their customers and making compromises until it, as it always does, blows up in their face. I'm sure there are people like me who feel that conviction in every corner of Atlanta's technology sector, but where's our bullhorn?

I want a startup community in Atlanta that's vocal about standing for more than just getting the quickest profit. The profit-seekers have been getting the word out pretty well about how their formula is working out to their benefit. I say it's time that we start getting the word out that it's possible to do it right, and make a profit. Let's expand the conversation about startups in Atlanta from mere discussion of rounds and exits, to discussions on bootstrapping, innovation, and long-term job creation. Will you be running twenty companies at once? Nope, you'll probably only have enough hours in the day for one at a time. Will you be able to hide behind the twitter account with a cute headshot and nice one-liners? Negative, you'll need to be three-dimensional and really get to know the people around you, but in exchange you'll have an opportunity to impact the community around you for decades to come.

My name is Matt Farmer. I'm a Christian, amateur photographer, professional instagrammer, music-lover, coffee/beer-snob, and a Software Engineer. I'm one of a group of dreamers working on a project that aspires to help promote and encourage this type of conversation in Atlanta. Dreams are infectious. Will you dare to dream with us?

Canvas, Chart.js, and Retina

Hey folks, so, just a quick one tonight. We ran across an interesting bug on Anchor Tab awhile back that I finally got around to looking at. So, to start, on Anchor Tab we have this magical chart that shows you your views and submits for the last seven days. Presently, mine looks something like this.

Yes, I have a very sad subscribe rate. Then again, most of the people who read this blog are friends who catch my posts via Facebook or Twitter, so that's to be expected for someone in my sector, I guess.

The graph you see above is drawn with the brilliant Chart.js library. Honestly, we started out beta testing with a test version of Highcharts, but couldn't afford the license. Then we found this, and it's awesome. Go check it out.

Anyway, Justin was reporting issues on his Retina MacBook Pro. The graph was appearing much larger than it should and breaking the page. Today, on a wild hare, I decided to check it out on my retina iPhone to see if I had the same issue. Sure enough, I did. So I hooked her up to my computer's web inspector and found this in my DOM:

Somehow there was logic in place to quadruple the size of the canvas in the event you're on a retina screen. (WAT?) Not sure what's up with that, but the fix, for me, was to manually set the width and height to their correct values in our CSS file and add a "!important" onto the end of each rule so they overrode the width and height set on the element itself.

Figured I'd go ahead and put this out here, in the hopes of saving someone else in the future a bit of time.

Cheers,

Intelligent New Relic Transaction Naming with Lift

So, I was going to wait until the artifact showed up in Maven Central, but I've got other things to do today in this beautiful weather that are decidedly better than staying indoors and waiting on Sonatype to finish publishing my artifact.

Today I released an add-on for Lift projects that want to use NewRelic for monitoring: lift-newrelic. The purpose of this little add-on is really simple, you drop it in your Lift project and it automatically sets the name of the transaction in NewRelic based on the URL that the SiteMap Menu entry that matches the current request.

Why do we need this?

The default behavior in NewRelic is to use the name of the filter that's used to serve the request. In Lift apps, there exists one filter, /LiftFilter, so the result is that you get all of your transactions filed under /LiftFilter in your NewRelic Web Transactions list - totally useless for helping to identify hotspots in your production code.

With this add-on, your SiteMapped entries are named intelligently. Normal Menu entries just contain their URL. So, the forgot password page for AnchorTab shows up as "/amnesia" on our NewRelic account. However, it's also smart enough to handle parameterized types. So, an edit mage might look something like "/tabs/star/edit" in NewRelic.

RestHelper currently isn't supported, but I'd be interested in accepting a patch from anyone who may have an idea around how to do that. :) So, now that you know about it, go check out the GitHub project and use it! It should be on Sonatype shortly, too. :)

Cheers!