Subscribe

Inform and Act

Read our official statements regarding recent executive orders and find resources to help you take action. Learn more

How CS50 at Harvard uses GitHub to teach computer science

How does Harvard's largest course, an Introduction to Computer Science, use GitHub to achieve its learning goals?

Professor David J. Malan, Gordon McKay Professor of the Practice of Computer Science at Harvard University, is dedicated to offering his students a robust learning experience. This post outlines how he uses GitHub and his own custom tools to build hands-on assignments for CS50 students.

Using GitHub for CS50

With over 700 students, 80 staffers, and 2,200 participants in their end-of-term CS50 Fairs, CS50 has a reputation for rigor, real-life application, and engaging material.

At the same time, says Professor Malan, about half of CS50’s students typically treat the course as “terminal”— as their one and only course in computer science. So the projects touch on applications in a variety of fields, from social sciences and humanities to medicine and finance.

Malan says of the learning goals of CS50: “We want to provide students with a solid foundation in computer science so that they are well prepared for any field. And also bring to bear some practical skills to that world. So that is actually tied in with our adoption of GitHub this past year.”

A gentle onboarding to Git and GitHub

The mental model for cloning, branching, opening pull requests, or pushing can be tricky for newbies just starting out. As a way to onboard students, Malan wrote a command-line tool that wraps a sequence of Git commands called submit50. They developed submit50 to not “reinvent the wheel” with a new submission system, but to create space for students to grow into comprehensive GitHub use as their learning evolves beyond CS50. Says Malan:

One goal was to have students graduate, so to speak, from the class actually having a GitHub account. And even though they don't keep their work in public portfolios for the course, the hope is that they'll have at least enough understanding of GitHub that they can use it after the term ends for personal projects.

Course outline for CS50

Student workflow for submit50

CS50 uses the structure of one branch per problem, and students engage Git and GitHub from the command line.

First, they run a command in their directory on a Linux system with a folder they wish to submit to CS50’s servers. The student then runs submit50 foo where foo is the unique identifier for that assignment.

submit50 models how Git and GitHub work while abstracting away some of the complexity:

Behind the scenes we show them the command so that through a bit of osmosis, they can infer what's actually going on.

We clone their repo, which lives in our submit50 organization. So we have full administrative rights, and students have push and pull privileges only.

The submit50 script clones that repo into a temporary directory. We do the equivalent of rm -rf to blow away whatever is currently in there, and then git-add the entire contents of their current working directory into that repo, and then tag it with a tag that corresponds to the problem's name, and then push it to the server.

Project-based assignments, real-life applications

An example assignment is “C$50 Finance” where students build an application to simulate stock trades using Python with Flask, HTML, CSS and SQL.

Students create tables with user accounts, who can then buy and sell stocks. The application queries Yahoo Finance for stock quotes, almost in real time.

Malan is delighted to see the different personal touches students add to their projects, both functional and aesthetic.

It's a fun opportunity to introduce students to even the aesthetics of web design. Invariably the first thing students do is customize the aesthetics of the site, and then certainly there are differences in features, and we're fine with that. The assignment requires ultimately that they add a personal touch, so any feature that's not been enumerated by us they're welcome to do so long as it's of reasonable scope. So we'll get different outputs from that as well.

Rituals of success

All students exhibit their final projects an end-of-semester “CS50 Fair.” About 2,200 people attend to see the student demos.

Malan designs the event as a kind of celebration, a capstone ritual where students can show people what they’ve made:

It's a fun way to delight in how much you've finished, particularly if new to programming just months prior. And it perhaps creates a bit of social pressure too. You know you're going to be showing this not just to your Teaching Fellow, but to your classmates, and you want to be proud of it. And so, hopefully, that incentivizes all the more of a strong finish.

Computer science and tech news = CS50 Live

Pushing beyond the boundaries of the traditional classroom, Malan connects the course materials with the news in a kind of “Daily Show” for technology, called “CS50 Live.”

Malan and the crew of Teaching Fellows take up current events, like Apple’s implementation of OpenSSL with a bug in it, and dig into the code on the show.

Hear more about GitHub and CS50 at SIGCSE

Professor David Malan will present CS50 along with Omar Shaikh (SFSU) and S. Monisha Pulimood (The College of New Jersey) at the Special Interest Group in Computer Science Education of the Association for Computing Machinery (ACM SIGCSE).

"How I Implemented GitHub In My Classroom"
Saturday, March 11
10:45AM-12:00PM
Room: 616/617


This is a post in our “Teacher Spotlight” series, where we share the different ways teachers use GitHub in their classrooms.

Join this week’s discussion in the community forum: How to automatically gather or collect assignments?

How to run a Google Summer of Code project on GitHub

Google provides some guidance on how to effectively run a Google Summer of Code project but it's not tailored specifically to GitHub's workflow. To set clear expectations for mentors and students here's our ideas on how to successfully participate in Google Summer of Code as a mentor or organization administrator.

The application process

Document project ideas

Make a dedicated file or repository for documenting project ideas and discuss them in issues. The ideas should be things that are going to be useful to your project, would take a maintainer a week or two to complete and you think should take a student between a month and a month and a half to complete. You can populate these from help wanted-labeled issues in your repository. They should be brief enough to stimulate discussion on their implementation but not detailed enough for students to be able to copy-paste any part into their proposal.

For example, the Homebrew project has a repository for these ideas (updated for GSoC 2017).

Strongly encourage students to adopt one of your ideas rather than their own. You have a much better idea than they do on what will be useful, achievable, and mergeable.

Require a merged pull request to your project

Rather than angsting over student technical interviews or their proposals documents you should make your decision primarily on which students (if any) to accept based on a trial of the work you expect from them in the summer: a pull request to your project's repository. Google expects students to get involved in communities so requiring e.g. a one line change in a pull request is more time efficient than any other metric.

In general any established GitHub open source repository should have an easy way for new, aspiring contributors to submit a useful pull request. In Homebrew's case they have a brew audit linting tool where some lints are deliberately left unfixed to give newcomers an opportunity for an easy first pull request.

For example, the Homebrew project's process is documented in their README.

You should not help students any more than any new contributor or provide any more guidance than what's already documented in your project. If they ask for help, point them to the instructions (and consider improving them). If they cannot figure out what other contributors can: they are unfortunately not good candidates for GSoC which requires them to be self-motivated, driven and able to learn independently over the summer.

Provide regular review to student pull requests before the application deadline. Make it clear to the student that the pull request must go through the review process and get merged before you can accept their application. They're in a rush, but you shouldn't be. In respect of time, students shouldn't rush last minute to hit a deadline.

The summer

Favor small pull requests over large ones

This is a good principle in general but not the typical mindset for students who typically do work for a single output that's handed in. Encourage them to split their work up into multiple, regular pull requests over the summer so their pull requests can be more easily reviewed and merged.

For example, see @AnastasiaSulyagina's pull request to remove some duplicated exceptions as part of Homebrew's 2016 GSoC. This was a small change review and a merge followed quickly.

Maintain normal flow

Most of your interactions with your student should look like your interactions with other maintainers and contributors on your project. For example, if you talk with other maintainers on Slack, invite your student and encourage them to ask questions when they have them. If you can talk about things in issue comments and pull request reviews: do that instead of video calls or other private methods of communication so that other maintainers can help provide review and feedback.

Brief, regular check-ins

Have a meeting that you both stick to every week (that neither of you are on vacation) on text (i.e. IM), audio or video chat. Defer to the student's preferences on IM vs. audio/video as they may feel more comfortable communicating over text if English isn't their first language. This should be your chance to see what progress there has been if there's been no public activity. That said, a week with no commits, issue comments, or PR comments is a sign of major concern that you should raise with the student.

Strict failure requirements

As mentioned previously: you should not accept students who have not made a trivial pull-request to your project. Similarly, the focus of the summer should be around pull-requests too. If the student does not have a significant, non-trivial pull request opened by their mid-term: they should fail. If the student does not have a significant, non-trivial pull request merged by the end of the program: they should fail. Again, splitting the work up into multiple pull requests over the summer is vastly preferable to opening pull requests at the last minute.

Like many things in life: strict, no-compromise boundaries may sound harsh but end up being kinder to the student. You can communicate these expectations at the beginning of the program and then they don't need to worry about whether they will pass or fail. This is also a life lesson: many deadlines after graduation are not negotiable and it's better to fail at GSoC than many other things in life.

That seems quite strict?

It does, yes. The requirements above may mean that you're not able to get any students who are good enough for your project or that you need to fail students. This is unfortunate but it's ultimately better for students and much better than having a bad GSoC experience.

For point of comparison while following the above system for the last two years the Homebrew project has always had more good students than mentors available for them, never failed any students, had the majority of students ship major features our users have been happy with and, best of all, had a minority of students become and stay Homebrew maintainers.

Now that you know how to effectively run a Google Summer of Code project on GitHub consider applying as a GSoC organisation before the February 9, 2017 at 17:00 (GMT) deadline and have a great summer!

GitHub Classroom for AP Computer Science at Naperville North High School

We released GitHub Classroom in fall of 2015 to make it easier for teachers to distribute code and collect assignments on GitHub. In the last year, we've seen it enter the classrooms of thousands of teachers. We're delighted that it's helping students learn STEM subjects and even more excited to share the processes, tips, and tricks educators have built around it.

To kick off a series about educators and classroom practices, we'd like to introduce you to Geoff Schmit, a former engineer for National Instruments. In his tenth year of teaching at Naperville North High School, Geoff seeks to prepare students with the mindset of a creative, ethical engineer who uses real-world tools:

I had a background in source control which I brought with me from my life as a software engineer. I think students should learn about source control before they leave this class. They should have written unit tests before they leave this class. And they should read articles about technology in society and ethics before they leave this class.

He kickstarts his semester with pre-filled repositories—sample code and libraries in GitHub Classroom. Students dive straight in, without the tool getting in the way:

On the first days of school I want them doing turtle graphics in BlueJ. I don't want to worry about setting up the environment and everything. So I'm able to pre-package everything, so they can double-click on it and type some code in, and we'll work.

This is his first year using GitHub Classroom to organize his assignments and gently introduces students to GitHub.

Using Classroom, students click on a single link to create and manage their repositories:

So rather than them having to worry about forking, cloning, and that stuff, they just click on the link to accept the assignment.

With Github Classroom things are so much smoother because it copies the whole assignment into a private repository, which is nice.

Distribute assignments with one link

To submit their assignment, students commit to the master branch of their own repositories, then pass that link to Geoff’s Learning Management System (LMS), Canvas.

To grade their the project, Geoff downloads the code through the GitHub desktop client, runs it, and assesses the lab.

I have the link right there to GitHub, and I click on it, and I download it, go through all their code, run it, whatever, and just go right on to the next one. So it's super fast to take a look at their code and run it, which is great. It's been really easy. It's worked really well.

Creative assignments

Dr. Mitchell Resnick, creator and educator of Scratch, refers to learning experiences with “low floors, wide walls:” activities that are easy to begin, but enable a creative flow that keeps learners engaged past the requirements.

Geoff’s labs aim to spark this kind of engagement in his students. The Cityscape Lab, one of four over the semester, offers few concrete specifications: create three classes and animate your Cityscape in some way.

Cityscape Lab from Schmit’s course

So, that's the low floor and for some students, that's going to be a stretch and they're going to work really hard to do that.

But then for others, it's like, "Well, you could do more." We haven't done loops or anything yet so I say, can you figure out how to do windows, other than having to draw all 100 of them by hand? or *can you figure out basic looping structures? 

And I've had submissions like a student who downloaded constellation star data so the stars in the sky actually matched reality. I'm sure she spent hours and hours outside of class working on that but she was really excited about it, whereas other students just got their buildings done, and that's fine.

What I have been surprised about, because I was worried about it at first, is that when students meet the requirements they don't stop.

Top Classroom hacks

Geoff has several AP Computer Science courses a day. When he’s demonstrating to his class and projecting code snippets or examples, he uses one branch per class period.

So when Period Four starts on Tuesday, Geoff picks up from yesterday’s branch:

Every day I update Canvas with a link to the branch of each class period. If a student is absent, they know where to find everything we did together as a class yesterday. And that's been really great.

Take risks, trust each other

Geoff only grades exams and a summative lab at the end four units. All the other projects, daily hands-on activities, and everything else, is all practice.

By putting projects front-and-center instead of grades, Geoff says students are more open to learning experiences that might put them in more vulnerable positions, like sharing work and pair programming.

Students say to themselves, "I can take risks. I'm not being graded on this. I'm not worried about my partner not doing as well as me, because we're just practicing." That trust goes a long way towards helping them accept different kinds of activities.


This post is the first in our “Teacher Spotlight” series. We’ll share the different ways instructors use GitHub in their classrooms, and facilitate discussions in the Education Community.

Join this week’s discussion: What are your favorite resources for teaching programming?

CARTO adds data insights to the Student Developer Pack

CARTO is the newest addition to the GitHub Student Developer Pack.

CARTO joins the Student Developer Pack

CARTO is a powerful open platform for discovering and predicting key insights underlying the world's location data. It's a suite of geospatial tools, services, and APIs for discovering and predicting the key insights from your location data in your applications. You'll be able to do powerful analysis of your data.

With CARTO you get:

  • CARTO Builder, a web-based drag-and-drop analysis tool for users to discover and predict key insights from location data.
  • CARTO Engine, a one-stop shop of geospatial tools, services, and APIs to discover and make predictions with your location data.
  • A Mobile SDK that lets you develop custom applications with maps on any mobile platform—Android, iOS, and Windows Mobile 10.
  • Location data services that let you obtain maps and services on native applications, using them on the web with open source JavaScript or third-party libraries.
  • Data Observatory services so you can turn your data or address locations into comprehensive reports about the characteristics of the local population.

Members of the pack get:

  • 350MB Database Storage
  • Synced Tables
  • $5 worth of LDS credit per month
  • 10K tweets per month
  • 100K mapviews per month
  • Free account upgrades with increased database storage
  • Real-time data
  • Location data service credits
  • Premium features

The Student Developer Pack gives students free access to the best developer tools from different technology companies like Datadog, GitKraken, Travis CI, and Unreal Engine.

Students, get mapping now with your pack.

Flatiron School joins the GitHub Student Developer Pack

Flatiron School has joined the Student Developer Pack to offer students one free month of their Community-Powered Bootcamp, a flexible online course in web development.

Flatiron School joins the Student Developer Pack

The Community-Powered Bootcamp is a self-paced subscription program for beginners. You'll learn online using the same course of study as the Web Developer Program—a comprehensive curriculum tailored to job seekers. In a month, you can pick up a few in-demand skills and work with a community of other learners to start reaching your goals, whether they are technical literacy, a new programming language, or a new career.

The details

  • Get the first month of tuition free
  • Start 800+ hours of rigorous web development coursework
  • Take on topics like HTML, CSS, JavaScript, Node.JS, React, and Ruby on Rails
  • Learn online and at your own pace with a curated community of students
  • Build a portfolio
  • Get help when you need it, 24/7

After one month, you can sign up for a monthly subscription of $149 USD.

The Student Developer Pack gives students free access to the best developer tools from different technology companies like Datadog, GitKraken, Travis CI, and Unreal Engine. Sign up for the pack, and start learning.

GitKraken joins the Student Developer Pack

GitKraken is now part of the Student Developer Pack. Students can manage Git projects in a faster, more user-friendly way with GitKraken's Git GUI for Windows, Mac, and Linux.

GitKraken joins the Student Developer Pack

GitKraken is a cross-platform GUI for Git that makes Git commands more intuitive. The interface equips you with a visual understanding of branching, merging and your commit history. GitKraken works directly with your repositories with no dependencies—you don’t even need to install Git on your system. You’ll also get a built-in merge tool with syntax highlighting as well as one-click undo and redo for when you make mistakes. Other features of GitKraken are:

  • Drag and drop to merge, rebase, reset, push
  • Resizable, easy-to-understand commit graph
  • File history and blame
  • View image diffs in app
  • Fuzzy finder and command palette
  • Submodules and Gitflow support
  • Easily clone, add remotes, and open pull requests in app
  • Keyboard shortcuts
  • Dark and light color themes
  • GitHub integration

Members of the pack get GitKraken Pro free for one year. With GitKraken Pro, Student Developer Pack members will get all the features of GitKraken plus:

  • The ability to resolve merge conflicts in the app
  • Multiple profiles for work and personal use
  • Support for GitHub Enterprise

Students can get free access to professional developer tools from companies like Datadog, Travis CI, and Unreal Engine. The Student Developer Pack lets you learn, experiment, and build software with the tools developers use at work every day without worrying about cost.

Students, get a Git GUI now with your pack.

Get testing with Taplytics in the Student Developer Pack

Taplytics is now offering mobile testing to students in the Student Developer Pack.

Taplytics joins the Student Developer Pack

Taplytics helps mobile developers create great experiences through: A/B testing, push notifications, and custom analytics. As part of the GitHub Student Developer Pack, Taplytics will give you complete access to its suite of tools for native mobile apps.

For members of the pack Taplytics is offering full, unlimited access to the platform free for 6 months. You will be able to do visual tests on your apps and make design decisions that work best for your users. You’ll be able to get analytics around your apps that help you iterate on your app in the future. Taplytics also includes tools that help you provide users with the right information at the right time.

The Student Developer Pack gives students free access to the best developer tools from different technology companies like Datadog, Travis CI, and Unreal Engine.

Students, get testing now with your pack.

Back to school: monitoring with Datadog

Datadog is now offering their Pro plan to students in the Student Developer Pack.

Datadog joins the Student Developer Pack

With Datadog, you'll be able to see metrics from all your apps, tools, and services. The plan allows you to:

  • Monitor up to 10 concurrent hosts.
  • Retain stock and custom metrics for up to 13 months.
  • Create insightful dashboards to demonstrate the performance and availability of your applications.
  • Create notifications upon failures.

Datadog provides monitoring and alerting for anything from your first app to multiple servers.

The Student Developer Pack gives students free access to the best developer tools from different technology companies like Stripe, Travis CI, and Unreal Engine.

Students, get monitoring now with your pack.

Back to school: Get translations with Transifex

Transifex is now offering translation and localization software to students in the Student Developer Pack. Transifex is a cloud-based platform built to help you manage the translation and localization of your software.

Transifex joins the Student Developer Pack

Members are eligible for a free year of the Starter plan, a $99/month value. You'll get 50,000 hosted words, unlimited projects, and access to translation partners to bring your software to a global market from the start. You can create software that works internationally from the moment you build your app.

Students also receive 10 team collaborators and can reuse existing translations across your projects.

The Student Developer Pack gives you free access to the best developer tools from different technology companies like Stripe, Travis CI, and Unreal Engine.

Get translating now with your pack.

Summer internships at GitHub in San Francisco

Applications are now open for summer internships at GitHub. Interns will spend nine weeks from June to August working out of our headquarters in San Francisco with teams in engineering, product, marketing, legal, design, and more.

Be a GitHub summer intern

Our interns are placed within existing teams, work on impactful projects, and gain experience with help from professional mentors. Learn more about the program by reading stories from the 2016 interns.

GitHub Interns - Summer 2016
2016 Summer Interns

To qualify for the GitHub internship program you must be a student enrolled in a university, community college, associate, or graduate school program.

2017 Summer Internship Opportunities

More internship opportunities may become available, see our jobs listings for current postings. If you'd like to stay up to date on new openings, sign up for email updates.

Back to School: Learn Fundamentals of Web Development with Thinkful

Thinkful is now offering their Fundamentals of Web Development course to Student Developer Pack members. As a student, you will receive two weeks of 1-on-1 mentorship from a professional software developer.

Thinkful joins the Student Developer Pack

Mentorship is at the core of a Thinkful education. Students who learn 1-on-1 with a mentor perform better than 98 percent of conventionally educated students. If you’re a computer science major looking to get industry-relevant web development skills, this program will help prepare you for the job search. Even if you’re not studying computer science, coding skills will give you a big edge in today’s job market.

The Fundamentals of Web Development curriculum will teach you:

  1. Structure and style with HTML and CSS
  2. Adding interactivity with jQuery
  3. Programming fundamentals in JavaScript
  4. AJAX and advanced jQuery

The Student Developer Pack gives students free access to the best developer tools from different technology companies like Stripe, Travis CI, and Unreal Engine. Now, with Thinkful included in the pack, it's even easier for students to start building great products.

Students, get your pack.

Building your first Atom plugin

Authored by GitHub Campus Expert @NickTikhonov.

This tutorial will teach you how to write your first package for the Atom text editor.
We'll be building a clone of Sourcerer,
a plugin for finding and using code snippets from StackOverflow. By the end
of this tutorial you will have written a plugin that converts programming
problems written in English into code snippets pulled from StackOverflow:

Final Plugin Demo

What you need to know

Atom is written using web technologies. Our package will be built entirely using the EcmaScript 6 standard for JavaScript. You will need to be familiar with:

  • Using the command line
  • JavaScript programming
  • Promises
  • HTTP

Tutorial repository

You can follow this tutorial step-by-step or check out the
supplementary repository on GitHub, which contains
the plugin source code. The repository history contains one commit for each step outlined here.

Getting Started

Installing Atom

Download Atom by following the instructions on the Atom website.
We will also need to install apm, the Atom Package Manager command line tool.
You can do this by opening Atom and navigating to Atom > Install Shell Commands
in the application menu. Check that apm was installed correctly by opening your
command line terminal and running apm -v, which should print the version of
the tool and related environments:

apm -v
> apm  1.9.2
> npm  2.13.3
> node 0.10.40
> python 2.7.10
> git 2.7.4

Generating starter code

Let's begin by creating a new package using a utility provided by Atom.

  • Launch the editor and press Cmd+Shift+P (on MacOS) or
    Ctrl+Shift+P
    (on Windows/Linux) to open the Command Palette.
  • Search for "Package Generator:
    Generate Package" and click the corresponding item on the list. You will see a
    prompt where you can enter the name of the package - "sourcefetch".
  • Press enter to generate the starter package, which should automatically be opened in Atom.

If you don't see package files appear in the sidebar, press
Cmd+K Cmd+B (on
MacOS) or Ctrl+K
Ctrl+B (on Windows/Linux).

Generating a Package

The Command Palette lets you find and run package commands using fuzzy search.
This is a convenient way to run commands without navigating menus or
remembering shortcuts. We will be using it throughout this tutorial.

Running the starter code

Let's try out the starter package before diving into the code itself. We will
first need to reload Atom to make it aware of the new package that was added.
Open the Command Palette again and run the "Window: Reload" command.

Reloading the current window ensures that Atom runs the latest version of our
source code. We will be running this command every time we want to test the
changes we make to our package.

Run the package toggle command by navigating to Packages > sourcefetch > Toggle
using the editor menu, or run sourcefetch: Toggle using the Command Palette.
You should see a black box appear at the top of the screen. Hide it by running
the command again.

Starter Package

The "toggle" command

Let's open lib/sourcefetch.js, which contains the package logic and defines
the toggle command.

toggle() {
 console.log('Sourcefetch was toggled!');
 return (
   this.modalPanel.isVisible() ?
   this.modalPanel.hide() :
   this.modalPanel.show()
 );
}

toggle is a function exported by the module. It uses a
ternary operator to call show and hide
on the modal panel based on its visibility. modalPanel is an instance of
Panel, a UI element provided by the
Atom API. We declare modalPanel inside export default, which lets us access it as an
instance variable with this.

this.subscriptions.add(atom.commands.add('atom-workspace', {
  'sourcefetch:toggle': () => this.toggle()
}));

The above statement tells Atom to execute toggle every time the user runs
sourcefetch:toggle. We subscribe an anonymous function, () => this.toggle(),
to be called every time the command is run. This is an example of
event-driven programming,
a common paradigm in JavaScript.

Atom Commands

Commands are nothing more than string identifiers for events triggered by the
user, defined within a package namespace. We've already used:

  • package-generator:generate-package
  • window:reload
  • sourcefetch:toggle

Packages subscribe to commands in order to execute code in response to these events.

Making your first code change

Let's make our first code change—we're going to change toggle to reverse
text selected by the user.

Change "toggle"

  • Change the toggle function to match the snippet below.
toggle() {
  let editor
  if (editor = atom.workspace.getActiveTextEditor()) {
    let selection = editor.getSelectedText()
    let reversed = selection.split('').reverse().join('')
    editor.insertText(reversed)
  }
}

Test your changes

  • Reload Atom by running Window: Reload in the Command Palette
  • Navigate to File > New to create a new file, type anything you like and
    select it with the cursor.
  • Run the sourcefetch:toggle command using the Command Palette, Atom menu, or
    by right clicking and selecting "Toggle sourcefetch"

The updated command will toggle the order of the selected text:

Reversing Selected Text

See all code changes for this step in the sourcefetch tutorial repository.

The Atom Editor API

The code we added uses the TextEditor API
to access and manipulate the text inside the editor. Let's take a closer look.

let editor
if (editor = atom.workspace.getActiveTextEditor()) { /* ... */ }

The first two lines obtain a reference to a TextEditor
instance. The variable assignment and following code is wrapped in a conditional
to handle the case where there is no text editor instance available, for example,
if the command was run while the user was in the settings menu.

let selection = editor.getSelectedText()

Calling getSelectedText gives us access to text selected by the user. If
no text is currently selected, the function returns an empty string.

let reversed = selection.split('').reverse().join('')
editor.insertText(reversed)

Our selected text is reversed using JavaScript String methods
. Finally, we call insertText to replace the selected text with the
reversed counterpart. You can learn more about the different TextEditor methods
available by reading the Atom API documentation.

Exploring the starter package

Now that we've made our first code change, let's take a closer look at how an
Atom package is organized by exploring the starter code.

The main file

The main file is the entry-point to an Atom package. Atom knows where to find the
main file from an entry in package.json:

"main": "./lib/sourcefetch",

The file exports an object with lifecycle functions which Atom calls on
certain events.

  • activate is called when the package is initially loaded by Atom.
    This function is used to initialize objects such as user interface
    elements needed by the package, and to subscribe handler functions to package
    commands.
  • deactivate is called when the package is deactivated, for example, when
    the editor is closed or refreshed by the user.
  • serialize is called by Atom to allow you to save the state of the package
    between uses. The returned value is passed as an argument to activate when
    the package is next loaded by Atom.

We are going to rename our package command to fetch, and remove user interface
elements we won't be using. Update the file to match the version below:

'use babel';

import { CompositeDisposable } from 'atom'

export default {

  subscriptions: null,

  activate() {
    this.subscriptions = new CompositeDisposable()

    this.subscriptions.add(atom.commands.add('atom-workspace', {
      'sourcefetch:fetch': () => this.fetch()
    }))
  },

  deactivate() {
    this.subscriptions.dispose()
  },

  fetch() {
    let editor
    if (editor = atom.workspace.getActiveTextEditor()) {
      let selection = editor.getSelectedText()
      selection = selection.split('').reverse().join('')
      editor.insertText(selection)
    }
  }
};

Activation commands

To improve performance, Atom packages can be lazy loading. We can tell Atom to
load our package only when certain commands are run by the user. These commands
are called activation commands and are defined in package.json:

"activationCommands": {
  "atom-workspace": "sourcefetch:toggle"
},

Update this entry to make fetch an activation command.

"activationCommands": {
  "atom-workspace": "sourcefetch:fetch"
},

Some packages, such as those which modify Atom's appearance need to be loaded
on startup. In those cases, activationCommands can be omitted entirely.

Triggering commands

Menu items

JSON files inside the menus folder specify which menu items are created for
our package. Let's take a look at menus/sourcefetch.json:

"context-menu": {
  "atom-text-editor": [
    {
      "label": "Toggle sourcefetch",
      "command": "sourcefetch:toggle"
    }
  ]
},

The context-menu object lets us define new items in the right-click menu. Each
item is defined by a label to be displayed in the menu and a command to run when
the item is clicked.

"context-menu": {
  "atom-text-editor": [
    {
      "label": "Fetch code",
      "command": "sourcefetch:fetch"
    }
  ]
},

The menu object in the same file defines custom application menu items created
for the package. We're going to rename this entry as well:

"menu": [
  {
    "label": "Packages",
    "submenu": [
      {
        "label": "sourcefetch",
        "submenu": [
          {
            "label": "Fetch code",
            "command": "sourcefetch:fetch"
          }
        ]
      }
    ]
  }
]

Keyboard shortcuts

Commands can also be triggered with keyboard shortcuts, defined with JSON files
in the keymaps directory:

{
  "atom-workspace": {
    "ctrl-alt-o": "sourcefetch:toggle"
  }
}

The above lets package users call toggle with Ctrl+Alt+O
on Windows/Linux or Cmd+Alt+O on MacOS.

Rename the referenced command to fetch:

"ctrl-alt-o": "sourcefetch:fetch"

Reload Atom by running the Window: Reload command. You should see that the
application and right-click menus are updated, and the reverse functionality
should work as before.

See all code changes for this step in the sourcefetch tutorial repository.

Using NodeJS modules

Now that we've made our first code change and learned about Atom package structure,
let's introduce our first dependency—a module from
Node Package Manager (npm). We will use the request
module to make HTTP requests and download the HTML of a website. This functionality
will be needed later, to scrape StackOverflow pages.

Installing dependencies

Open your command line application, navigate to your package root directory
and run:

npm install --save request@2.73.0
apm install

These commands add the request Node module to our dependencies list and
install the module into the node_modules directory. You should see a new entry
in package.json. The @ symbol tells npm to install
the specific version we will be using for this tutorial. Running apm install
lets Atom know to use our newly installed module.

"dependencies": {
  "request": "^2.73.0"
}

Downloading and logging HTML to the Developer Console

Import request into our main file by adding an import statement to the top
of lib/sourcefetch.js:

import { CompositeDisposable } from 'atom'
import request from 'request'

Now, add a new function, download to the module's exports, below fetch:

export default {  

  /* subscriptions, activate(), deactivate() */

  fetch() {
    ...
  },

  download(url) {
    request(url, (error, response, body) => {
      if (!error && response.statusCode == 200) {
        console.log(body)
      }
    })
  }
}

This function uses request to download the contents of a web page and logs
the output to the Developer Console. When the HTTP request completes, our
callback function
will be called with the response as an argument.

The final step is to update fetch so that it calls download:

fetch() {
  let editor
  if (editor = atom.workspace.getActiveTextEditor()) {
    let selection = editor.getSelectedText()
    this.download(selection)
  }
},

Instead of reversing the selected text, fetch now treats the selection as a
URL, passing it to download. Let's see our changes in action:

  • Reload Atom by running the Window: Reload command.
  • Open the Developer Tools. To do this, navigate to
    View > Developer > Toggle Developer Tools in the menu.
  • Create a new file, navigate to File > New.
  • Enter and select a URL, for example, http://www.atom.io.
  • Run our package command in any of the three ways previously described:

Downloading and logging HTML

Developer Tools make it easy to debug Atom packages. Any console.log statement
will print to the interactive console, and you can use the Elements tab to
explore the visual structure of the whole applicatio—which is just an HTML
Document Object Model (DOM).

See all code changes for this step in the sourcefetch tutorial repository.

Using Promises to insert downloaded HTML into the editor

Ideally, we would like our download function to return the HTML as a string
instead of just printing page contents into the console. Returning body won't work,
however, since we get access to body inside of the callback rather than
download itself.

We will solve this problem by returning a Promise
rather than the value itself. Let's change download to return a Promise:

download(url) {
  return new Promise((resolve, reject) => {
    request(url, (error, response, body) => {
      if (!error && response.statusCode == 200) {
        resolve(body)
      } else {
        reject({
          reason: 'Unable to download page'
        })
      }
    })
  })
}

Promises allow us to return values obtained asynchronously by wrapping asynchronous
logic in a function that provides two callbacks— resolve for returning a
value successfully, and reject for notifying the caller of an error. We call
reject if an error is returned by request, and resolve the HTML otherwise.

Let's change fetch to work with the Promise returned by download:

fetch() {
  let editor
  if (editor = atom.workspace.getActiveTextEditor()) {
    let selection = editor.getSelectedText()
    this.download(selection).then((html) => {
      editor.insertText(html)
    }).catch((error) => {
      atom.notifications.addWarning(error.reason)
    })
  }
},

In our new version of fetch, we get access to the HTML by calling
then on the Promise returned by download. This lets us insert the HTML into
the editor. We also accept and handle any errors returned by calling catch.
We handle errors by displaying a warning notification using the
Atom Notification API.

Let's see what changed. Reload Atom and run the package command on a selected URL:

Downloading and Inserting HTML

If the command is run on an invalid URL, a warning notification will be displayed:

Trying to Download an Invalid URL

See all code changes for this step in the sourcefetch tutorial repository.

Building a scraper to extract code snippets from StackOverflow HTML

The next step involves extracting code snippets from the HTML of a
StackOverflow page we obtained in the previous step.
In particular, we're interested in code from the accepted answer—an answer
chosen to be correct by the question author. We can greatly simplify our
package implementation by assuming any such answer to be relevant and correct.

Constructing a query using jQuery and Chrome Developer Tools

This section assumes you are using the Chrome web
browser. You may be able to follow along using another browser, but instructions
may change.

Let's take a look at a typical StackOverflow page that contains an accepted
answer with a code snippet. We are going to explore the HTML using Chrome
Developer Tools:

  • Open Chrome and navigate to any StackOverflow page containing an accepted
    answer with code, such as this hello world example in Python or this question
    about reading text from a file in C.
  • Scroll down to the accepted answer and highlight a section of the code snippet.
  • Right click and select Inspect
  • Inspect the location of the code snippet within the HTML code using the Elements
    browser.

Note that the document has the following structure:

<div class="accepted-answer">
  ...
    ...
      <pre>
        <code>
          ...snippet elements...
        </code>
      </pre>
    ...
  ...
</div>
  • The accepted answer is denoted by a div with class accepted-answer
  • Block code snippets are located inside a pre element
  • Elements that render the code snippet itself sit inside a code tag

Exploring the DOM using Chrome Developer Tools

Now let's construct a jQuery statement for extracting code snippets:

  • Click the Console tab within Developer Tools to access the JavaScript console.
  • Type $('div.accepted-answer pre code').text() into the console and press Enter.

You should see the accepted answer code snippets printed out in the console.
The code we just ran uses a special $ function provided by jQuery. $
accepts a query string to select and return certain HTML elements from the
website. Let's take a look at how this code works by considering a couple of
intermediate example queries:

$('div.accepted-answer')
> [<div id="answer-1077349" class="answer accepted-answer" ... ></div>]

The above query will match all <div> elements that contain the class
accepted-answer, in our case - just one div.

$('div.accepted-answer pre code')
> [<code>...</code>]

Building upon the previous, this query will match any <code> element that
is inside a <pre> element contained within the previously matched <div>.

$('div.accepted-answer pre code').text()
> "print("Hello World!")"

The text function extracts and concatenates all text from the list of elements
that would otherwise be returned by the previous query. This also strips out elements
used for syntax highlighting purposes from the code.

Introducing Cheerio

Our next step involves using the query we created to implement a scraping
function using Cheerio, a jQuery
implementation for server-side applications.

Install Cheerio

  • Open your command line application, navigate to your package root directory
    and run:
npm install --save cheerio@0.20.0
apm install

Implement the scraping function

  • Add an import statement for cheerio in lib/sourcefetch.js:
import { CompositeDisposable } from 'atom'
import request from 'request'
import cheerio from 'cheerio'
  • Now create a new function that extracts code snippets given
    StackOverflow HTML, called scrape:
fetch() {
  ...
},

scrape(html) {
  $ = cheerio.load(html)
  return $('div.accepted-answer pre code').text()
},

download(url) {
  ...
}
  • Finally, let's change fetch to pass downloaded HTML to scrape instead
    of inserting it into the editor:
fetch() {
  let editor
  let self = this

  if (editor = atom.workspace.getActiveTextEditor()) {
    let selection = editor.getSelectedText()
    this.download(selection).then((html) => {
      let answer = self.scrape(html)
      if (answer === '') {
        atom.notifications.addWarning('No answer found :(')
      } else {
        editor.insertText(answer)
      }
    }).catch((error) => {
      console.log(error)
      atom.notifications.addWarning(error.reason)
    })
  }
},

Our scraping function is implemented in just two lines because cheerio does
all of the work for us! We create a $ function by calling load with our
HTML string, and use this function to run our jQuery statement and return the
results. You can explore the entire Cheerio API in their
developer documentation.

Testing the updated package

  • Reload Atom and run soucefetch:fetch on a selected StackOverflow URL to
    see the progress so far.

If we run the command on a page with an accepted answer, it will be inserted
into the editor:

Scraping a StackOverflow Page

If we run the command on a page with no accepted answer, a warning
notification will be displayed instead:

Running the command when there are no accepted answers

Our new iteration of fetch gives us the code snippet within a StackOverflow page
instead of the entire HTML contents. Note that our updated fetch function
checks for the absence of an answer and displays a notification to alert the user.

See all code changes for this step in the sourcefetch tutorial repository.

Implementing Google search to find relevant StackOverflow URLs

Now that we can turn StackOverflow URLs into code snippets, let's implement
our final function, search, which will return a relevant URL given the
description of a snippet, such as "hello world" or "quicksort". We will be
using Google search via the unofficial google npm module, which allows us to
search programmatically.

Installing the Google npm module

  • Install google by opening your command line application at the package root
    directory, and run:
npm install --save google@2.0.0
apm install

Importing and configuring the module

Add an import statement for google at the top of lib/sourcefetch.js:

import google from "google"

We will configure the library to limit the number of results returned
during search. Add the following line below the import statement to limit
returned results to just the top one.

google.resultsPerPage = 1

Implementing the search function

Next, let's implement our search function itself:

fetch() {
  ...
},

search(query, language) {
  return new Promise((resolve, reject) => {
    let searchString = `${query} in ${language} site:stackoverflow.com`

    google(searchString, (err, res) => {
      if (err) {
        reject({
          reason: 'A search error has occured :('
        })
      } else if (res.links.length === 0) {
        reject({
          reason: 'No results found :('
        })
      } else {
        resolve(res.links[0].href)
      }
    })
  })
},

scrape() {
  ...
}

The code above searches Google for a StackOverflow page relevant to the given
query and programming language, returning the URL of the top result. Let's take
a look at how it works:

let searchString = `${query} in ${language} site:stackoverflow.com`

We construct the search string using the query entered by the user and
the current language selected. For example, if the user types
"hello world" while editing Python, the query will be hello world in python site:stackoverflow.com. The final part of the string
is a filter provided by Google Search that lets us limit results
to those linked to StackOverflow.

google(searchString, (err, res) => {
  if (err) {
    reject({
      reason: 'A search error has occured :('
    })
  } else if (res.links.length === 0) {
    reject({
      reason: 'No results found :('
    })
  } else {
    resolve(res.links[0].href)
  }
})

We wrap the call to google inside a Promise so that we can return our URL
asynchronously. We propagate any errors returned by the library, also returning
an error when there are no results available. We resolve the URL of
the top result otherwise.

Updating fetch to use search

Our final step is to update fetch to use search:

fetch() {
  let editor
  let self = this

  if (editor = atom.workspace.getActiveTextEditor()) {
    let query = editor.getSelectedText()
    let language = editor.getGrammar().name

    self.search(query, language).then((url) => {
      atom.notifications.addSuccess('Found google results!')
      return self.download(url)
    }).then((html) => {
      let answer = self.scrape(html)
      if (answer === '') {
        atom.notifications.addWarning('No answer found :(')
      } else {
        atom.notifications.addSuccess('Found snippet!')
        editor.insertText(answer)
      }
    }).catch((error) => {
      atom.notifications.addWarning(error.reason)
    })
  }
}

Let's take a look at what changed:

  • Our selected text is now treated as the query entered by the user.
  • We obtain the language of the current editor tab using the
    TextEditor API
  • We call search to obtain a URL, which we access by calling then on the
    resulting Promise
  • Instead of calling then on the Promise returned by download, we instead
    return the Promise itself and chain another then call onto the original call.
    This helps us avoid callback hell

See all code changes for this step in the sourcefetch tutorial repository.

Testing the final plugin

And we're done! See the final plugin in action by reloading Atom and running
our package command on a problem description, and don't forget to select a language
in the bottom-right corner.

Final Plugin Demo

Next steps

Now that you know the basics of hacking Atom, feel free to practice what you've learned by forking the sourcefetch repository and adding your own features.

Back to school: Join the GitHub Education Community

Just in time for back-to-school preparations, we welcome you to join a new forum for technology education: education.github.community

GitHub Education Community

This supportive environment will allow educators to collaborate with each other, and with GitHubbers directly.

  • Discuss current trends in technology education with your peers from around the world. Share your opinions and successes.
  • Suggest improvements to GitHub Classroom, our new open source tool for managing your assignments on GitHub.
  • Let us know what you think of our upcoming lesson plans for teaching GitHub in the classroom, or share lesson plans of your own.
  • Discover new ways to utilize valuable tools from the GitHub Student Developer Pack in your curriculum.

New to GitHub? This is a great opportunity learn by interacting directly with teachers and learn from their experience. Community members are also invited to request a swag bag full of educational materials and goodies for your students.

Getting started is easy, head over and introduce yourself.

GitHub Campus Experts - Technology leadership at your school

The student developer community is thriving thanks to hardworking student leaders like Josh Simpson. They organize tech talks, write tutorials, plan meetups, teach workshops, host office hours, produce hackathons, and more.

To encourage more students to become stewards of their campus technology communities we've created the GitHub Campus Experts program.

GitHub Campus Experts Logo

Starting today, we're accepting Campus Expert applications from students. Successful applicants will receive training in public speaking, community leadership, technical writing, and software development from GitHub. As part of a network of technology leaders at universities around the world participants receive training and mentorship from GitHub employees, opportunities to participate in exclusive events, and support to help grow the local student developer community.

Becoming a Campus Expert is a great way to amplify your efforts as a student leader, get training and mentorship with the latest technologies, and gain experience relevant to a career in developer relations.

Learn more and apply to become a GitHub Campus Expert for your school.

Supporting the student hacker community

To stimulate the growth and show our support of the student hacker community, we've partnered with Major League Hacking (MLH) to provide each new member hackathon with a $1,000 grant and one sponsored ticket to Hackcon, the conference for hackathon organizers.

GitHub <3 Students

Hackathons are amazing social gatherings where students interested in technology can come together to learn, build, and share brand new creations over the course of a weekend.

For a small, first-time hackathon, $1,000 can make or break the event budget. For organizers, having the opportunity to meet the people behind the most successful student hackathons at Hackcon is invaluable to the continued success of their events.

As the official student hackathon league, MLH provides member events with organizational support including mentorship, hardware labs, and connections to technology companies. Last week, they announced their seed funding and B-Corp certification to reaffirm their mission-driven focus on empowering student hackers. Together, GitHub and MLH have supported a community of 50,000 students at over 150 global events in the last year.

We're proud to be part of the rapidly growing movement of hackathons organized for students by students. GitHubbers regularly participate in student hackathons as mentors, guest speakers, and judges while the GitHub Student Developer Pack gives student hackers free access to the best developer tools to use for their hacks.

To organize a hackathon at your school with support from GitHub start an MLH member hackathon in the 2016-2017 season.