Author Archives: kevin

About kevin

I write the posts

It begins

Email from my alma mater:

Dear Members of the Claremont McKenna College Community,

I am writing to update you on an important action taken by the Board of Trustees at its meeting on March 9, 2013. In particular, the Board acted to end the College’s “No Packaged Loan” financial aid policy. Beginning with the fall 2014 entering freshman class, the College will reinstate its former practice of including reasonable loan amounts of up to $4,000 per year in the financial aid package for need-based students. This policy change will not affect any current students during their remaining time at CMC, nor will it affect new students enrolling in fall 2013.

This decision was not taken lightly, as we know that there are challenges and pressures that some families face regarding the affordability of a college education. However, our current situation is best understood in view of the College’s long-standing commitment to need-blind admission and to meeting the financially demonstrated need of all admitted, domestic freshman students. The College’s Strategic Plan identifies need-blind admission as one of our most important values, and highlights the importance of insuring our need-blind policy is financially sustainable over the long term. Therefore, I wanted to take this opportunity to briefly discuss the background of the No Packaged Loan policy, and the reasons why the Board determined it was necessary to end the policy at this time.

The College adopted the No Packaged Loan policy in the spring of 2008, just prior to the global financial crisis, at a time when a number of CMC’s peer colleges and universities were implementing various forms of no-loan or reduced-loan policies. At that time, the College completed an extensive financial analysis of the cost of a no packaged loan policy. The financial projections indicated that the College could replace loans with grants within its existing financial aid resources through a combination of actions, including reductions in the amount of merit aid and, most significantly, a reallocation of unrestricted endowment funds that were then being used to support a 0% interest institutional loan fund.

The financial collapse that caused the recent economic recession soon followed. As with most colleges and universities, the economic conditions of the past several years have placed significant pressure on the College’s operating budget. The College has worked to navigate through this period, which has included increasing our commitment to institutional financial aid at almost twice the rate of tuition increases. But we have had concerns about the sustainability of the No Packaged Loan policy, as we have focused on doing everything we can to ensure CMC remains accessible and affordable to all qualified students, regardless of need.

It is within this context that the Board has been engaged this year in a number of important discussions related to the costs and funding of a CMC education, and about the No Packaged Loan policy in particular. This discussion has also included valuable insight and analysis from the faculty, particularly from the faculty’s Admission and Financial Aid Committee (AFAC), who examined the effects of the No Packaged Loan policy on lower-income and minority applicants since the program’s inception five years ago. The Board weighed the AFAC’s findings in their decision and is appreciative of this research.

Through these discussions and careful analysis, the Board decided that, although the No Packaged Loan policy was important to preserve, if feasible, the College’s overarching priority should be to preserve and protect the College’s need-blind admission policies.

In making the decision to eliminate the No Packaged Loan policy, the Board reaffirmed several important commitments:

That the College is committed to providing access to all qualified students based on academic talent and not on financial need;

That the College is committed to securing and strengthening its need-blind admission and to meeting full-need policies by making fundraising for financial aid a priority;

That the College is committed to ensuring that packaged loan levels are reasonable and affordable;

That the College’s financial aid budget will not be reduced by this decision, and ongoing evaluation of the financial aid budget should take place during the next five years.

To help meet these goals, the Board authorized the administration to develop a plan for a targeted fundraising initiative that will focus on securing additional support for financial aid.

It seems probable that many colleges and universities across the country will soon be conducting similar evaluations of their financial aid policies and making changes. It is important for each institution to develop a strategy that assists students and their families to afford higher education with a program that is financially sustainable for the institution. I believe that is what we have done here.

Sincerely,

Pamela Gann
President

Liked what you read? I am available for hire.

Submit forms using Javascript without breaking the Internet, a short guide

Do you write forms on the Internet? Are you planning to send them to your server with Javascript? You should read this.

The One-Sentence Summary

It's okay to submit forms with Javascript. Just don't break the internet.

What Do You Mean, Break the Internet?

Your browser is an advanced piece of software that functions in a specific way, often for very good reasons. Ignore these reasons and annoy your users. User annoyance translates into lower revenue for you.

Here are some of the ways your Javascript form submit can break the Internet.

Submitting to a Different Endpoint Than the Form Action

A portion of your users are browsing the web without Javascript enabled. Some of them, like my friend Andrew, are paranoid. Others are on slow connections and want to save bandwidth. Still others are blind and browse the web with the help of screen readers.

All of these people, when they submit your form, will not hit your fancy Javascript event handler; they will submit the form using the default action and method for the form - which, if unspecified, default to a GET to the current page. Likely, this does not actually submit the form. Which leads to my favorite quote from Mark Pilgrim:

Jakob Nielsen's dog

There is an easy fix: make the form action and method default to the same endpoint that you are POSTing to with Javascript.

You are probably returning some kind of JSON object with an error or success message and then redirecting the user in Javascript. Just change your server endpoint to redirect if the request is not an AJAX request. You can do this because all browsers attach an X-Requested-With: XMLHttpRequest HTTP header to asynchronous Javascript requests.

Changing Parameter Names

Don't change the names of the submitted parameters in Javascript - just submit the same names that you had in your form. In jQuery this is easy, just call the serialize method on the form.

var form = $("#form-id");
$.post('endpoint', $(form).serialize(), function(response) {
    // do something with the response.
});

Attaching the Handler to a Click Action

Believe it or not, there are other ways of submitting a form besides clicking on the submit button. Screen readers, for example, don't click, they submit the form. Also there are lots of people like me who use tab to move between form fields and press the spacebar to submit forms. This means if your form submit starts with:

$("#submit-button").click(function() {
    // Submit the form.
});

You are doing it wrong and breaking the Internet for people like me. You would not believe how many sites don't get this right. Examples in the past week: WordPress, Mint's login page, JetBrains's entire site.

The correct thing to do is attach the event handler to the form itself.

$("#form-id").submit(function() {
    // Write code to submit the form with Javascript
    return false; // Prevents the default form submission
});

This will attach the event to the form however the user submits it. Note the use of return false to avoid submitting the form.

Validation

It's harder to break the Internet with validation. To give fast feedback loop to the user, you should detect and prevent invalid input on the client side.

The annoying thing is you have to do this on both the client side and the server side, in case the user gets past the client side checks. The good news is the browser can help with most of the easy stuff. For example, if you want to check that an email address is valid, use the "email" input type:

<input type="email" />

Then your browser won't actually submit a form that doesn't have a valid email. Similarly you can note required fields with the required HTML attribute. This makes validation on the client a little easier for most of the cases you're trying to check for.

Summary

You can submit forms with Javascript, but most of the time you'll have to put in extra effort to duplicate functionality that already exists in your browser. If you're going to go down that road, please put in the extra effort.

Liked what you read? I am available for hire.

Helping Beginners Get HTML Right

If you've ever tried to teach someone HTML, you know how hard it is to get the syntax right. It's a perfect storm of awfulness.

  • Newbies have to learn all of the syntax, in addition to the names of HTML elements. They don't have the pattern matching skills (yet) to notice when their XML is not right, or the domain knowledge to know it's spelled "href" and not "herf".

  • The browser doesn't provide feedback when you make mistakes - it will render your mistakes in unexpected and creative ways. Miss a closing tag and watch your whole page suddenly acquire italics, or get pasted inside a textarea. Miss a quotation mark and half the content disappears. Add in layouts with CSS and the problem doubles in complexity.

  • Problems tend to compound. If you make a mistake in one place and don't fix it immediately, you can't determine whether future additions are correct.

This leads to a pretty miserable experience getting started - people should be focused on learning how to make an amazingly cool thing in their browser, but instead they get frustrated trying to figure out why the page doesn't look right.

Let's Make Things A Little Less Awful

What can we do to help? The existing tools to help people catch HTML mistakes aren't great. Syntax highlighting helps a little, but sometimes the errors look as pretty as the actual text. XML validators are okay, but tools like HTML Validator spew out red herrings as often as they do real answers. Plus, you have to do work - open the link, copy your HTML in, read the output - to use it.

We can do better. Most of the failures of the current tools are due to the complexity of HTML - which, if you are using all of the features, is Turing complete. But new users are rarely exercising the full complexity of HTML5 - they are trying to learn the principles. Furthermore the mistakes they are making follow a Pareto distribution - a few problems cause the majority of the mistakes.

Catching Mistakes Right Away

To help with these problems I've written an validator which checks for the most common error types, and displays feedback to the user immediately when they refresh the page - so they can instantly find and correct mistakes. It works in the browser, on the page you're working with, so you don't have to do any extra work to validate your file.

Best of all, you can drop it into your HTML file in one line:

</p>

<script type="text/javascript" src="https://raw.github.com/kevinburke/tecate/master/tecate.js"></script>

<p>

Then if there's a problem with your HTML, you'll start getting nice error messages, like this:

error message

Read more about it here, and use it in your next tutorial. I hope you like it, and I hope it helps you with debugging HTML!

It's not perfect - there are a lot of improvements to be made, both in the errors we can catch and on removing false positives. But I hope it's a start.

PS: Because the browser will edit the DOM tree to wipe the mistakes users make, I have to use raw regular expressions to check for errors. I have a feeling I will come to regret this. After all, when parsing HTML with regex, it's clear that the <center> cannot hold. I am accepting this tool will give wrong answers on some HTML documents; I am hoping that the scope of documents turned out by beginning HTML users is simple enough that the center can hold.

Liked what you read? I am available for hire.

Designing a better shower faucet

How should you design the controls for a shower? Let's take a quick look.

Affordance

a hammer

A device should make clear by its design how to use it. Take a hammer for example.

No one has ever looked at a hammer and wondered which end you are supposed to grab and which part you're supposed to pound nails with. This is an example of good affordance.

Some things do not have such good affordance, like the shower at my friend's house. It looked like this, except the handles were perfectly horizontal.

shower faucet and handles

The shower handles have one good affordance - you know where you are supposed to grab, and it's clear you are supposed to rotate the handles. However they leave the following questions unanswered.

  • Which one is hot and which one is cold?
  • How far do I have to turn the handles to reach the desired temperature?
  • What combination of hot and cold do I want?
  • Which direction do I turn the handles, up or down?

That's pretty bad for a device which doesn't need to do much. Maybe not as bad as this sink with two faucets, one for hot and one for cold:

sink fail

But it leaves a lot for the user to figure out, especially when there is usually a lag between when you move the handle and when the temperature changes, making it tough to figure out what's going on.

Designing a Better Showerhead

Functionally, a device should have two properties:

  1. Allow you to do the tasks you want
  2. Make it easy for you to do those tasks.

That's it - if the device is pretty on top of this, that's a big bonus. What do we want a shower to do?

  • Turn on hot water
  • Occasionally, make it even hotter
  • Turn off the water

That's it. These tasks don't map terribly well to the current set of faucets, which ask you to perform a juggling act to get water at the right temperature.

So how can we design a tool to do just this? I'll assume for the moment we have to stick with a physical interface - a tablet for a shower control would allow interesting choices like customizing the shower temperature per user, but would put this out of the reach of most homes. A good start would be a simple control to turn the water on and off. It's not necessary that the control shows the state of water, on or off, as you get that feedback from the hot water - it could just be a button that you press.

That's a good start, now how to control the temperature? I wasn't able to find good data, but my guess is that most people want showers in a 15 degree range of hot to very hot. Either way, there should be a sliding control that lets you select temperatures in this range.

The sliding shower handle comes close and this is one of the better designs I've seen:

Sliding shower handle

However it still has two problems. It shouldn't have a cold range at all, or select a temperature which will burn you.

Second, sliding the handle changes both pressure and temperature. You should get the best pressure available the moment you slide the handle a little bit.

Third, the feedback you get when you turn the shower off could be better. The device could offer a little resistance, and then slide into place when turning it on or off - this way you know that the shower is on or off, similar to the way stoves and iPhone headphones slide into place with a satisfying click.

A shower handle that gave resistance when turning it on or off, turned on full blast straight away, and only let you slide between various hot temperatures. That would be nice.

Liked what you read? I am available for hire.

How to design your API SDK

I've worked with Twilio's client libraries pretty much every day for the last year and I wanted to share some of the things we've learned about helper libraries.

Should you have helper libraries?

You should think about helper libraries as a more accessible interface to your API. Your helper libraries trade the details of your authentication scheme and URL structure for the ease of "do X in N lines of code." If the benefits of a more accessible interface outweigh the costs, do it.

If people are paying to access your API (Twilio, AWS, Sendgrid, Stripe, for example), then you probably should write helper libraries. A more accessible API translates directly into more revenue for your company.

If you're two founders in a garage somewhere, maybe not. The gap between your company's success and failure is probably not a somewhat easier API interface. Writing a helper library is a lot of work, maybe one to four man-weeks depending on the size of your API and your familiarity with the language in question, plus ongoing maintenance.

You might not need a client library if your customers are all highly experienced programmers. For example the other day I wrote my own client for the Recaptcha API. I knew how I wanted to consume it and learning/installing a Recaptcha library would have been unnecessary overhead.

You may also not need a client library if standard libraries have very good HTTP clients. For example, the Requests library dramatically lowers the barrier for writing a client that uses HTTP basic auth. Developers who are familiar with Requests will have an easier time writing http clients. Implementing HTTP basic auth remains a large pain point in other languages.

How should you design your helper libraries?

Realize that if you are writing a helper library, for many of your customers the helper library will be the API. You should put as much care into its design as you do your HTTP API. Here are a few guiding principles.

  • If you've designed your API in a RESTful way, your API endpoints should map to objects in your system. Translate these objects in a straightforward way into classes in the helper library, making the obvious transformations - translate numbers from strings in the API representation into integers, and translate date strings such as "2012-11-05" into date objects.

  • Your library should be flexible. I will illustrate this with a short story. After much toil and effort, the Twilio SMS team was ready to ship support for Unicode messages. As part of the change, we changed the API's 'Content-Type' header from

application/json

to

application/json; charset=utf-8

We rolled out Unicode SMS and there was much rejoicing; fifteen minutes later, we found out we'd broken three of our helper libraries, and there was much wailing and gnashing of teeth. It turns out the libraries had hard-coded a check for an application/json content-type, and threw an exception when we changed the Content-Type header.

  • Your library should complain loudly if there are errors. Per the point on flexibility above, your HTTP API should validate inputs, not the client library. For example let's say we had the library raise an error if you tried to send an SMS with more than 160 characters in it. If Twilio ever wanted to ship support for concatenated SMS messages, no one who had this library installed would be able to send multi-message texts. Instead, let your HTTP API do the validation and pass through errors in a transparent way.

  • Your library use consistent naming schemes. For example, the convention for updating resources should be the same everywhere. Hanging up a call and changing an account's FriendlyName both represent the same concept, updating a resource. You should have methods to update each that look like:

$account->update('FriendlyName', 'blah');
$call->update('Status', 'completed');

It's okay, even good, to have methods that map to readable verbs:

$account->reserveNumber('+14105556789');
$call->hangup();

However, these should always be thin wrappers around the update() methods.

class Call {
    function hangup() {
        return $this->update('Status', 'completed');
    }
}

Having only the readable-verb names is a path that leads to madness. It becomes much tougher to translate from the underlying HTTP request to code, and much trickier to add new methods or optional parameters later.

  • Your library should include a user agent with the library name and version number, that you can correlate against your own API logs. Custom HTTP clients rarely (read: never) will add their own user agent, and standard library maintainers don't like default user agents much.

  • Your library needs to include installation instructions, preferably written at a beginner level. Users have varying degrees of experience with things you might take for granted, like package managers, and will try to run your code in a variety of different environments (VPS, AWS, on old versions of programming languages, behind a firewall without admin rights, etc). Any steps your library can take to make things easier are good. As an example, the Twilio libraries include the SSL cert necessary for connecting to the Twilio API.

How should you test your library?

The Twilio API has over 20 different endpoints, split into list resources and instance resources, which support the HTTP methods GET, POST, and sometimes DELETE. Let's say there are 50 different combinations of endpoints and HTTP methods in total. Add in implementations for each helper library, and the complexity grows very quickly - if you have 5 helper libraries you're talking about 250 possible methods, all of which could have bugs.

One solution to this is to write a lot of unit tests. The problem is these take a lot of time to write, and at some level you are going to have to mock out the API, or stop short of making the actual API request. Instead we've taken the following approach to testing.

  1. Start with a valid HTTP request, and the parameters that go with it.
  2. Parse the HTTP request and turn it into a piece of sample code that exercises an aspect of your helper library.
  3. Run that code sample, and intercept the HTTP request made by the library.
  4. Compare the output with the original HTTP request.

This approach has the advantage of actually checking against the HTTP request that gets made, so you can test things like URL encoding issues. You can reuse the same set of HTTP requests across all of your libraries. The HTTP "integration" tests will also detect actions that should be possible with the API but are not implemented in the client.

You might think it's difficult to do automated code generation, but it actually was not that much work, and it's very easy if you've written your library in a consistent way. Here's a small sample that generates snippets for our Python helper library.

def process_instance_resource(self, resource, sid, method="GET", params=None):
    """ Generate code snippets for an instance resource """
    get_line = '{} = {}.get("{}")'.format(self.instance_name, self.base, sid)

    if method == "GET":
        interesting_line = 'print {}.{}'.format(self.instance_name,
            self.get_interesting_property(resource))
        return "\n".join([get_line, interesting_line])

    elif method == "POST":
        update_line = '{} = {}.update("{}", {})'.format(
            self.instance_name, self.base, sid, self.transform_params(params))
        interesting_line = 'print {}.{}'.format(
            self.instance_name, self.get_interesting_property(resource))
        return "\n".join([update_line, interesting_line])

    elif method == "DELETE":
        return '{}.delete("{}")'.format(self.base, sid)

    else:
        raise ValueError("Method {} not supported".format(method))

Generating code snippets has the added advantage that you can then easily embed these into your customer-facing documentation, as we've done in our documentation.

How do people use helper libraries?

While pretty much every resource gets used in the aggregate, individual accounts tend to only use one or two resources. This suggests that your API is only being referenced from one or two places within a customer's codebase.

How should you document your helper library?

Per the point above, your library is probably being used in only one or two places in a customer's codebase. This suggests your customer is hiring your API to do a specific job. Your documentation hierarchy should be aligned around those jobs. Combined with the integration test/code snippet generator above, and you should have a working code example for every useful action in your API. You will probably also want to have documentation for the public library interface, such as the types and parameters for each method, but the self-service examples will be OK for 85% of your users.

Liked what you read? I am available for hire.

How to talk to recruiters at a career fair

Last week two other Twilio engineers and I went to the Columbia engineering career fair. We had a great time and talked to a lot of really smart people. However I was surprised at some of the naive mistakes students made when we were talking. We're there to try to hire students and students are there to try and get internships and jobs, so we desperately want it to work out. As a student, here are some things to avoid when you are talking to a recruiter.

  • Are you hiring full time software engineers? I am looking for a full time position, here is my resume - This question demonstrates a high degree of naïveté. First, the market for programming talent is absolutely on fire right now and everyone is looking for talented people. It's also safe to assume we are at the career fair because we are trying to recruit people for full time positions.

    Second, especially as a small company, we are looking for people who are passionate about what we are doing. It's good to talk about cool things you've done, but at some level you have to express interest in what we are doing, or tie your skills back to how they'd fit in at our company.

    Maybe fifteen people asked me this "are you hiring" question during the fair and most of them were ESL students. I know these students are very bright, and I understand it can be nerve wracking for them to speak to recruiters, but it was very difficult for us to get a read on whether someone would be a good fit, based on how the conversations went. For us, that translates to a "no phone screen".

  • I love programming Java - This is a red flag for us. There is nothing wrong with Java per se, but it's a language that's hard to get excited about. It's also the language students have been using for class, which tells us that you might not do that much programming/learning outside of class (another red flag).

    The other big problem is Java probably has the worst signal to noise ratio of any language on students' resumes nowadays; a higher ratio of students with, say, Haskell experience are good candidates than students who mention Java. Two people who have covered this topic in much better detail than me are Paul Graham and Yaron Minsky.

    The one exception to this rule is if you have experience with advanced Java programs like Hadoop or Asterisk (we are a telecom company and use Asterisk extensively). In this case definitely tell us about your Java experience.

  • You're wearing a suit At some career fairs almost everyone is wearing suits so it's not a big deal if you are also wearing one. That said, I went out of my way to talk to people wearing jeans because a) it indicated they're not interested in jobs where they'd like to see you wearing a suit, and b) it indicated they were confident enough in yourself and your skill set to ignore the vast numbers of people wearing suits. So at least if you are looking for a job at a small tech company, don't be afraid to wear something more comfortable.

  • I don't really know what I want to do - Like the suits, you are young and it's fine if you don't know what you want to do yet. The problem is that we have three specific teams and while we are talking, I am trying to figure out which team you would be the best fit for. Sometimes this can be hard and good people will fall through because we don't know where to put you. It really helps if you express a strong preference that matches the skills on your resume, then I know what team to have you interview with and have a sense you'll be happy.

    If you are not sure, one good strategy is to rotate - tell one company you'd like to do frontend work, tell the next you'd like to work on mobile and tell the third company you'd like to work on big data. Next summer (or in your spare time) you can try out something different.

  • Here's my resume, looking forward to a phone screen - Even if you are an exceptional candidate, this will not get you a phone screen at most small companies. Here is the deal. The Google, Facebook and LinkedIn recruiters have little say in whether you get an interview or not. They are there to hand out pens, collect resumes and answer basic questions about internships/full time opportunities. You'll be encouraged to apply online.

    When you talk to smaller companies at career fairs, the engineers you are talking to are actively evaluating you and making decisions about whether to advance you through the screening process. The stakes are much higher and you should consider it like a culture fit interview. You should do your research, try out the company's product, read through blog posts to figure out what sort of stack they use, etc. Then when you are talking, be sure to bring up parts of your experience that match up. For example, green flags for us are when students mention experience at hackathons, experience using Twilio in the past, or experience with HTTP/API's/writing web applications. So don't expect you can just drop a resume and get an interview - at a small company that won't fly.

Hopefully these help somewhat. Two things to keep in mind are, these are things we look for as a small Internet company - if you want to work at an Internet giant, or in a different industry, my advice would be much different. Second, I might have sounded critical above, but we all really want you to do well - we love talking to great people, and it makes interviewing and screening much more pleasant. Third, we're hiring! I hope you found this article helpful, and I hope you check us out - twilio.com/jobs.

Liked what you read? I am available for hire.

Companies Respond To Incentives, Too

A Google data center

The New York Times has a big new feature up explaining why data centers at Google, Facebook etc. waste tons of electricity. Diego Doval, a former CTO at a popular startup, skewers the NYT with a 5,000 word critique of the factual inaccuracies in the post.

Doval is right on with his critique, but there's a simpler problem with the piece, that I find tends to underlie lots of liberal thought. As the article points out, data centers use 2% of the electricity in the United States. The expense required to power these data centers represents a huge, huge incentive for all of these companies to cut down on their power use as much as possible. To do otherwise, with the amount of money they're spending, would be negligent.

Sadly, people who can write code, and understand the performance and reliability problems faced when running a large data center, are rare enough and highly paid enough that most of them work in the tech sector. When non-technical reporters try to report what's going on without understanding the fundamental issues, you get articles like this one.

Liked what you read? I am available for hire.

How one of the all time great magicians thinks about experiences

I was fascinated by this article in Esquire about Teller, half of the magic duo Penn and Teller, because of its description of how Teller thinks about his craft. I especially liked this story:

When Teller was in high school, [a teacher] read a short story to those few students before him, including an enraptured Teller: "Enoch Soames," by Max Beerbohm, written in 1916.

In the story, Beerbohm relates the tragic tale of Soames, a dim, hopeless writer with delusions of future grandeur. In the 1890s, Beerbohm recounts, Soames made a deal with the devil: In exchange for his soul, Soames would be magically transported one hundred years into the future — to precisely 2:10 P.M. on June 3, 1997 — into the Round Reading Room at the British Museum. There, he could look at the shelves and through the catalogs and marvel at his inevitable success. When Soames makes his trip, however, he learns that time has almost erased him before the devil has had the chance. He is listed only as a fictional character in a short story by Max Beerbohm.

Thirty-four-and-a-half years after that snowy reading by his satanic-looking teacher... Teller flew to England ahead of June 3, 1997.

As it turned out, there were about a dozen people in the Round Reading Room that afternoon... And at ten past two, they gasped when they saw a man appear mysteriously out of the stacks, looking confused as he scanned empty catalogs and asked unhelpful librarians about his absence from the files. The man looked just like the Soames of Teller's teenage imagination, "a stooping, shambling person, rather tall, very pale, with longish and brownish hair," and he was dressed in precise costume, a soft black hat and a gray waterproof cape. The man did everything Enoch Soames did in Max Beerbohm's short story, floating around the pin-drop-quiet room before he once again disappeared into the shelves.

And all the while, Teller watched with a small smile on his face. He didn't tell anyone that he might have looked through hundreds of pages in casting books before he had found the perfect actor. He didn't tell anyone that he might have visited Angels & Bermans, where he had found just the right soft black hat and gone through countless gray waterproof capes. He didn't tell anyone that he might have had an inside friend who helped him stash the actor and his costume behind a hidden door in the stacks. Even when Teller later wrote about that magical afternoon for The Atlantic, he didn't confess his role. He never has.

"Taking credit for it that day would be a terrible thing — a terrible, terrible thing," Teller says. "That's answering the question that you must not answer."

Now, again, his voice leaves him. That afternoon took something close to actual sorcery, following years of anticipation and planning. But more than anything, it required a man whose love for magic is so deep he can turn deception into something beautiful.

Years of preparation for something only twelve people would see. Read Teller's account of the day in 1997, or the full profile of Teller in Esquire

Liked what you read? I am available for hire.

Virgin Mobile fails web security 101, leaves six million subscriber accounts wide open

Update: Virgin fixed the issue Tuesday night after taking their login page down for four hours. Please see my update at the bottom of this post.

The first sentence of Virgin Mobile USA’s privacy policy announces that “We [Virgin] are strongly committed to protecting the privacy of our customers and visitors to our websites at www.virginmobileusa.com.” Imagine my surprise to find that pretty much anyone can log into your Virgin Mobile account and wreak havoc, as long as they know your phone number.

I reported the issue to Virgin Mobile USA a month ago and they have not taken any action, nor informed me of any concrete steps to fix the problem, so I am disclosing this issue publicly.

The vulnerability

Virgin Mobile forces you to use your phone number as your username, and a 6-digit number as your password. This means that there are only one million possible passwords you can choose.

Screenshot of Virgin Mobile login screen

This is horribly insecure. Compare a 6-digit number with a randomly generated 8-letter password containing uppercase letters, lowercase letters, and digits – the latter has 218,340,105,584,896 possible combinations. It is trivial to write a program that checks all million possible password combinations, easily determining anyone’s PIN inside of one day. I verified this by writing a script to “brute force” the PIN number of my own account.

The scope

Once an attacker has your PIN, they can take the following actions on your behalf:

  • Read your call and SMS logs, to see who’s been calling you and who you’ve been calling

  • Change the handset associated with an account, and start receiving calls/SMS that are meant for you. They don’t even need to know what phone you’re using now. Possible scenarios: $5/minute long distance calls to Bulgaria, texts to or from lovers or rivals, “Mom I lost my wallet on the bus, can you wire me some money?”

  • Purchase a new handset using the credit card you have on file, which may result in $650 or more being charged to your card

  • Change your PIN to lock you out of your account

  • Change the email address associated with your account (which only texts your current phone, instead of sending an email to the old address)

  • Change your mailing address

  • Make your life a living hell

How to protect yourself

There is currently no way to protect yourself from this attack. Changing your PIN doesn’t work, because the new one would be just as guessable as your current PIN. If you are one of the six million Virgin subscribers, you are at the whim of anyone who doesn’t like you. For the moment I suggest vigilance, deleting any credit cards you have stored with Virgin, and considering switching to another carrier.

What Virgin should do to fix the issue

There are a number of steps Virgin could take to resolve the immediate, gaping security issue. Here are a few:

  • Allow people to set more complex passwords, involving letters, digits, and symbols.

  • Freezing your account after 5 failed password attempts, and requiring you to identify more personal information before unfreezing the account.

  • Requiring both your PIN, and access to your handset, to log in. This is known as two-step verification.

In addition, there are a number of best practices Virgin should implement to protect against bad behavior, even if someone knows your PIN:

  • Provide the same error message when someone tries to authenticate with an invalid phone number, as when they try to authenticate with a good phone number but an invalid PIN. Based on the response to the login, I can determine whether your number is a Virgin number or not, making it easy to find targets for this attack.

  • Any time an email or mailing address is changed, send a mail to the old address informing them of the change, with a message like “If you did not request this change, contact our help team.”

  • Require a user to enter their current ESN, or provide information in addition to their password, before changing the handset associated with an account.

  • Add a page to their website explaining their policy for responsible security disclosure, along with a contact email address for security issues.

History of my communication with Virgin Mobile

I tried to reach out to Virgin and tell them about the issue before disclosing it publicly. Here is a history of my correspondence with them.

  • August 15 – Reach out on Twitter to ask if there is any other way to secure my account. The customer rep does not fully understand the problem.

  • August 16 – Brute force access to my own account, validating the attack vector.

  • August 15-17 – Reach out to various customer support representatives, asking if there is any way to secure accounts besides the 6-digit PIN. Mostly confused support reps tell me there is no other way to secure my account. I am asked to always include my phone number and PIN in replies to Virgin.

    Email screenshot of Virgin asking me to include my PIN

  • August 17 – Support rep Vanessa H escalates the issue to headquarters after I explain I’ve found a large vulnerability in Virgin’s online account security. Steven from Sprint Executive and Regulatory Services gives me his phone number and asks me to call.

  • August 17 – I call Steven and explain the issue, who can see the problem and promises to forward the issue on to the right team, but will not promise any more than that. I ask to be kept in the loop as Virgin makes progress investigating the issue. In a followup email I provide a list of actions Virgin could take to mitigate the issue, mirroring the list above.

  • August 24 – Follow up with Steven, asking if any progress has been made. No response.

  • August 30 – Email Steven again. Steven writes that my feedback “has been shared with the appropriate managerial staff” and “the matter is being looked into”.

  • September 4 – I email Steven again explaining that this response is unacceptable, considering this attack may be in use already in the wild. I tell him I am going to disclose the issue publicly and receive no response.

  • September 13 – I follow up with Steven again, informing him that I am going to publish details of the attack in 24 hours, unless I have more concrete information about Virgin’s plans to resolve the issue in a timely fashion.

  • September 14 – Steven calls back to tell me to expect no further action on Virgin Mobile’s end. Time to go public.

Update, Monday night

  • Sprint PR has been emailing reporters telling them that Sprint/Virgin have fixed the issue by locking people out after 4 failed attempts. However, the fix relies on cookies in the user’s browser. This is like Virgin asking me to tell them how many times I’ve failed to log in before, and using that information to lock me out. They are still vulnerable to an attack from anyone who does not use the same cookies with each request. (ed: This issue has been fixed as of Tuesday night)

  • News coverage:

  • This vulnerability only affects Virgin USA, to my knowledge; their other international organizations appear to only share the brand name, not the same code base.

Update, Tuesday night

Virgin’s login page was down for four hours from around 5:30 PDT to 9:30 PDT. I tried my brute force script again after the page came back up. Where before I was getting 200 OK’s with every request, now about 25% of the authentication requests return 503 Service Unavailable, and 25% return 404 Not Found.

Wednesday morning

Virgin took down their login page for 4 hours Tuesday night to deploy new code. Now, after about 20 incorrect logins from one IP address, every further request to their servers returns 404 Not Found. This fixes the main vulnerability I disclosed Monday.

I just got off the phone with Sprint PR representatives. They apologized and blamed a breakdown in the escalation process. I made the case that this is why they need a dedicated page for reporting security and privacy issues, and an email address where security researchers can report problems like this, and know that they will be heard.

I gave the example of Google, who says “customer service doesn’t scale” for many products, but will respond to any security issue sent to security@google.com in a timely fashion, and in many cases award cash bounties to people who find issues. Sprint said they’d look into adding a page to their site.

Even though they’ve fixed the brute force issue, I raised issues with PIN based authentication. No matter how many automated fraud checks they have in place, PIN’s for passwords are a bad idea because:

  • people can’t use their usual password, so they might try something more obvious like their birthday, to remember it.

  • Virgin’s customer service teams ask for it in emails and over the phone, so if an attacker gains access to someone’s email, or is within earshot of someone on a call to customer service, they have the PIN right there.

  • If I get access to your PIN through any means, I can do all of the stuff mentioned above – change your handset, read your call logs, etc. That’s not good and it’s why even though Google etc. allow super complex passwords, they allow users to back it up with another form of verification.

I also said that they should clarify their policy around indemnification. I never actually brute forced an account where I didn’t know the pin, or issue more than one request per second to Virgin’s servers, because I was worried about being arrested or sued for DOSing their website. Fortunately I could prove this particular flaw was a problem by dealing only with my own account. But what if I found an attack where I could change a number in a URL, and access someone else’s account? By definition, to prove the bug exists I’d have to break their terms of service, and there’s no way to know how they would respond.

They said they valued my feedback but couldn’t commit to anything, or tell me about whether they can fix this in the future. At least they listened and will maybe fix it, which is about as good as you can hope for.

Liked what you read? I am available for hire.

Reddit’s database has two tables

Steve Huffman talks about Reddit’s approach to data storage in a High Scalability post from 2010. I was surprised to learn that they only have two tables in their database.

Lesson: Don’t worry about the schema.

[Reddit] used to spend a lot of time worrying about the database, keeping everthing nice and normalized. You shouldn’t have to worry about the database. Schema updates are very slow when you get bigger. Adding a column to 10 million rows takes locks and doesn’t work. They used replication for backup and for scaling. Schema updates and maintaining replication is a pain. They would have to restart replication and could go a day without backups. Deployments are a pain because you have to orchestrate how new software and new database upgrades happen together.

Instead, they keep a Thing Table and a Data Table. Everything in Reddit is a Thing: users, links, comments, subreddits, awards, etc. Things keep common attribute like up/down votes, a type, and creation date. The Data table has three columns: thing id, key, value. There’s a row for every attribute. There’s a row for title, url, author, spam votes, etc. When they add new features they didn’t have to worry about the database anymore. They didn’t have to add new tables for new things or worry about upgrades. Easier for development, deployment, maintenance.

The price is you can’t use cool relational features. There are no joins in the database and you must manually enforce consistency. No joins means it’s really easy to distribute data to different machines. You don’t have to worry about foreign keys are doing joins or how to split the data up. Worked out really well. Worries of using a relational database are a thing of the past.

This fits with a piece I read the other day about how MongoDB has high adoption for small projects because it lets you just start storing things, without worrying about what the schema or indexes need to be. Reddit’s approach lets them easily add more data to existing objects, without the pain of schema updates or database pivots. Of course, your mileage is going to vary, and you should think closely about your data model and what relationships you need.

Update, 10:05AM PDT: It’s worth reading the comments from a current Reddit engineer on this post. Particularly this one:

I’m personally not a fan of using an RDBMS as a key-value store – but take a look at, say, line 60 of the accounts code. Each item in that _defaults dictionary corresponds to an attribute on an account. For pretty much all of those (1) we don’t need to join on it and (2) we don’t want to do database maintenance just to add a new preference toggle. Those points are particularly more important when you’ve got a staff of 2-3 engineers. Sure, reddit has more now – but we’ve also now got a lot of data to migrate if we wanted to change, a lot of code to rewrite, and a lot of more important problems.

The data architecture made sense for Reddit as a small company that had to optimize for engineering man hours. Now they are much bigger and can afford a saner structure. He/she mentions that they are in the process of migrating their Postgres data over to Cassandra, but slowly.

Update, 11:31PM PDT: A former engineer at reddit adds this comment.

There isn’t a “table” for a subreddit. There is a thing/data pair that stores metadata about a subreddit, and there is a thing/data pair for storing links. One of the properties of a link is the subreddit that it is in. Same with the comments. There is one thing/data pair for comments and the subreddit it is in is a property.

Still today I tell people that even if you want to do key/value, postgres is faster than any NoSQL product currently available for doing key/value.

Update, 7:11PM PDT: From Hacker News, it looks like they use two tables for each “thing”, so a thing/data pair for accounts, a thing/data pair for links, etc.

Liked what you read? I am available for hire.