Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Teaching Programming Online

Pamela Fox
October 18, 2013

Teaching Programming Online

A talk about how Khan Academy teaches programming online, thanks to App Engine, HTML5, and open source.

Pamela Fox

October 18, 2013
Tweet

More Decks by Pamela Fox

Other Decks in Technology

Transcript

  1. So many options Languages Uses Java Python C++ Haskell JavaScript

    Ruby Scheme Games Animation Hardware Robotics Data Science Simulation Mobile Websites Lua Friday, October 18, 13
  2. So many options Languages Uses Java Python C++ Haskell JavaScript

    Ruby Scheme Games Animation Hardware Robotics Data Science Simulation Mobile Websites Lua Friday, October 18, 13
  3. JSHint var myName = “spaghetti if (i == 0) {

    } var i = 2; if (i == 0) { } errors warnings best practices Friday, October 18, 13
  4. Infinite Loop Checker var i = 0; while(i < 10)

    { ellipse(i, i, 30, 30); } Web Worker Friday, October 18, 13
  5. Our approach: “talk-throughs” Uses same environment they program in Making

    passive instruction interactive! https://www.khanacademy.org/cs/programming/drawing-basics/p/intro-to-drawing Friday, October 18, 13
  6. Playing talk-throughs SoundManager2.js commands = [ {"key": "\n", "time": 14124},

    {"key": "\n", "time": 14260}, {"key": "r", "time": 14676}, {"key": "e", "time": 14764}, {"key": "c", "time": 15036}, {"key": "t", "time": 15548},...] <audio> or <object> var player = soundManager.createSound({ url: revision.getMp3Url(), whileplaying: function() { updateTimeLeft(Record.currentTime()); Record.trigger("playUpdate"); } }); Friday, October 18, 13
  7. Recording audio var multirecorder = new MultiRecorder(); multirecorder.startRecording(); https://github.com/Khan/MultiRecorderJS/blob/master/multirecorder.js rightBuffer.push(stream[0]);

    leftBuffer.push(stream[1]); getUserMedia() new Worker() multirecorder.stopRecording(); getInterleaved(); encodeWAV(); Friday, October 18, 13
  8. Our approach: coding challenges Structured yet flexible. More than one

    way to code the solution. Friday, October 18, 13
  9. StructuredJS http://khan.github.io/structuredjs/index.html var $numVar = $numVal; if ($numVar > 0)

    { rect($x, $y, $w, $h); } var theNumber = 10; fill(255, 255, 255); if (theNumber > 0) { rect(10, 10, 30, 40); } if (theNumber < 0) { rect(10, 50, 30, 40); } structure: user code: it’s a match! Friday, October 18, 13
  10. staticTest staticTest(“Add the ifs!”, function() { var descrip = “Now

    add an if to check if the number is positive.”; var pattern = function() { var $numVar = $numVal; if ($numVar > 0) { rect($x, $y, $w, $h); } }; result = match(pattern); if (passes(result)) { var goodX = structure(pattern, inRange(“$x”, 10, 20)); if (!matches(goodX)) { result = fail(“Hm, does your rect start on the side?”); } } assertMatch(result, descrip, displayP); }); Friday, October 18, 13
  11. ...Not quite that simple, though! Most challenge tests are hundreds

    of lines long. Most steps have 10-20 helpful messages. https://www.khanacademy.org/cs/challenge-exploding-sun/2050946856 Friday, October 18, 13
  12. Wilson Voting Algorithm, GAE’d def wilson_confidence(upvotes_name, downvotes_name, score): """Lower bound

    of Wilson score 90% confidence interval. This is the algorithm Reddit uses to sort comments. You should not use this if downvotes are disallowed - it is only useful in the presence of both upvotes and downvotes because its ranking is based on an estimate of the ratio of upvotes to downvotes. See http://www.evanmiller.org/how-not-to-sort-by-average-rating.html """ upvotes = getattr(score, upvotes_name) downvotes = getattr(score, downvotes_name) if upvotes == 0: return -downvotes elif upvotes == downvotes: return 0 n = upvotes + downvotes z = 1.64485 # 90% confidence z-score phat = float(upvotes) / n # p-hat return ((phat + z * z / (2 * n) - z * math.sqrt((phat * (1 - phat) + z * z / (4 * n)) / n)) / (1 + z * z / n)) class TimeIndependentScoreProperty(ndb.ComputedProperty): def __init__(self, upvotes_name="upvotes", downvotes_name="downvotes", **kwargs): super(TimeIndependentScoreProperty, self).__init__( functools.partial(wilson_confidence, upvotes_name, downvotes_name), **kwargs) Friday, October 18, 13
  13. Reddit Voting Algorithm, GAE’d def time_dependent(decay_seconds, upvotes_name, downvotes_name, created_name, score):

    """Ranking based on both age and quality. This is the algorithm Reddit uses to sort stories. We want there to be churn, a constant stream of new programs hitting the hot page, so this algorithm takes into account both the score of the scratchpad and the age. See http://amix.dk/blog/post/19588 """ s = getattr(score, upvotes_name) - getattr(score, downvotes_name) # Weight votes logarithmically - initial votes are worth a ton order = math.log(max(abs(s), 1), 10) sign = 1 if s > 0 else -1 if s < 0 else 0 # Seconds since this algorithm's start date date = getattr(score, created_name) or datetime.datetime.now() seconds = epoch_seconds(date) - 1349108492 return round(order + sign * seconds / decay_seconds, 7) class TimeDependentScoreProperty(ndb.ComputedProperty): def __init__(self, decay_seconds, upvotes_name="upvotes", downvotes_name="downvotes", created_name="created", **kwargs): super(TimeDependentScoreProperty, self).__init__(functools.partial( time_dependent, decay_seconds, upvotes_name, downvotes_name, created_name), **kwargs) Friday, October 18, 13