Everything is a remix; making the best use of conventions to build Runscope.

dont-make-me-think-cover.jpg

One of the most influential books of my software career is Steve Krug's Don't Make Me Think. While the book is a little dated now, it contains a plethora of software design gems. The one that stuck with me the most over the years is "Conventions are your friends" in Chapter 3.

Short of copying and pasting the whole section, here are my three favorite excerpts, starting with how an idea becomes a convention:

All conventions start life as somebody’s bright idea. If the idea works well enough, other sites imitate it and eventually enough people have seen it in enough places that it needs no explanation.

Why conventions are useful (emphasis mine):

As a rule, conventions only become conventions if they work. Well-applied conventions make it easier for users to go from site to site without expending a lot of effort figuring out how things work. (...) There’s a reassuring sense of familiarity...

Krug's ultimate recommendation:

Innovate when you know you have a better idea (and everyone you show it to says “Wow!”), but take advantage of conventions when you don’t.

Reduce, Reuse, Recycle

About a year ago I started on the initial product design that would become Runscope. Knowing we were building something completely new I wanted to introduce as few new concepts as possible. With Krug's voice in my head I was determined to make the best use of existing conventions.

I thought it would be fun to look back at the concepts we borrowed from other services with the benefit of hindsight. Which ones worked out? Which do we regret? Let's find out.

Buckets

Buckets are the term we use for organizing your requests by project, app, customer or whatever else works for you. The name was borrowed from S3 but my intial idea for how they would work was more like Gmail's filters and labels. Using a well-known name from another developer tool with the behavior from another tool ended up being pretty confusing. Some early external feedback drove this point home and in the end buckets ended up much closer to their S3 brethren. Verdict: right decision after an adjustment.

Stars

In a fast moving stream of API calls, we were looking for a way to single out requests to save and easily reference later. Gmail's stars seemed like a good model for this. That ended up to not be the case. It forced people to use buckets for lighter-weight organization and those weren't a good fit for a variety of reasons. We needed a middle ground: a simple organization method within a bucket. Verdict: Not a useful convention for us.

Collections

We replaced Stars with Collections. They're conceptually similar to Gmail's labels: lightweight, user-defined and optionally one-to-many. With starred requests you had to attribute your own meaning to what starring meant. For collections, you define the meaning in the name you give them. It's much more flexible. Verdict: Right decision.

In need of a way to share API calls across account boundaries (e.g. to send to an API's support team) I immediately thought of Dropbox's shareable links. We implemented it just like Dropbox, with an explicit click to make a request public and create a public, shareable URL. Public links can be revoked at any time. Revoking and resharing creates a new, unique URL.

A funny thing happened. When asking people to share requests with us, people would click the link to go to the share preview page and then send us the URL for that page, even after clicking the 'Create Share Link' button and being presented with the public URL. Even making the button and resulting URL much more prominent didn't fix it. It took a little bit of history.replaceState() cleverness to mitigate the confusion.

If I could go back, I'd simplify the feature. Every request would have a single non-guessable URL with a simple public/private visibility toggle (like Sentry). We may still do this, though revokability is an issue. Verdict: Right idea, but a little over-engineered.

Teams/Organizations

The first version of our identity database had tables Accounts and Users with every user belonging to a single account. Frank wisely deleted that as soon as he saw it. People very rarely have a single organizational association. We ended up using the GitHub model of users and organizations (we call them Teams). This has given us and our customers a lot of flexibility. Verdict: one of the best early decisions...thanks Frank!

Many More

These examples are just from our initial Traffic Inspector product. In Runscope Radar (our new product for automated testing) we've also re-used concepts like integration testing assertions and variables with a Mustache-like template syntax.

Next time you're designing a new feature, listen to your inner Steve Krug:

Sometimes time spent reinventing the wheel results in a revolutionary new rolling device. But sometimes it just amounts to time spent reinventing the wheel.

How Runscope raised a $1.1M seed round without customers, revenue or even a product.

I’ve been seeing a lot of posts lately on how to raise money from venture capitalists for your startup. I used to gobble that stuff up, reading any and every post I could to try to glean any insight I could into the process. Now that I’ve been through the process and have the benefit of hindsight I’ve concluded there’s no universally-applicable advice other than this: your mileage may vary.

Fundraising is a crazy experience, and every founder who’s tried will love to tell you just how crazy it was for them. Your story always feels like the worst possible case until you hear someone else’s. For instance, another founder I knew was raising around the same time we were. They had a product, revenue and had just graduated from an accelerator. I felt like we had no chance compared to where they were at. They didn’t get funded and the company is gone. We did, and we’re here.

I’ve been asked a lot, “How did you pull it off?” We had three things working for us: the right people, a ripe market and a good “story.” My approach to pitching was to hone in on those three things and ignore everything else.

The Right People

When I left Twilio, I really wanted to get into consumer web stuff. IFTTT was the perfect hybrid between dev tools and consumer services. Except I repeatedly found myself drawn back to building dev tools. My co-founder Frank is the same way. Everywhere we go, we build tools because it’s what we love to do.

Between the two cofounders, we also had the right talent mix. My background as a developer, product manager and evangelist and Frank as a Lead Engineer on a popular API. We had the skills and track record. Selling the team was always the easiest part of pitching.

A Ripe Market

APIs are blowing up. App developers (especially mobile) are building and relying on more APIs (even if they don’t call them that) than ever. The trend is clear. Existing API tools are all focused on API providers. App developers need tools too.

The most common question I got was “How big a market is it?” How many apps can you imagine not talking to a remote web service in the future? That’s how big it is. This was also easy to pitch.

A Good Story

Investors hear from good teams, with good ideas in good markets all the time. That was the minimum bar for getting in the door (being relatively well-connected also accelerated the process). But I think what made the biggest difference was the story we told about getting from where we are now to becoming a huge business.

I tried to paint as vivid a picture as possible. Like any good story it had a beginning, middle and end. I explained how product development and marketing would progress and dovetail with each other over time. What the target audience was for each phase. How each phase set the stage for the next one. What we learned from working at a company that went through the process already. After the first few meetings I proactively addressed concerns before they were asked.

Knowing our story inside and out gave me a lot of confidence. The more people I told, the more confident I got that we were on to something. Paul Graham covers this in ‘How to Convince Investors’:

Investors are not always that good at judging technology, but they’re good at judging confidence. If you try to act like something you’re not, you’ll just end up in an uncanny valley. You’ll depart from sincere, but never arrive at convincing.


Raising money was not fun. It was stressful and time-consuming. I feel incredibly fortunate to have had it work out. We ended up with great investors and never felt like we had to “sell out.”

It’s still early for Runscope. We are finding our way and we’re a long way from successful. So far I’m happy with how it’s going. We’re on track to meet our goals, we have a great team (what I’m the most proud of) and we’re having a lot of fun.

A Survey of the Localhost Proxying Landscape

In late 2009, soon after coining the term ‘webhooks’ and starting to evangelize them to the world, Jeff Lindsay ran into a problem.

I had another idea while thinking about webhooks. It would be great if I could expose a local web server to the Internet with a friendly URL. It should just be a simple command. There would have to be a server, but there could just be a public server that you didn’t even have to think about.

Jeff’s idea grew into localtunnel, a friendly wrapper around an SSH reverse tunnel that makes your localhost available via a public URL. The first time I used it, it felt like magic. It completely changed the nature of working with webhooks. I was, well, hooked.

What was novel at the time has grown into a little bit of a cottage industry amongst API tool makers. Many similar services have cropped up, specializing in different versions of the same problem. Here’s an overview of all the services I know of.

localtunnel

The original. The initial SSH-based version with the Ruby client eventually ran into some issues. Ruby and SSH are also a bit precocious on Windows. Jeff later released a beta of a version 2 with a Python client and a new wire format. Localtunnel has been discontinued in favor ngrok (see below).

localtunnel.me

A Node.js copy of the original localtunnel that couldn't come up with an original name.

Forward (formerly Showoff)

Forward was another early entrant, focusing more on allowing developers to show off web sites they were working on from their local machine. In early 2011 they rebranded from Showoff to Forward. They offer a few different pricing plans for various needs.

ProxyLocal

Another Ruby based solution, ProxyLocal was started in late 2010 and was last updated a year ago, though the web service seems to be operating still. It distinguishes itself from localtunnel by letting you choose the subdomain for your public URL. The service is free.

PageKite

PageKite is another commercial service started around the same time independently of the others (this comment suggests localtunnel predated it by only a few months). PageKite is Python-based, open source, offers end-to-end encryption and can tunnel protocols other than HTTP. Here’s a post comparing it to Showoff. They offer subscriptions, pay-what-you-want and a free plan for OSS devs.

Ultrahook

Ultrahook is a new entrant to the scene, focusing on webhook debugging. Created by Vinay Sahni from SupportFu, Ultrahook consists of a client distributed via Ruby gem. The service is free, but the source is not available. By signing up for a free account you’ll receive an API key that “gives you a exclusive namespace. All endpoints you create will be subdomains under your own namespace. This ensures that you can always reconnect to the same endpoints at some point in the future.” Ultrahook does not proxy responses back and only supports POST requests.

Finch

Another Node.js client/server, currently in beta as of May 2014. Paid plans will be offered when it officially launches. As it is in beta at the time of this update, the full feature set is unknown.

Vagrant Share

Vagrant Share is a solution for sharing web servers (or any other TCP/UDP connection like SSH) running inside your Vagrant environments. Uses TLS end-to-end. Requires a Vagrant Cloud account.

ngrok

The current king of localhost proxying is ngrok from Alan Shreve (formerly of Twilio). ngrok is written in Go (both client and server) and has, by far, the easiest client installation options with single-file executables for Windows, OS X and Linux. No more fighting with Ruby gems Windows users! In addition, ngrok adds an introspection layer so you can see the traffic that was passed back and forth over the tunnel and even retry requests. ngrok supports SSL, password-protected tunnels, reserved subdomains and support for TCP/UDP tunneling. It’s free and the source is on GitHub.

Runscope Passageway

My company Runscope also offers a version of ngrok called Passageway. We’ve added tight integration with the Runscope API Traffic Inspector and some other enhancements to create a more seamless experience with our other products.

My Recommendation

If you’re just getting started, I recommend ngrok. Client set up is the easiest and it offers the most features of any of the options and its completely free.

Did I miss any? If so, let me know in the comments.

Update 5/18/2014: Added Finch, localtunnel.me, Vagrant Share and updated details about Runscope Passageway using ngrok instead of localtunnel.

Photo courtesy of Tina Carlson

API Changelog: API Documentation Change Notifications

My company Runscope just launched this free service for tracking and sending notifications for changes to the docs for 23 popular APIs including Facebook, Twitter, Stripe, Twilio, Dropbox and more. Follow the APIs you depend on and receive a daily email summary if anything changes.

Launched

Today we opened the doors on Runscope, our new set of tools for debugging, testing and inspecting your API integrations. In addition to that, we announced that we’ve received a seed round investment of $1.1M from True Ventures, Lerer Ventures, David Cohen, Andreessen Horowitz, Nat Friedman, Jon Dahl and Ullas Naik.

While launching to the public is a lot of fun and the culmination of a lot of hard work, it’s just the starting line for the next stage of what we’re trying to accomplish. Even so, getting here required a lot of help and support from a great many people and I’d like to thank those that were instrumental in helping us get this far.

First off, my wife Emily. When I told her I wanted to quit my job to start a company she didn’t even flinch. When fundraising hit rough patches she was unwaveringly supportive. Thank you honey.

Next up, my co-founder Frank and the rest of the team that has joined us in the past few months: you’ve done amazing work in a short period of time and you’re a blast to work with. Honored to be working with you.

To Nat Friedman, Jon Dahl, Ullas Naik, Adam D’Augelli and the True crew, David Cohen, Ari Newman, Max Stoller, Steve Schlafman, Chris Dixon, and Frank Chen: I couldn’t ask for a better set of investors. Thank you all for your support.

And lastly to everyone else who helped with intros, reference calls, testing out the preview, advice, lawyering, finding office space, candidate referrals, etc: thanks for playing a small part in helping us get this far.

Now, the hard part.

API Digest 2.0

Today I’m happy to release a brand new API Digest. Previously the digest was email-only. Starting today all links will be available via apidigest.com and @APIDigest on Twitter and App.net. You can also subscribe to the RSS feed. Lastly, be sure to check out the new ‘Events' list.

Designing APIs for Humans

Earlier this month I gave a talk at Devs Love Bacon on an API design philosophy I picked up while working at IFTTT I’ve been calling ‘APIs for Humans’. Sadly, it’s not about this:

At IFTTT I identified three major areas for how non-developers end up consuming API data in significant numbers. In this talk I cover what those areas are and how you can tailor your API designs to encourage developers to build human-friendly integrations.

Since I had extra time I threw in a few points on developer experience too. After all, developers are humans too.

Authentication: Don’t be Clever

My contribution to the new API UX blog:

By using standardized, common authentication schemes you can reduce the cognitive overhead for the developer consuming your API and avoid getting into unfamiliar, untested security situations. Authentication is the first thing any developer using your API will have to deal with and it’s those first few moments that are crucial to their success using your API to solve their problem. Take care to make the first impression a good one.

The Good and the Bad of OAuth 2.0 Authorization Implementations

While testing out a new tool I’m working on that uses a variety of OAuth2 providers and thought I’d catalog some of the quirks I came across. This is just for the authorization flow, not for actually making requests once you’ve secured a token.

Now that the OAuth2 spec is solidified we should start seeing less and less of these issues.

Google

Good: The APIs Console is one of the best out there. My favorite feature: allowing you to specify multiple callback URLs for a single app. This makes testing different environments way easier because you don’t need to go back and constantly edit the callback URL value.

Good: The OAuth 2.0 Playground is fantastic. It will show you all the HTTP requests that are made for a standard auth flow. This makes it really easy to debug issues on your end by comparing the requests. I used it to diagnose the following problem.

Bad: When requesting an Access Token the request will fail if you include any parameters that it is not expecting. Google does not require a state or type parameter when getting the token like some other APIs do and will give you a 400 Bad Request with an invalid_request error if they are included.

Bad: The scopes options are not immediately obvious. There’s a huge list of services and you must enable them individually (good) in the ‘Services’ section of your project in the APIs Console. This page though does not list the scopes value to use. The Playground does have what appears to be a complete list.

Facebook

Bad: If you just want to use OAuth with the Graph API, you still need to enable “Website with Facebook Login” in order to set the Site URL. This is hidden by default and took me a little bit to find it. This setting restricts which domains they will redirect back to.

Good: The Site URL only requires a domain instead of a full URL which means you can change your callback URL path without breaking your app.

37signals

Bad: When you create the app you select which services you want your app to have access to but during the auth flow only one of the services is displayed.

Bad: There’s no support for limiting access to read-only via scopes. The only option is full read/write for all of the apps selected.

Stripe

Bad: Stripe does not use a client_secret. Most client libraries and OAuth examples use it so it may be confusing for experienced developers wondering where that value is.

Bad: This is not technically wrong, but it isn’t common. When exchanging the code for an access token you are required to send an Authorization header with a value of Bearer and your Stripe account secret key (either test or live). I’d rather they just tell you to use the secret key as the client_secret and not require the additional header.

Instagram

Bad: The docs say that the scope parameter is optional but will give you an error (400 OAuthException - Invalid scope field(s)) if it isn’t specified. You should specify at least ‘basic’.

Box

Bad: The redirect URL settings requires HTTPS which can be difficult if you’re trying to test locally (for instance my test app runs on http://localhost:5001 which is accepted every where else). Box has informed me this will be resolved soon.

Bad: Does not use scopes for read-only or read/write access (is configured with the application). Box has also told me they will be changing this once they have more than one scope.

Microsoft Live Connect

Good: Permissions are set via an extensive and clear list of scopes. Very nice.

Stack Exchange

Good: Callback URL validation is set via domain only (similar to Facebook).

GitHub

Bad: Scopes must be specified comma-separated, contrary to the OAuth2 spec. This is on the roadmap to be fixed.

App.net

Good: The application manager allows you to generate a token for yourself with custom scopes without having to go through the flow. This is extremely helpful during development.

Others

Here are some others that I tried that I didn’t have any notable issues with: MailChimp, Foursquare, Wordpress.

Here are the services I desperately wish would move from OAuth 1.0a to OAuth 2.0: Twitter, Dropbox, LinkedIn

If you’ve come across a unique implementation quirk of your own, post it below in the comments.

Related Posts

Age

This post is a little more personal and not at all technical. I realized I’ve been wanting to write about this for awhile.

On the latest episode of Hanselminutes two of my favorite internet friends had a discussion on age as they are nearing their 40th and 45th birthdays. I happened to come up a couple times as a reference point for The Young’uns.

Age has always been a sensitive issue for me. When I was 5 my mom homeschooled me and when she couldn’t do it anymore and it was time to go to public school I was effectively done with first grade so she bumped me ahead to second grade. The rest of my primary and secondary school years I trailed all my classmates in age by a year. I got my license my junior year, graduated at 17, etc. I played sports on teams consisting of all older players. I was always very determined to prove that my age didn’t matter.

When I started running companies when I was 15 my age was an advantage. It got me attention and customers. When I started working real jobs at 19 it was also an advantage because people couldn’t believe how mature and experienced I was “for his age.” At about 25 when all my peers had experience too (with degrees to boot) it wasn’t as advantageous.

Now I’m 31. In the SF tech scene I frequently feel old. My experience frequently gets deferred to (which often makes me slightly uncomfortable). Some of the younger engineers I’ve worked with lately have made me feel really old. They’re insanely smart but make me realize how much experience I actually have now (going on 16 years of doing computer stuff for money). 30 under 30 lists drive me crazy not because that’s my goal in life, but just because it’s impossible nonetheless. My wife consoles me by saying there’s plenty of time for 81 under 81.

Back to the Hanselminutes episode. Rob talks about a recent dinner we had together where he was giving me some advice (that I appreciated) and my reaction. I (not surprisingly) reacted by giving him a look that said I have it all under control. Almost certainly I was overcompensating for my age insecurities. I rarely feel like I do have everything under control and I crave insight from people more experienced than me.

At the same time, I do know some things now. More importantly I know what I don’t know. All of that experience has lead me to a position where I can be a founder of a startup. I’m not doing this because I’m young and impetuous and want to ride the wave of the current ‘bubble.’ I’m doing this because I know what it will take for me to be happy in my work and I’m not going to spend any more time not pursuing it. I’ve known that for a long time, but I’m at a point where my age is an asset in making this happen. So I’m going to.

Runscope

I’m very excited to announce that I have co-founded a company. If you use APIs in your mobile or web applications request an invite to our early preview. We’re still very early in this and will be talking about more details as we progress.

The plan when I moved out to San Francisco was always to eventually start something of my own. I learned a ton working at Twilio and IFTTT and now hope to apply that knowledge to build a great company. Now’s the time. We’ve got a great team and a giant problem to solve and I can’t wait to show it to all of you.

Follow Runscope on Twitter to track our progress.

Box API v2: Less is More

Box has updated their API to version 2 and has simplified it along the way. The highlights:

  • Consistent request/response models
  • Convention-based attribute names (please do this in your APIs)
  • No more XML, huzzah!
  • Better events streams (I hope that Webhooks follows)
  • Settled on OAuth2 standard

My favorite line:

There’s an inherent impedance mismatch between XML and regular humans.

These are all very developer-friendly changes. If you’re designing an API, there’s a lot to learn from Box’s experience.

Source: http://developers.blog.box.com/2012/12/14/...

Traffic and Weather: My new Cloud/API Podcast

Steve Marx and I had such a great time with the conversation I posted here that we decided to do it every week. Check out Traffic and Weather, a (mostly) weekly news and commentary podcast about all things cloud and API. We’ve already done two episodes and I’m really happy with how they’ve turned out.

Subscribe to the RSS feed or subscribe in iTunes.

Lastly, thanks to my friends at SendGrid for sponsoring our first few episodes.

Craving Conversation

Twitter is my water cooler. I blow off steam, talk about what I’m working on, learn new things from others, etc. For the first few years I spent using the service it seemed like every night there was an awesome conversation going on. Lately it seems like people have been conversing less and retweeting more. I don’t know if it’s because I’ve shifted away from following people in a specific tech community (the .NET crew seems to have focused their conversing there more than the others I’ve observed) or just a general behavioral shift in how people use Twitter (or both) but lately I’ve been missing those great conversations.

Other social networks never really filled the gap. Google+ was OK, but activity tapered off pretty quickly after it launched. App.net is still promising, but nascent and hasn’t grabbed me yet. I almost started a site just to share links and discuss APIs just to have it. I’m not famous enough to bootstrap a discussion community though (learned that lesson once before).

Then Google+ Communities were launched a few days ago. You can create them by topic. They’re moderated. The posts work like any other G+ post so links, etc. are first-class and each item has comments. To me, this is the perfect application of the G+ stream structures and having them scoped by topic solves the problem of having to follow someone who may post a lot about stuff you’re not interested in.

Ultimately, it’s another message medium like many before. The quality will be determined by the people that contribute to the community. But it’s looking promising. You can find me chatting about APIs over there.

X-Callback Header: Evented Web Building Block by @progrium

The X-Callback header is a proposal for a common way to describe HTTP callbacks, primarily in the case of registering them.

Great proposal from my former Twilio colleague Jeff Lindsay for instructing a server to respond to an HTTP request via a callback instead of a synchronous response.

A couple of tweaks I would suggest:

  • Rename the header name to Callback-Location (or something). X- prefixed headers are being discouraged these days.
    • Use a 2xx class response code to indicate that the request was received and the callback registered. The current definitions of 200-206 don’t fit well enough for my liking.

Jeff is working on advancing the state of Webhooks into something more standard-like, so his blog is definitely one you’ll want to keep an eye on.

A conversation with Steve Marx

I’ve wanted to record the kinds of conversations I have with the interesting people in tech I meet and Steve Marx of Site44 and Webscript.io fame (and formerly of Microsoft Windows Azure fame) was willing to be the first guinea pig in this experiment. Let me know what you think in the comments or on Twitter.

Length: 52:53

Recorded: 11/12/12

Download MP3

Links mentioned:

Super Hexagon (iTunes)

Super Hexagon is deceivingly simple. It looks easy, but it’s probably the hardest game I’ve played on iOS (lasting 60 seconds is a good score). Perfect casual game with great music. If you get dizzy easily or have a history of inner ear issues, you may not like it.