Getting into open source


“I sho’ would like to contribute to open source, but I suck at git! I mean who has time to cherry-pull a request? How do I append my commits?” Does this sound like you? Are you enthusiastically intimidated by the vast wall of Hi, I’m Cliff. You’re here because you want to “cherry-pull” your github thing-uh-muh-whats-it. I’m here because I used to feel the same way, intimidated by git and social coding. How do the experts do it? Why come I can’t do it? I wanna be cool like the kids in the bay area. Today I plan to show you a simple example using someone who is not yet aware that she will be my guinea pig. In case you are not aware, there’s an initiative circling the web called #100DaysOfCode where folks write code for 100 days straight and share their progress. I happen to be involved in a group of terrific #CodeNewbie people who are all doing the same. Many of them are early in their career and/or experience yet are extremely passionate about what they are doing. Each individual works their own Github repository. I chose to grab a random Github project from this group and submit the infamous Pull Request while explaining the process in its entirety.

The lucky winner of my random drawing, thus the guinea pig and recipient of my unsolicited assistance, is Angela Andrews (@ScooterPhoenix). Her repository is a rather interesting restaurant Tip Calculator where she is currently working on the details of splitting the check between guests. The code is relatively simple as it is early in the challenge. I’m going to assume only a passing familiarity with git and github in my article meaning you should have at least heard of Github and the git software while having a basic understanding of what it’s used for. With that understanding we begin, as anyone would begin in open source, by visiting the repository and perusing the Readme.

When starting your own Github project you would usually create a Readme as the first file added to your project. The Readme is a special file, usually having an “.md” extension, that is rendered when you first load the home page of a Github repository. It is a text file you can fill with details describing the project. You may use a special programming syntax called “mark-down” to format the text in any way you like, such as adding boldness to the font, colors, hyperlinks, images, etc. You can think of Mark-Down as a different kind of HTML. In my case I won’t need to create a readme. Instead I will collaborate with our unsuspecting participant by getting a copy of the repository under my Github account. We use the special term, “fork” to refer to a copy that someone obtains of of a git repository. I click on the “fork” button on the project’s home page to create this special copy under my account.
fork screenshot
github-forking-screenshot

Now I own a publicly visible copy of the original repository and can do whatever I please without damaging the original or upsetting the original project creator. The concept of ownership is important because I am now responsible for whatever changes I make to the source code. If someone finds my fork and decides to use it then they are obtaining the copy that I choose (or choose not) to maintain. If the original project owner decides to make further changes to the project then it is up to me to update my copy by pulling those new changes in. That does not mean that the entire project belongs to me, only that there is a potential for me to create an entirely new product based on the original idea. I will cover ownership in more detail later but the important thing to understand is that I have taken ownership of a copy of the project.

The Git Command Line Client
The next step is to download the source code to my development computer. I do this with special software called a git client. People often confuse the git client software with the github website because they both have git in the name and they both do similar things. The differences may not be obvious but it might help to understand that the “git client” is a set of programs that you run directly on your development computer while github.com is a web site that we all use to view and interact with open source repositories that have been uploaded by ourselves and others. The “git client” programs come in several different variations with the most popular and most intimidating being the git command line program. The git command line program enables you to run git commands from within another program (called a terminal or command program) and it requires a bit of understanding of how terminal programs and command lines work. There are other more newbie friendly git clients available, some of which have a Graphical User Interface (GUI) or are bundled as part of an IDE. (An IDE is a term that describes a program source code editor like Visual Studio, Xcode, or Eclipse.) I will use the git command line program to in today’s example so bear with me. (The details of downloading and installing a git command line program for your computer can be found here. Also note that the command line program comes bundled with a git GUI program.)

Cloning the repository
The act of cloning a git repository simply means copying the repository and all of its working files to your development computer. After forking the project I am taken to the forked copy under my account. If you blink you might miss this subtle but important detail because the page looks exactly like the original but it adds the detail of being associated with my personal github account. The URLs to the page and all the source code under it will all reflect my user account rather than the account the original project owner. I click green “Clone or download” button to find a special clone URL.

I open terminal on my Mac (on windows you would start the “command” program which can be found in your start menu), change my working directory to an empty one and run a git command to download or copy the source code from my fork: git clone https://github.com/cliff76/tipcalc.git
The special URL seen here is found on the webpage of my forked copy NOT the original. It’s important to understand that I am downloading and working from my forked copy rather than directly off the original because it is one of the strengths of git. It is also one of its more confusing aspects because many people are more familiar with the idea of working directly against an original set of files. Instead, you work with a downloaded copy of you forked copy of the original. That is a copy of a copy of the original! I stress this point because I’ve heard so many people express fear and doubts about destroying the original project which is actually pretty difficult to do. (That’s not to say it is impossible, just that it would need to be a pretty intentional action from both the project owner and the contributor.)

After the clone command completes you can feel free to examine the files that were copied to your development computer. The index.html file is usually the starting point for any web application and this one his no different. In my case, I open this file in my web browser (by double clicking the icon in Finder, my file explorer) and play with the app. After entering an amount in the total bill amount form field you can adjust the tip percentage by either clicking one of the options next to “Tip Percentage” or by sliding the “Tip Percentage” slider. The app works beautifully! While toying, I noticed that selecting one of the options does not automatically adjust the slider to the selected amount. Now I decide to put on my open source contributor hat and go to work! (You could do the same with many of these earlier Github projects!)

I open the HTML file in my favorite program editor (I always use IntelliJ Idea for everything but for some reason I decided to use TextMate2) and search for the fields I am interested in, the radio option buttons and the slider control. I notice that they each call a JavaScript function named “tipCalculate()” whenever you interact with them. I then look at the JavaScript file named “scripts.js”. I find the JavaScript function’s definition there and read through it. The function takes the tip percentage as a whole number as its parameter and the bill amount as it’s second parameter. It uses these two values to compute the tip amount. It then updates the tip amount next to the slider with the computed value.

Armed with this understanding, I would like to add the capability of adjusting the slider to reflect the tip amount when this function is finished. I could add a single line of code to set the value of the slider at the very end of the function but then I would have a situation where any attempt to manually change the slider’s value calls into this function which will automatically change the value of the slider which could trigger a call back into to the function which would change the slider which would call back into the function which would… you get the point? This is a common problem called recursion where a function creates some side effect that triggers a call back into the same function triggering the side effect and eventually causing a loop that never ends. Rather than fight with recursion I decide to create a new function named, “updateTip()” that does the EXACT same thing as the “tipCalculate()” function.

function tipCalculate (slider, bill){
    var tip = document.getElementById('tipamount');
    var total = document.getElementById('billAmount');
    var slideval = document.getElementById('slideval');
    var bill = parseInt(document.getElementById(bill).value);

    var prcnt = slider * .01;

  if (bill == null || bill == '') {
    tip.innerHTML = 'Please enter an amount';
    return false;
  }
  if(isNaN(bill)) {
    tip.innerHTML = 'Please enter a number';
    return false;
  }

  if(bill >= 0){
    tipToLeave = (bill * prcnt);
      tip.innerHTML = '$' + (bill * prcnt) .toFixed(2);
        slideval.innerHTML = slider + '%';
        total.innerHTML = '$' + (bill + tipToLeave).toFixed(2);
  }

}

function updateTip(slider, bill){
    var tip = document.getElementById('tipamount');
    var total = document.getElementById('billAmount');
    var slideval = document.getElementById('slideval');
    var bill = parseInt(document.getElementById(bill).value);

    var prcnt = slider * .01;

  if (bill == null || bill == '') {
    tip.innerHTML = 'Please enter an amount';
    return false;
  }
  if(isNaN(bill)) {
    tip.innerHTML = 'Please enter a number';
    return false;
  }

  if(bill >= 0){
    tipToLeave = (bill * prcnt);
      tip.innerHTML = '$' + (bill * prcnt) .toFixed(2);
        slideval.innerHTML = slider + '%';
        total.innerHTML = '$' + (bill + tipToLeave).toFixed(2);
  }

}

What that change I can open the index.html and call this function form the slider’s “onchange” attribute instead of calling “updateTip()”. I also need to give the slider an id so that I can locate it with the JavaScript function document.getElementById('slider'). The new code looks as follows:

<input id="slider" class="range-style" max="100" min="0" step="1" type="range" value="0" data-com="" />

Then I can add the one line at the end of “tipCalculate()” to set the value of the slider knowing that the slider itself will never call this function.

function tipCalculate (slider, bill){
    var tip = document.getElementById('tipamount');
    var total = document.getElementById('billAmount');
    var slideval = document.getElementById('slideval');
    var bill = parseInt(document.getElementById(bill).value);

    var prcnt = slider * .01;

  if (bill == null || bill == '') {
    tip.innerHTML = 'Please enter an amount';
    return false;
  }
  if(isNaN(bill)) {
    tip.innerHTML = 'Please enter a number';
    return false;
  }

  if(bill >= 0){
    tipToLeave = (bill * prcnt);
      tip.innerHTML = '$' + (bill * prcnt) .toFixed(2);
        slideval.innerHTML = slider + '%';
        total.innerHTML = '$' + (bill + tipToLeave).toFixed(2);
  }

  document.getElementById('slider').value = slider;
}

I test this by saving both the “index.html” file and the “scripts.js” file and refreshing my browser to load both files again. It works like a charm but I’m not happy! I have to functions that do almost the EXACT same thing because I copied all of the code from one function into the other. Copied code is a problem in any software project and I KNOW I can do better. Instead of copying the code I can call the new “updateTip()” function from the “tipCalculate()” function! That way if anyone ever needs to change the way it works changes only need to be made in one spot. The final code in “scripts.js” looks like so:

function tipCalculate (slider, bill){
	updateTip(slider, bill);
	document.getElementById('slider').value = slider;
}

function updateTip(slider, bill){
    var tip = document.getElementById('tipamount');
    var total = document.getElementById('billAmount');
    var slideval = document.getElementById('slideval');
    var bill = parseInt(document.getElementById(bill).value);

    var prcnt = slider * .01;

  if (bill == null || bill == '') {
    tip.innerHTML = 'Please enter an amount';
    return false;
  }
  if(isNaN(bill)) {
    tip.innerHTML = 'Please enter a number';
    return false;
  }

  if(bill >= 0){
    tipToLeave = (bill * prcnt);
      tip.innerHTML = '$' + (bill * prcnt) .toFixed(2);
        slideval.innerHTML = slider + '%';
        total.innerHTML = '$' + (bill + tipToLeave).toFixed(2);
  }

}

After testing the change and verifying my computer doesn’t decompose I commit the change! I use the terminal commands
git add . && git commit -m "Connects the slider's value to the radio buttons that set the percentage."
This is two commands, the first adds all of my changes to a staging area to be picked up by a commit and the second command performs the actual commit. A git commit records all of the changes you made to your local repository. Most newbies feel afraid or ashamed at this point because of fear of breaking the project and upsetting the owner or because of imposter syndrome. You want to commit all the time, it’s perfectly safe and highly recommended! Remember what I said above about working against a copy of a copy of the original? You WILL NOT BREAK THE ORIGINAL! (I promise!) Finally I run one more command,
git push origin master
This pushes the changes recorded in my local copy of the repository up to the forked copy under my github account. (I still have not broken or touched the original!) These changes will now be visible from github.com to anyone who visits my forked copy.

I am ready for the final part of my ritual! I am ready to tell Ms. Angela about my hard work! I hope she likes the change and does not decide to send the National Guard to my door or demand repentance! This final ritual comes in the form of a pull request! This is the magic art that all the cool kids in New York talk about all day. They’re all, “I did a PR on the Mahogany project but then project lead said I had to rebase my commits on top of the latest from develop and I was like fa reeeeaaaallllzzz???!!” And you’re all, “What’d he say? PR a wooden table and something about second base but who’s on 1st? I don’t know???”

The All Mighty Pull Request
The most difficult part of contributing to open source is now behind me and I am ready to explain the most exciting and beloved series of steps. Because my changes have been recorded on my development computer and then pushed to my personal account I can share them with the original author via a few mouse clicks. Furthermore, these changes can become part of the original just as easily. I visit github.com and view my forked copy of the project to find the “new pull request” button under the number of commits counter.
click-new-pull-request
Alternatively you can drill into the pull requests tab and create a new pull request from there.
click-pull-request Clicking that button gives you a screen with a big green create pull request button that you can click to create your first pull request. Simply fill in the comment box with details of what changes you made or why you would like your changes to be combined with the original project, click the green button and you’re off!
create-pull-request

2 thoughts on “Getting into open source

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s