Posts Tagged With: Code

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.

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.

Bash user? Try Zsh, the more usable terminal shell

On most operating systems, the default command line shell is Bash. Bash is a perfectly good shell. However there are a number of tasks that are slow or annoyingly time-consuming in Bash, particularly relating to the shell history. It's like using your phone to complete tasks, instead of a laptop.

Zsh is a newer terminal shell with slightly different syntax than Bash. Zsh makes many smart usability decisions where Bash fails, helping you get work done faster. I thought I'd highlight some of the best examples.

ZSH skips repeat commands in history. Let's say I run our unit test suite 20 times in a row. With Bash, if I wanted to get the command I ran just before that, I'd have to hit the up arrow 21 times to get the previous line. Zsh combines all the duplicate commands into one history item, so you only have to press 'up' twice to get that old command.

Ctrl+U deletes the whole line, no matter where the cursor is. In Bash Ctrl+U will delete everything left of the cursor. I have never wanted to delete everything left of the cursor without also deleting the whole line.

Command sensitive history. In Zsh if I type git and then press 'up', Zsh will cycle through all of my latest git commands, skipping any non-git commands. This is especially useful with a few infrequent commands I run that take many command line options, such as our configuration scripts.

Shared history across tabs. With Bash, using the 'up' arrow to access previous commands only gives you access to the history of the current tab. This is like having Chrome only remember your history for one given tab, instead of sharing it across all your tabs.

Smarter tab completion out of the box. Zsh is smart about figuring out which filenames you actually want. There's a good list of tab completion examples here, the two that stand out for me are:

  • Typing

    rm foo*<tab> 
    

    will expand to

    rm foo.txt foo.txt.swp foo.o foo.c
    

    or however many files beginning with foo there are in the directory.

  • Typing

    vim zzz<tab>
    

    will match in the middle of files, for example blah-blah-blah-zzz.txt.

You should give it a try - it may be a little unfamiliar at first, but you'll save a lot of time and annoyance by completing tasks more quickly with Zsh. You can switch by typing at the Bash command prompt:

$ zsh

That will load Z Shell in the current window. You can change your shell permanently by running:

$ chsh -s $(which zsh)

Let me know what you think!

Liked what you read? I am available for hire.

Why we’ll never shut down our API

Recently there have been several articles by startups who built a service around another company's API, and then got upset that the other company changed their Terms of Service, revoked their API access, or sent them a cease and desist letter. Others have rightly pointed out that Craigslist, Netflix, &c. offer API's to improve the value of their own services, and building a company around access to another's API may be foolhardy.

There's an obvious exception; you rarely hear about terms-of-service or cease-and-desist shenanigans from companies with APIs at their core. Twilio (where I work) is a good example. The amount of money we make is directly correlated to the number of API requests we receive. We have no reason to shut anyone off, because we make more money when people use our API more. Google shut off its Translate API recently, despite a large volume of legitimate use, because it interfered with search quality - spammers were using it to generate thin copies of good content. We would never turn off our API, because it's core to our business.

(One caveat: if your big plan is to use Twilio to spam people, then yeah, we're going to shut you off. We make money when people spend money with us, but we do have an Acceptable Use Policy.)

The only conceivable situation we'd shut down our API is if the company was forced to shut down. That's a risk, but we believe that risk is low and we're working every day to minimize it. So we're not going to shut off your access, unlike Linkedin or Craigslist or another company whose API is a convenience.

Liked what you read? I am available for hire.

How to use EC2 as a web proxy

If KRON Channel 4 or KICU gave me the ability to stream A's games, I'd gladly pay for it, but they don't, and we're not going to pay for cable just to get baseball.

MLB.tv is great and they allow you to stream games, but they have blackout restrictions where you can't stream the game if it's also being shown on cable locally.

Fortunately, there's a workaround. Because MLB.tv filters based on IP address, you can get around the restriction by sending your Internet traffic through a proxy computer, with an IP address that isn't blocked (this is how, for example, people in China get on the internet). Most proxies are slow though and become unwatchable if you try to stream a high-bandwidth video. If only you could use a high-bandwidth proxy and not share it with anyone else...

Fortunately Amazon provides servers in the cloud that let you do exactly this. People usually use them for running web servers, but you can use them for this purpose just as easily.

  1. Go to aws.amazon.com and login using your Amazon credentials. They will ask you for your credit card and to verify your phone number. As long as you stay inside the Free Tier (roughly 30-40 games a month) you will not be charged.

  2. Click on EC2. Click "Create Instance," then use the Quick Launch wizard. Create an Ubuntu instance (one of the "Free Tier eligible" ones) and make sure you download the credentials, as you need them to log in and they won't be available later.

  3. On the next page click on "Edit Details," then on "Security Settings." You need to create a new Security Group, that will allow computers from your apartment to connect to your new computer in the cloud. Find your apartment's IP address by visiting http://jsonip.com. Then fill out the details like this:

    EC2 Security Group Settings

    Substitute in your own IP address. If you have a cool ISP like Sonic, you can get a static IP address, which makes this much easier. Otherwise your IP address may change from day-to-day, and you'll have to update this setting, or provide a broader range of valid IP addresses in the form.

  4. You need one other piece of information which is the hostname for your EC2 instance. It will look something like this: ec2-12-34-56-789.compute-1.amazonaws.com.

  5. Now the fun parts! Open up the Terminal and type in:

    ssh -i $HOME/.ssh/mlb.pem ubuntu@ec2-12-34-56-789.compute-1.amazonaws.com -D 2001
    

    where $HOME/.ssh/mlb.pem is the route to the .pem file you downloaded earlier, and the hostname is the hostname you got above. Go ahead and leave this connection open. You need to leave this open while you're trying to watch some baseball.

    (This won't work for PC users. If you're on a PC you have to configure PuTTY to use SSH, which is an unusable mess that I'm glad I don't have to deal with anymore).

  6. Now open Firefox Preferences, click "Advanced", click "Settings", then type in these settings:

    Firefox proxy settings

    To check that they were applied correctly, visit jsonip.com in your Firefox browser. It should be a different IP than your apartment! Browse away!

Some notes:

  • The next time you set this up, all you have to do is run the SSH command in your terminal, and set up Firefox to use the proxy. It won't hurt your computer to kill either at any time, but the stream will stop working.

  • This uses the free tier of Amazon Web Services; if you go over your limits then Amazon will charge you. You can check your usage in the "Account Activity" portal on aws.amazon.com.

  • I've only done this for one game, and the usage I checked was about 0.4 GB, which means with 15 GB in/out per month, you should be able to stream about 30 games, assuming no other usage. The connection between MLB and Amazon is really good; the connection between Amazon and your apartment may not be, depending on your connection speed.

  • It may be better to configure these settings in your router so everyone can connect. I'm not sure how to do that, however.

  • Again, I wish this weren't a problem but MLB blacks out games on their streaming service, so there's no way to stream games that are on cable. I have no problem paying for a stream, as we are in fact paying for MLB.tv. I'll take this post down once someone figures out how I can pay to stream games in my local market, without resorting to hacks like this.

Liked what you read? I am available for hire.

Why code review beats testing: evidence from decades of programming research

tl;dr If you want to ship high quality code, you should invest in more than one of formal code review, design inspection, testing, and quality assurance. Testing catches fewer bugs per hour than human inspection of code, but it might be catching different types of bugs.

Everyone wants to find bugs in their programs. But which methods are the most effective for finding bugs? I found this remarkable chart in chapter 20 of Steve McConnell’s Code Complete. Summarized here, the chart shows the typical percentage of bugs found using each bug detection technique. The range shows the high and low percentage across software organizations, with the center dot representing the average percentage of bugs found using that technique.

As McConnell notes, “The most interesting facts … are that the modal rates don’t rise above 75% for any one technique, and that the techniques average about 40 percent.” Especially noteworthy is the poor performance of testing compared to formal design review (human inspection). There are three pages of fascinating discussion that follow; I’ll try to summarize.

What does this mean for me?

No one approach to bug detection is adequate. Capers Jones – the researcher behind two of the papers McConnell cites – divides bug detection into four categories: formal design inspection, formal code inspection, formal quality assurance, and formal testing. The best bug detection rate, if you are only using one of the above four categories, is 68%. The average detection rate if you are using all four is 99%.

But a less-effective method may be worth it, if it’s cheap enough

It’s well known that bugs found early on in program development are cheaper to fix; costs increase as you have to push changes to more users, someone else has to dig through code that they didn’t write to find the bug, etc. So while a high-volume beta test is highly effective at finding bugs, it may be more expensive to implement this (and you may develop a reputation for releasing highly buggy software).

Shull et al (2002) estimate that non-severe defects take approximately 14 hours of debugging effort after release, but only 7.4 hours before release, meaning that non-critical bugs are twice as expensive to fix after release, on average. However, the multiplier becomes much, much larger for severe bugs: according to several estimates severe bugs are 100 times more expensive to fix after shipping than they are to fix before shipping.

More generally, inspections are a cheaper method of finding bugs than testing; according to Basili and Selby (1987), code reading detected 80 percent more faults per hour than testing, even when testing programmers on code that contained zero comments. This went against the intuition of the professional programmers, which was that structural testing would be the most efficient method.

How did the researchers measure efficiency?

In each case the efficiency was calculated by taking the number of bug reports found through a specific bug detection technique, and then dividing by the total number of reported bugs.

The researchers conducted a number of different experiments to try and measure numbers accurately. Here are some examples:

  • Giving programmers a program with 15 known bugs, telling them to use a variety of techniques to find bugs, and observing how many they find (no one found more than 9, and the average was 5)
  • Giving programmers a specification, measuring how long it took them to write the code, and how many bugs existed in the code base
  • Formal inspections of processes at companies that produce millions of lines of code, like NASA.
In our company we have low bug rates, thanks to our adherence to software philosophy X.

Your favorite software philosophy probably advocates using several different methods listed above to help detect bugs. Pivotal Labs is known for pair programming, which some people rave about, and some people hate. Pair programming means that with little effort they’re getting informal code review, informal design review and personal desk-checking of code. Combine that with any kind of testing and they are going to catch a lot of bugs.

Before any code at Google gets checked in, one owner of the code base must review and approve the change (formal code review and design inspection). Google also enforces unit tests, as well as a suite of automated tests, fuzz tests, and end to end tests. In addition, everything gets dogfooded internally before a release to the public (high-volume beta test).

It’s likely that any company with a reputation for shipping high-quality code will have systems in place to test at least three of the categories mentioned above for software quality.

Conclusions

If you want to ship high quality code, you should invest in more than one of formal code review, design inspection, testing, and quality assurance. Testing catches fewer bugs per hour than human inspection of code, but it might be catching different types of bugs. You should definitely try to measure where you are finding bugs in your code and the percentage of bugs you are catching before release – 85% is poor, and 99% is exceptional.

Appendix

The chart was created using the jQuery plotting library flot. Here’s the raw Javascript, and the CoffeeScript that generated the graph.

References

Liked what you read? I am available for hire.

Chrome extension to drop jQuery into any site

Chrome extensions are sandboxed. This means that, while they can access the page, they can’t interact with other Javascript variables that are live on the page or live in other Chrome extensions. All in all this is probably a good thing, because the global namespace gets polluted easily and there are probably security reasons why you want to have this feature as well.

However, this makes debugging Chrome extensions a pain in the neck, because none of the variables that are live in your extension are live in the page itself. This means that you can’t really debug them in the console. Lots of times all I want to do is inspect some objects on the page with jQuery and test that I’m selecting the right object on the page. I have jQuery in my extension, but I can’t run jQuery on the page, because the page doesn’t load it.

So I wrote a Chrome extension that’ll drop jQuery into any page you are testing, so you can inspect things from the console. It’s pretty simple again but will save me from writing console.log statements into my Chrome content script, tabbing over to chrome://extensions clicking “Reload”, refreshing the page, and then clicking around to trigger my behavior. You want to enable it while you are debugging your app, and then disable it when it’s complete, otherwise you’ll have a performance hit from the extra external request. It’s about three lines of Javascript, but they are a good three lines.

You can grab the extension here.

Liked what you read? I am available for hire.

How long does it take for shuffled poker chips to return to their original state?

I like to shuffle poker chips while I work. It gives me something to do while pages are loading or while I'm thinking that doesn't involve checking Twitter or Hacker News.

I got curious Shuffling poker chipshow long it took for chip stacks of various heights to return to their shuffled state. However right now I can only shuffle stacks of 18 chips (9 red, 9 blue) before they come tumbling back to the floor, out of my hand. So I wrote a short program to simulate chip shuffles and determine how long it would take to get the stacks back to their shuffled state.

Here are the results:

Number of Red Chips    Total Shuffles
1                      2
2                      4
3                      3
4                      6
5                      10                     
6                      12
7                      4
8                      8
9                      18
10                     6
11                     11
12                     20
13                     18
14                     28
15                     5
16                     10
17                     12
18                     36
19                     12
20                     20

That's a pretty interesting pattern. I'm sure there's a bunch of cool math behind it; I'll look it up soon and then update this post if I find any. Note that if the number of shuffles is divisible by two, the chips reverse order in the stack (ex. go from all red on the bottom to all red on the top) before returning to their original state.

Update: I found the pattern behind the poker chip shuffle sequence, on a site that lets you plug in any integer sequence and try to find the pattern that matches. You can find the pattern here. Glad I found that page, because I'm not sure I would have guessed the pattern. Here is more detail:

In other words, least m such that 2n+1 divides 2^m-1. Number of riffle shuffles of 2n+2 cards required to return a deck to initial state. A riffle shuffle replaces a list s(1), s(2), ..., s(m) by s(1), s((i/2)+1), s(2), s((i/2)+2), ... a(1) = 2 because a riffle shuffle of [1, 2, 3, 4] requires 2 iterations [1, 2, 3, 4] -> [1, 3, 2, 4] -> [1, 2, 3, 4] to restore the original order.

Here's the example code, in Haskell:

To output numbers, save that code as a file called
chips.hs
and run:
$ ghci
GHCi, version 6.10.4: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer ... linking ... done.
Loading package base ... linking ... done.
Prelude> :l chips.hs
[1 of 1] Compiling Main             ( chips.hs, interpreted )
Ok, modules loaded: Main.
*Main> zip [1..20] (map getNumberOfShuffles [1..20])

Liked what you read? I am available for hire.

How to import a CSV file to Google Calendar

I had a lot of trouble with this recently, so hope this helps. Google is pretty strict with the CSV files it imports.

First off open Excel. In the first row of your file, add the following headers:

Subject, Start Date, Start Time, End Date, End Time, All Day Event, Reminder On/Off, Reminder Date, Reminder Time, Meeting Organizer, Description, Location, Private

Every event (every row in Excel) needs to have a Subject, Start Date, and Start Time. The other headers are optional and you can mix and match them as much as you please. Here is a complete sample I uploaded today.

Subject, Start Date, Start Time, End Date, End Time, Private, All Day Event, Location
Ramsay Shield, 7/26/2008, 7:00 PM, , 9:00 PM, FALSE, , TBC
Training, 7/27/2008, 12:00 PM, , TRUE, FALSE,

Make sure you format your cells properly

Highlight every time under Start Time, End Time, and Reminder Time, click “Format Cells,” then “Time,” then “1:30 PM.”

Also, highlight every date under Start Date, End Date, and Reminder Date, then click “Format Cells,” then “Date,” then “3/14/2001.”

You need to do both of those things for Google to recognize your file.

For Private, All Day Event, and Reminder On/Off, type True or False in the relevant cell. If you leave them blank, Google Calendar will use the default settings for these events (for privacy, it will make the event private or public depending on whether the calendar is private or public). If there isn’t any info after Start Date & Start Time, Google assumes the event is one hour long. Also, make sure that the only data on the spreadsheet is events – otherwise Google will return an error.

Once you’re done click File –> Save As, then click down at the bottom where it says “Microsoft Office Excel Notebook” for file type, and change it to CSV (Comma Separated Value) format. Then you’re ready to upload to Google!

Note: if you upload the same CSV file twice, Google will create duplicates of your events rather than replace the first set. There’s no “Remove duplicates” button either – you have to do it manually, or erase the whole calendar and start again.

Liked what you read? I am available for hire.