Broken Strings and Error Handling

We're down something of a rabbit hole creating a banjo in JavaScript. If you missed the first few parts, you probably want to go back and read them before getting into today's email.

Day 1

Day 2

Day 3

Day 4

Ready to go? Ok.

When you play them long enough, eventually banjo strings break. If I wanted to model that in the BanjoString class, I might add some random chance to the pick() method:

(view in a browser for better formatting)

class BanjoString {

  broken = false

  //... other methods/properties unchanged

  pick(strength) {
    // if string is already broken, throw early
    if (this.broken) {
      throw new Error("Can't pick a broken string")

    // correlate chance of breakage to strength of pick
    const breakChance = strength * .00001  
    if (breakChance > Math.random()) {
      this.broken = true
      throw new Error("String Broke")

    return {
      pitch: this.basePitch + this.fretPosition,
      volume: strength,
      duration: strength * strength

This seems pretty straightforward. The break is a catastrophic failure for the string. Therefore, we throw an error when it breaks, and also if you try to pick the string after it's already broken.

However, a single string breaking is not a catastrophic failure for the whole banjo. If you're playing with a group of people and a string breaks, you're probably not going to stop everyone while you replace it. You're going to keep playing until the end of the song, and avoid picking that string. And if by mistake you do try to pick that string, the banjo doesn't burst into flames. It simply doesn't make noise for that pick.

Sounds like some error handling is in order

class Banjo {

  // of class is unchanged

  pickString(stringIndex, strength) {
    try {
      return this.strings[stringIndex].pick(strength)
    } catch (err) {
      return null

This again has parallels to how a router or controller works in a server-side framework. If you encounter an error when handling a request, you probably don't want to crash the entire application. Crashing the entire app would mean that you wouldn't be able to serve further requests. Instead, you catch the error and return an appropriate HTTP status code and message to the user.

Or if you're more comfortable on the front end, this is similar to Error Boundaries in React. Same idea: if one component fails, you don't want to crash the entire application if you can help it. Depending on the context, a catastrophic failure of one component can be simply a minor inconvenience to its parent.

If you're working through this exercise with an object of your own choosing, start thinking about errors. In what ways can various components of it fail? How should those failures be handled at various levels of the application?

Tomorrow we'll start adding a real UI.

Did you like this?

I send a daily email with tips and ideas like this one. Join the party!