Committing to Open Source

Committing to open source is a badge of honour in the developer community. When you first start learning to code, you will quickly learn what open source is, the language you're learning with is probably open source, the packages you use to help you actually put some pixel on a screen, or whatever your goal is, are probably open source. Understanding what open source is quickly becomes second nature to a developer. A common interview screener is, do you commit to open source projects? It's such a common concept between us, that we sometimes forget how strange it is to the rest of the world. I excitedly told a friend of mine the other day that I made my first commit to open source, he is an English teacher, this was his response:

I would often think to myself, when am I going to commit to open source? When am I going to be able to understand enough to give back to an open source project? I was genuinely concerned about it. If you're also wondering or in any way worried, here is my timeline, and some advice based on making my first commit, which actually turned out to be much easier than I thought it would be.

My first commit to Github was 18th February 2013, so coming up to 5 years.

I probably started learning to code a couple of months before that. In 2014 I got my first job as a junior developer working for MOO. I worked there for about 2 years without even thinking about contributing to open source. I was too busy trying to learn how to be a developer. Then I spent 2 years working at various places, doing some contracting/free lance work. In July of this year I started working at simplabs as an Ember.js consultant. Then on the 1st of November 2017, my first pull request to an open source project was accepted.

If you took a moment to look at the commit, there's one thing to notice, the change I made was literally 1 line of code... plus tests. The tests are the important part though. I probably could have written the one line of code 2 or 3 years ago, but without the tests, I would have spent a lot longer trying to get it to work and had a hard time getting it merged. So here's my advice for getting to the stage of committing to open source.

1. Learn testing.

Testing is boring. Testing fun.

Essentially playing tennis is boring if every time your partner hits a ball to you, you miss it. Playing tennis is fun if you can have a rally. Testing is the same when you're learning it, i.e. it's no fun when you're rubbish at it. I basically started learning to test about 3/4 years ago, when I was at MOO, but I never really 'got' it until recently. My testing learning experience went through three stages.

  1. Submitting code without tests and being asked to write tests. Spending some time feeling sad that I didn't really understand the tests, or their setup and dependencies, eventually getting help from some great senior developers who would patiently help me write new tests. Then I'd get the feature merged an move on with my life.
  2. Learning pattern recognition enough to find tests that were similar to my new feature, enough that I could copy and paste the other test, and adapt it for my feature.
  3. Reading tests through and understanding what the code supporting them is supposed to do, which believe it or not (and I wouldn't have believed it when at stage 1 & 2) was easier to understand than actually reading the code under test.

So it took me about 3/4 years to understand testing. It can be done much quicker if you're motivated, and hopefully I'll provide some motivation below. As an aside, I actually still hate setting up tests from scratch because setup and dependencies are always a nightmare (more so for front end code).

If you look at the tests for my pull request:

  test('resource accepts singular name', function(assert) {
    assert.expect(3);
    let done = assert.async(2);

    this.server.db.loadData({
      contacts: [
        { id: 1, name: 'Link' },
        { id: 2, name: 'Zelda' }
      ],
      blogPosts: [
        { id: 1, title: 'Post 1' },
        { id: 2, title: 'Post 2' }
      ]
    });

    this.server.resource('contact');
    this.server.resource('blog-post', { path: '/posts' });

    $.ajax({
      method: 'GET',
      url: '/contacts'
    }).done(function(res, status, xhr) {
      assert.equal(xhr.status, 200);
      assert.deepEqual(res, { contacts: [{ id: '1', name: 'Link' }, { id: '2', name: 'Zelda' }] });
      done();
    });

    $.ajax({
      method: 'GET',
      url: '/posts'
    }).fail((xhr, textStatus, error) => {
      assert.ok(false, 'failed to find custom path');
      done();
    }).done(function(res, status, xhr) {
      assert.ok(true);
      done();
    });
  });

This test is almost exactly the same as another test in the file:

  test('resource generates get shorthand for index action', function(assert) {
    assert.expect(3);
    let done = assert.async(2);

    this.server.db.loadData({
      contacts: [
        { id: 1, name: 'Link' },
        { id: 2, name: 'Zelda' }
      ],
      blogPosts: [
        { id: 1, title: 'Post 1' },
        { id: 2, title: 'Post 2' }
      ]
    });

    this.server.resource('contacts');
    this.server.resource('blog-posts', { path: '/posts' });

    $.ajax({
      method: 'GET',
      url: '/contacts'
    }).done(function(res, status, xhr) {
      assert.equal(xhr.status, 200);
      assert.deepEqual(res, { contacts: [{ id: '1', name: 'Link' }, { id: '2', name: 'Zelda' }] });
      done();
    });

    $.ajax({
      method: 'GET',
      url: '/posts'
    }).fail((xhr, textStatus, error) => {
      assert.ok(false, 'failed to find custom path');
      done();
    }).done(function(res, status, xhr) {
      assert.ok(true);
      done();
    });
  });

The only difference is this line:

    this.server.resource('contacts');

Vs.

    this.server.resource('contact');

This makes sense given the issue that I was trying to solve: https://github.com/samselikoff/ember-cli-mirage/issues/1082

resource helper should accept singular name

So in all honesty I have not read through the resource() method on server. I simply understood what the method was supposed to do based on the first test, and changed the key line. I wrote the second test (copy & pasted, then amended), which failed, then I simply added the one line:

    resourceName = pluralize(resourceName);

My test passed... and the other tests did not fail. So I was done. Hopefully this is a good motivation for getting comfortable with tests, or at least reach the pattern recognition stage.

2. Find a project you like and follow it.

I knew from at least a year ago that if I was to make a commit to anything, it would be ember-cli-mirage. I built a lot of prototypes in Ember so I used this package a lot, and found it super useful. I'd even tried to debug some errors which made me somewhat familiar with the code. About 6 months ago I started watching the project.

Subscribing to a project means you get regular email updates about activity. I know what you're thinking and the answer is:

I stopped checking those emails after 1 week. However I would occasionally browse them, and they provided the eventual nudge that got me to search for an issue to fix.

3. Play the system.

And by system, I mean people

Developers are people too. I knew that the maintainer of the project was probably a very busy chap. So the first thing I did was this:

I filtered the issues based on the project's author. I predicted that Sam would be more interested in merging fixes for issues he had created himself. I was not wrong. And of course I looked at that list and found the issue that I thought I'd be able to fix. In reality I had 2 days bank holiday (I live in Germany and it was 500 years since Luther nailed some flyer to a church door, or something), and a couple of days before, in the evening, I decided to scope out an issue that I would work on over those two days. Then I ended up submitting that PR the same evening within 2 hours of seeing that issue. Leaving me to enjoy Germany for 2 days.

4. Join a friendly Open Source community

YMMV - Your Millage May Vary with this one

I happen to love Ember.js which is a quite small community in comparison with say React. I don't know if it's because of its small size, or its outsider/underdog status, but in the case of Ember.js it is in fact true that every one is very friendly. Whenever I've had problems I have been able to reach out to authors of packages and get fairly timely and polite responses, no matter how dim witted my mistakes were. In this case, when I opened my PR I waited a couple of days, then said Hello to Sam on Ember.js slack and asked him to review it, which he did.

Conclusion

The point of this post is to give an example of someone who took 5 years to commit to open source and how I got to that point. I am sure many people commit sooner and many commit later or never at all. You should never worry how long it takes you to commit to open source, I could have probably committed something a couple of years before I did and I easily could have gone another couple of years without making a commit. Hopefully this post gives you an idea of how to make a contribution if you want, or the peace of mind to focus on what's really important to you right now if you're not ready to contribute to open source just yet.

My route to committing is also probably not that common. I imagine a lot of people use a package for work that didn't fulfil their needs or had a bug, and they ended up fixing it as part of work. That's a very valid way to contribute, it just never happened to me.

Finally big thanks to my friend and mentor Nick Angeli for getting me to this point. I'll buy you that beer one day.