The most important lesson the Ivy League teaches

Let’s face it — if you were sufficiently academically successful in high school to be admitted to an Ivy League university, you were probably a big fish in a small pond. You were one of the most diligent students in your high school. Maybe you were valedictorian of your graduating class, so you got to give a speech at graduation. Either way, everyone knew who you were, and you were able to succeed pretty easily.

You probably got a bit cocky. It’s alright to admit it. I, too, was very cocky in high school.

However, freshman year at an Ivy League school will crush your spirits. It’s not that school is guaranteed to be sufficiently challenging (although it certainly can be, as my grade in ACCT 102 will confirm). It’s that you’re suddenly a small fish in a big pond. Everyone is as bright and hard-working as you are. One-third of your class was a valedictorian. There are more, better students. It can be easy to feel insignificant, easy to feel average.

The Ivy League pushes you to work harder than you ever have, trying to balance a rigorous courseload with extracurriculars that you are legitimately passionate about. Fortunately, it lasts. When you take that work ethic and drive back into the real world for your first summer internship, you feel like a high school valedictorian again. That’s because the perseverance and dedication that the Ivy League instilled in you moves you to do your work exceptionally. A commonly-heard opinion at Penn is that employment is much easier than school.

That’s not the most important lesson the Ivy League teaches, however. The most important lesson is to be modest. You were once cocky, and you were shown the error of your ways via the artificial bubble of overachieving that is the Ivy League. But when you leave that bubble, you finally realize what others knew about you all along: you are exceptional. You had to be exceptional to get to where you are today. And because you already fell from grace, because you now know what it’s like to not be the best — you become humbled. You don’t let your success get to your head. And for this, you’re a much better person.

EPCOT Center, 2014

I’m a massive thrill-seeker. I dominated Cedar Point when I was 12, and I did each coaster with my hands up the entire ride.

Thus, it’s a bit unusual that I love EPCOT [1] so much. Disney parks aren’t known for having especially thrilling rides. EPCOT itself is known more for its blend of science and global culture than its adrenaline rushes. To be fair, I’m strongly interested in both topics, which I suppose makes the park relevant to me. I think another factor is simply how freaking magical the Disney experience is.

Either way, I’ve been to EPCOT a few times in recent memory — spring 2005, spring 2007, and summer 2009. My family went today, New Year’s Day 2014. Here are my thoughts, presented in chronological order.

Entering

Oh God, New Year’s Day was a terrific day to go to a theme park, given that you’re good at the dodging asteroids part of Mission: Space. You’ll sure as hell be dodging tourists that don’t know how to walk on a sidewalk without stopping at arbitrary points in time.

Test Track

As a traditionalist, I figured I’d really hate the new theme and Chevrolet sponsorship. However, The Imagineers did something right in that the new emphasis on designing your car really helped smooth the queue out. More time spent in the pre-show translates to less time aimlessly waiting in line (pay attention, Soarin’). With that being said, the part of the queue that you do have to wait in is now boring and uninspired. There was something great about waiting for an hour with your friends and family seeing how car testing works. Now, there’s really not much to look at or do, up until the car design point.

The new theme itself reminded me of the whole flat design fad. I’ll admit that it was refreshing, but why did Disney have to go ahead and kill a perfectly good queue? Not to mention that Chevrolet is really kicking ass, taking names, and chewing bubblegum with their Volt, the ultimate disruptive innovator of motor vehicles. Oh, wait…

The ride itself is somewhat ruined. That’s because Disney took immutable track and tried to apply a new ride experience. As a result, several things are completely wrong with the new Test Track:

1. No more German and Belgian blocks after the climb. You just drop for no reason.

2. The old ABS section is completely pointless now. You just swerve for no reason on the first attempt, and you don’t swerve for no reason on the second attempt. Apparently there was supposed to be snow/ice on the road…couldn’t tell.

3. The heat, cold, and corrosion tests were replaced by arbitrary scans for eco-efficiency and aerodynamic efficiency. Way lame.

4. No more almost crashing into the wall.

I’d continue to hop on this ride in the future because it means so much to me, but I’m really disappointed with Disney’s execution. I think that the opportunity to design your own car and see how it handles on the track is great, but Disney changed too much of the actual ride experience. There’s now a disconnect between what the car is doing and what the ride is trying to tell you that it’s doing.

Mission: Space

Still my favorite ride at any Disney park. Turns out that my two younger sisters can’t hang and didn’t feel amazing after the ride. I’ve done this three consecutive times in the past, but when you’re with a family of varying ages and ride preferences, however, sacrifices are made. Time to move on.

On the bright side, lines were decently short all day for this bad boy. I’m going to attribute that partially to EPCOT simply not attracting thrill-seekers on New Year’s Day and partially to word-of-mouth that this ride is intense.

Bonus for myself: I finally put together two and two — Ken Mattingly from Apollo 13 (Gary Sinise) plays the mission commander (or whatever) in Mission: Space. Nice touch.

Soarin’

Soarin’ is pure Disney magic. You will truly feel immersed in the experience — given that you can manage to avoid looking down at the ground, up at everyone else’s feet, or to the side to see the other ride vehicles.

Of course, the whole line situation for Soarin’ is FUBAR. Nothing like an eight-across free-for-all that speeds along at about four rows of people every five minutes. There are supposed to be interactive games on the right-hand wall. Not on New Year’s Day, evidently. Hopefully one of the Imagineers set a New Year’s resolution to fix the Soarin’ queue, God forbid our family was forced to actually talk to each other for 90 minutes. [2] [3] Waitin’ for Soarin’ is torture.

The Fastpass situation is also FUBAR. Besides how quickly these things run out, the cast members really favor letting Fastpass holders into the pre-show area. Listen, if standby is going to have a queue listed at 80 minutes, then Fastpass should probably still have a 10 to 15-minute queue, not a walk-on experience. The current balance pushed us to a 95-minute wait despite it being listed at 80 minutes. And to think that the queue was listed at three hours by the time we got off the ride!

I guess Soarin’ has the opposite issue that Test Track has.

Ellen’s Energy Adventure

I’ve got a sweet spot for this one. Nothing’s changed, besides the addition of the man talking on his cell phone during the entire pre-show period. That was part of the ride, right?

Nine Dragons

The Chinese-American restaurant in the China pavilion of World Showcase. Overpriced by normal standards, perfectly priced by elasticity of demand. Disney, man; they know their microeconomics.

Maelstrom

Highlight of the ride was my seventeen-year-old sister freaking out and curling herself into the fetal position on the drop — not because she was scared of the speed, but because she didn’t want to get wet. Don’t worry, no splash on this one. No real thrill, either. This was a lot more fun when I was 9.

Spaceship Earth

Bring back Jeremy Irons. His voice was serious, captivating, and romantic. You wanted to learn about the history and future of communication. The new narrator, whose name I really don’t care to learn because of what a disservice she’s done to the ride, is horrible. I held this position in summer 2009, about a year after Spaceship Earth re-opened with this retrogression of a renovation, and I maintain it today. The interactive screens and stupid and detract from the beauty of the star scene as you slowly climb downhill backwards. Instead of holding a captivated gaze, you’re making stupid choices about what you wanted the future to be. [4] [5]

The guy who took a flash photo from his iPhone of the Earth at the climax of the freaking ride was a real winner, too.

Overall

Hey Disney, stop making bad changes and please make some needed changes. Did you forget that what makes Disney Disney is that the entire ride experience is supposed to be magical, not just the ride but also the pavilion, queue, and post-show? The only magical part of Soarin’, save for the ride itself, was hearing this song from the Apollo 13 soundtrack; the fact that Universal gave Disney the rights to use a song from one of their films is pretty magical, especially given the grueling bidding wars on the Harry Potter franchise rights.

And believe it or not, I actually enjoyed myself today. Can’t wait to go back again!

Footnotes

[1] Yes, I’m aware that Disney changed the park’s name from EPCOT Center to Epcot awhile back. If you haven’t noticed, I’m old-fashioned.

[2] Just kidding, we figured out that Disney now has complimentary wireless Internet in their parks and instead just dicked around on Words with Friends / Instagram / Snapchat / Hacker News.

[3] And of course, this is tongue-in-cheek. I love my family, and we spent a lot of quality time together on this vacation — which is increasingly rare now that two of us are in college. Hi, Mom!

[4] It was worth a couple of chuckles to mark down that my sister and I were from rural Siberia, however. I can only hope that we somehow will affect a few dollars of Disney’s marketing efforts as a result of providing them with that datum.

[5] And yes, I realize that the ride is more popular than ever due to the new Siemens sponsorship and overhaul. It’s still ruined to me.

Programmatic Snapchat

Background

A few friends and I rocked the Blackberry Curve back in 2009. A user could attach up to ten recipients to a Curve text message. A user could also hit the resend option while a text message was sending, which would effectively send it twice. My friends and I, being devious, learned that you could attach the same person ten times to a text message, which would obviously send the same message to them ten times. Therefore, given a bit of patience, we could effectively “text bomb” our friends by hitting “resend” over and over, sending them hundreds of identical text messages. On newer phones, this was a minor nuisance; the Curve could handle all of those incoming text messages. However, older phones couldn’t handle this barrage, so the text bomb would incapacitate the phone for however long it took to process and receive all of those texts.

At the time, I had no idea how to program anything, so I had no problem doing that sort of manual labor just to annoy a friend.

Last night, an acquaintance asked me to help her send a lot of Snaps at once. She wanted to become the top Snapchat friend of a friend of hers, and she cited my computer science and programming knowledge as to why she was asking me. I immediately abstracted this problem as in the same category as the “text bomb” — or really, a denial of service attack — and knew exactly what to do. [1]

Snapchat API

Snapchat doesn’t have a public API, but people have reverse-engineered their private API. There are a ton of Github repositories containing working API code; I used snapchat-python.

The script

The snapchat-python repo contains concise and relevant example code, making my hunt a lot easier. All I wanted to do was to wrap the upload and send code in a for loop. Here’s what I did:

s = Snapchat()
s.login('USERNAME', 'PASSWORD')
for i in range(0, 100):
    m = s.upload(Snapchat.MEDIA_IMAGE, 'path/to/file.jpg')
    s.send(m, 'RECIPIENT_USERNAME')

This code should output True each time it successfully sends a Snap. I was able to fire off a Snap roughly once per second.

Did it work? Well, I logged back into my own account and started doing this to a couple of my friends that are fine with pranking. [2] One of them sent me this screenshot.

What happens to the recipient?

This Snapchat bomb truly incapacitates someone’s phone, mostly because of all the notifications that the phone had to process and output. Recipients simply can’t use their phones while still receiving Snaps.

Experimenting

First, I was curious if Snapchat supported GIFs. I loaded up a GIF and fired but one off to a friend. He told me he only saw the first frame of the GIF. GIFs are a no-go.

I was then curious if there was a bottleneck in my code from always re-uploading the image to Snapchat. What if I removed the upload API call out from the for loop? Well, this doesn’t work either; you need to upload a fresh image every time you want to send a Snap. The code still outputs True 100 times, but it only sends the Snap once.

Terms of use

This behavior is absolutely against Snapchat’s terms of use. According to the Prohibited Activities section, I agree that I will not:

Use the Services in any manner that could interfere with, disrupt, negatively affect or inhibit other users from fully enjoying the Services
Send any unsolicited or unauthorized advertising, spam, solicitations or promotional materials

and

Engage in any harassing, intimidating, predatory or stalking conduct

Reflection

It was laughably easy to use the private Snapchat API to game the friend ranking system and to annoy my friends. Snapchat can avoid this behavior by using rate limiting on specific sender-recipient relationships. I should be curbed from spamming a specific friend, but if I want to send a single Snap to 100 different friends, I shouldn’t hit any sort of limit.

It is important to implement a rate limiting scheme that will never have false positives; someone sending Snaps manually should never encounter this limit. Perhaps a burst algorithm would be best, one that detects when a user has sent several Snaps at a rate too fast to be possible manually.

A more serious consequence of Snapchat’s private API being so easy to access programmatically is that it is simple to impersonate somebody else over Snapchat. I’ve heard of people using Snapchat as a way to affirm that someone they’ve been talking to on some sort of Internet dating website (think Plenty of Fish or Tinder) is real, not frauding. These Snapchat libraries permit easy frauding, so the mere existence of a Snapchat should not be interpreted in this way.

Footnotes

[1] How did I actually Snapchat bomb her friend from her account? She gave me her username and changed her password to something benign. This does not violate Snapchat’s terms of use.

[2] In case anyone was curious, I was sending image memes. A joke is funnier the 100th time it’s told, right?

On cheat days

Bodybuilders adhere to a strict diet in order to make as many muscular gains as possible. However, once every two weeks, many amateur / recreational bodybuilders reward themselves with a cheat day. They can skim a bit on their diet on their cheat day. That’s not to say that they eat an entire package of Oreos, but they might have a more fattening breakfast or dessert, or they might hit the bars with some friends.

However, the best bodybuilders do not use cheat days. In a world where one must take every inch they can get, a world where everything always counts, the hyper-competitive bodybuilding world — there is no room for a cheat day.

A lot of people rationalize laziness via cheat days. Didn’t practice my instrument? It’s okay, I’ll take a cheat day. Got lazy and didn’t go for a run? Cheat day. Didn’t brush my teeth this morning? It’s okay, one day won’t do any damage.

To be clear, vacations are not cheat days. Not everyone is Jiro. Vacations are planned activities. Likewise, emergencies aren’t cheat days. Cheat days are unjustifiable excuses. Cheat days are laziness.

Unfortunately, cheat days become addictive because laziness is the easy way out. Before you know it, one day a week of not studying for your programming interviews becomes two days becomes three days, because you had a long day at work and you’re too hungry to focus and your bed is so comfortable.

There are two ways to combat cheat days. The first is to adhere to a very strict schedule with sheer willpower. This is important for those menial tasks that you don’t want to do but really need to be done: mowing the lawn, doing the laundry, brushing your teeth. It’s incredibly hard to be passionate about doing the laundry, so one must brute force these tasks.

The other way is to be 100% passionate about the activities you are doing.

Paul Graham often writes that start-up founders discover themselves completely immersed in their company. It’s what they think about all day, every day. This makes complete sense; it’s hard not to take pride in your own labor. Start-up founders don’t take cheat days.

Since it’s not as easy to take complete ownership in other areas of life, passion is a must. When I was in high school, I had the lethal combination of the innate desire to learn as much as possible, along with the (very stupid) ambition of getting more 5s on my AP exams than anyone else. I studied for my AP exams every day starting in March. My girlfriend wanted to come over? Cool. We studied together until I felt confident about the material I had reviewed that day.

I knew I was completely passionate about self-pedagogy because I never had an excuse not to study.

Likewise, as my summer internship wraps up, I’m beginning to review my interview fundamentals again. It can sometimes be hard to convince myself to study after an 11-hour work day and a 7-mile bike ride, but I know it’s the right thing to do for me. I can’t and I don’t make excuses not to prepare.

If you find yourself making excuses for cheat days, perhaps you are participating in an activity that is not right for you.

Chrome extensions for Facebook — detecting new pages

I wrote a Chrome extension earlier this week to hide Buzzfeed links from my news feed, my groups, and others’ profiles. However, I was having issues detecting when a user had changed pages so I could re-fire my script onto the new DOM. That’s because Facebook updates their pages with AJAX.

Chrome has a tabs library that one can use to check for when a tab’s URL has changed, onUpdated. However, Facebook updates the browser URL before the AJAX call completes. We’ll have to do this another way.

After poking around the Chrome console, I found that Facebook’s AJAX calls to a new page all use the GET parameter ajaxpipe=1 in the URL. So, all I had to do was snipe the HTTP request and re-fire my script on success. It turns out that Chrome’s webRequest library has a great onCompleted library to help us out here. Here’s the code I ended up writing:

chrome.webRequest.onCompleted.addListener(function(details) {
    var url = document.createElement('a');
    url.href = details.url;
    if (url.search && url.search.indexOf('ajaxpipe=1') !== -1) {
        console.log('New page via AJAX.');
        chrome.tabs.executeScript({'file' : 'blocker.js'});
    }
}, {urls : ["*://*.facebook.com/*"]});

Creating a link element was the quickest way for me to parse the GET parameters (url.search) out of the URL. If the link has search parameters and specifically has ajaxpipe=1, we know that Facebook has finished loading the new page, so we can fire off our content script (which here watches the DOM for Buzzfeed links and hides those posts).

Functional design patterns

Functional programming languages are useless in the real world, they say. And you know, they’re more correct than I usually want to admit. Firms really only use functional languages, if at all, for infrastructure. It doesn’t usually make sense to recruit Haskellers or to teach your engineers Lisp, when Java or PHP or Ruby can get the job done sufficiently.

Regardless, important design patterns are emergent properties of functional programming languages, and they are useful to adopt in all other programming paradigms.

Avoid mutation. Changing a variable’s value makes it more challenging to reason about code correctness. Since functional programming, derived from the Lambda calculus, is about persistent state, one logically should assign new variables for new computations instead of overwriting old ones.

Mutate and perform I/O at the top level. Haskell explicitly marks I/O and mutation through its type system; a String read from a file is different than a normal String and cannot be treated like a normal String. This is important because it forces a program’s logic to be simpler; retrieve all needed outside information, perform computations, and then use the results as necessary.

A method should do one thing. Pure functional languages do not have imperative statements, only expressions; therefore, a function is constrained to do one useful thing. This, again, permits easy reasoning about code; it also permits easy testing of code. Finally, it allows methods to be reused and recycled.

A method should be its own documentation. As a consequence of the above guideline, the types of a method’s inputted parameters and outputted value should sufficiently explain what the method does. For example, it should be obvious that a nameless method of the HashMap<K,V> class that takes a K and returns a V is performing a hash table lookup. If this does not hold true for a method, it is likely too complicated.

Computation should be composed. Since functional methods are broken into one-bite pieces, it is common to see multiple methods chained together, the output of one serving as the input to another. Given some array of objects, you may wish to grab a specific parameter from each object, apply a transformation to said parameter, and produce a condensed, representative value. (For example — grabbing a user’s tweets, plucking the number of retweets each post has, and summing to find total retweets.) This should comprise three method calls.

Embrace recursion. Due to its lack of mutation, functional programming languages eschew iteration in favor of recursion. The two are equally powerful, yet recursion may oftentimes be the simpler implementation. Because functional programming languages force first-day coders to contemplate recursion, functional programmers are better-prepared to implement and employ tree and graph data structures, whose algorithms are significantly clearer with recursion. Since a recursive data structure may be the best tool for a job, learning recursion competently will permit you to write better code in less time.

To reiterate, this is not an argument to switch your tech shop to OCaml. This is an argument to learn and use functional design patterns. Programming paradigms are not discrete absolutes, but rather form a continuous spectrum. Moving toward the functional paradigm will avoid code bloat, simplify testing, aid correctness, and improve productivity.

My thoughts on Facebook’s relevance

We’ve all seen the statistics and anecdotes about how today’s youth are leaving Facebook in favor of Vine, Instagram, and Snapchat. Facebook, to them, is no longer cool. Anecdotally, my older friends also report that there is some lost novelty to sharing their life on their timeline. As one of my summer roommates Leo put it, “I feel like an attention whore when I post a status, so I don’t really do it anymore.” What does this mean for the future of Facebook?

In my eyes, not much; Facebook has several things going for it that give it more longevity than other social networks.

I’m going to ask you to forgive the sloppier-than-usual writing style here, as I’m just trying to get some thoughts down on paper in a somewhat coherent manner.

Photos

Facebook’s strongest asset, in my opinion, is the amount of photos it hosts. Photo albums represent, to so many people, years of great memories. This isn’t something I usually hear about when people defend (or attack) Facebook, which is why I feel obligated to bring it up. Facebook, whether knowingly or unknowingly, ameliorated photo albums via tagged photos and comments. Photo tagging destroyed the previous barrier that a person’s photos had to be from their own camera. Comments took off on Facebook and often give photographs a life of their own beyond the memories the photo captured.

Frankly, those of us that have been on Facebook for 5 or more years — mostly current college students and recent graduates — have most of the important photos from their life on Facebook. There’s currently no easy and well-known way to export and save these photos (a cursory Google search shows that a few tools exist for this, but they’re not widely known). The convenience of having all photos on Facebook is key; one of the biggest complaints I remember about Google+ when it came out was that one effectively “lost” their photos as a switching cost.

To current users, Facebook can co-exist with Instagram and Snapchat. I personally use the latter two services for dumb snapshots, whereas I take photos on Facebook more seriously. I suspect that this stigma exists for most other people. Of course, this means that the photo switching cost is a non-factor for younger users; they don’t have photos on Facebook to preserve in the first place.

The reason that Myspace didn’t have this switching cost was primarily because Myspace limited the number of photos you could host. I vividly remember belaboring over which of my 20 photos to delete so I could upload a newer one. Thus, as Facebook became large, people saw no reason to not switch over.

Ultimately, a social network that figures out how to grab and re-host photos from Facebook can cut one of its legs out. But without that, Facebook’s currently active users have no incentive to switch without effectively losing most (if not all) of their photos from the last 5+ years of their lives.

Chat

The reason that I stopped going on AIM was that everyone I wanted to talk to was on Facebook Chat. Facebook has shown that users will take a buggy chat experience with 99% of their friends over a smooth chat experience with some less-than-supermajority of their friends — hence why AIM fell.

I submit that some sort of instant messaging is here to stay for a long time. It offers users speed over text messaging and easy multitasking ability (Alt+Tab to Facebook, send message, Alt+Tab back to whatever — as opposed to picking up the phone to send an SMS), while preserving the ability to delay response to a message. (Voice and video chat offer speed but lack convenience and temporal benefits.)

The prevalence of Facebook Chat is a function of its active users, so this is more a secondary effect of the staying power of Facebook photos. However, given the superiority of instant messaging, Facebook Chat prevents early adopters from switching social networks; why make the switch if I won’t be able to talk with my friends?

The easiest way I can think of to circumvent this would be maintaining dual membership until a critical majority of your friends switch to a new chat service. I remember maintaining dual membership on Myspace and Facebook for about six months while I waited for latecomers (although I did essentially let my Myspace become dormant during that time period).

Parting thoughts

I think there are plenty of reasons that a given person may want to leave Facebook, from spammy applications to a newsfeed with an unacceptable signal-to-noise ratio to seeing frustratingly annoying shared image memes. However, as much as people complain, I feel confident that photos and chat are both competitive advantages for Facebook. To reference The Social Network, the reason that Facebook works is because everyone you care about is on there.

I’m definitely interested in hearing your thoughts on this. Feel free to leave a comment or hit me up @maxscheiber!

CS skills in the real world — debugging

This is the first episode of what I hope to be a mini-series in the practical uses of skills learned through computer science.

It’s August of 2008, and you’re playing around on the Internet. Maybe you’re on Miniclip playing flash games. (I mean, I hardly remember what I did on the Internet in 2008. Exponential growth, am I right?) Maybe you’re refreshing your Facebook news feed, since this was back before the days of AJAX updates. Either way, you’re surfing the web, and you see reports that Russia has invaded Georgia. I can’t really imagine why a high school world history class would teach anything about Georgia — so if you’re like me, you’re a bit puzzled as to how/why Russia invaded the U.S.

I'm twelve years old and what is this?

You don’t want to be Jessica B. Jessica B doesn’t know how to debug.

Debugging is a computer science term for discovering and fixing an error in your code. For those in the know, the word debugging conjures up demonic visions of NullPointerExceptions, application traces, and segfaults. Yes, all of us that have taken a systems programming class have spent hours chasing down a single memory leak the night before a homework was due.

However, my assertion is that the hours spent painfully isolating and correcting those reclusive little bugs gives you a valuable skill applicable throughout your entire life.

Proper use of reference materials

When we teach new CS students at Penn how to debug, we emphasize “Google it” more than anything else. Somebody out there has seen and solved your problem before, especially for large and interconnected frameworks like Rails and iOS. (The number of hours I spent last semester figuring out why it was so damn hard to do nontrivial things with a UITableView…unbelievable.)

I specifically remember hearing about the Russia-Georgia War of 2008, seriously wondering what beef Russia had with America, and Googling for Georgia to figure out that Georgia was indeed a Eurasian country that had nothing to do with the Braves and the Falcons.

CS also teaches you about more directed searches. Javadocs, man pages, and Hoogle are all incredible inventions that don’t get praised enough. Ever tried coding non-trivial Haskell without Wifi, and thus without access to Hoogle? You can’t do it.

Predictably, computer scientists understand the value of information. We use this in all walks of life, from scouring through electronics manuals to saving face when unfamiliar with a “common” fact.

Thinking outside of the box

I recently had a problem set due for a class in theoretical regression. One of the problems was to show that Cov(α-hat, β-hat) = -xbar/Sxx. Not a hard problem, but I kept getting that Cov(α-hat, β-hat) = -xbar*σ^2/Sxx, and I had no idea how to get rid of that extra sigma term.

Some students might have fudged the derivation, hoping that the TAs wouldn’t notice the mathematical gap. I personally refused to do this on principle. Other students might have gone to the teacher to ask for help. While I’m a big proponent of asking for help after immersing one’s self in a problem, this was at 1am the night/morning before the problem set was due. So, what would you do here?

Maybe, through my CS experience, I’m familiar with the problem of data being out-of-sync. I’ve got Apple-Shift-R (force-refresh, ignoring your browser’s cache) on muscle memory speed dial. For whatever reason, the first thought that jumped into my head was what if I’m looking at an old version of the problem set?

Sure enough, when I revisited the course website and checked the problem set PDF, the derivation in question had been changed to reflect the answer I was getting.

I couldn’t show that Cov(α-hat, β-hat) equals -xbar/Sxx because Cov(α-hat, β-hat) doesn’t equal -xbar/Sxx.

I wouldn’t have thought that I’d downloaded an incorrect version of the problem set without my background in CS. That was definitely an unorthodox way to figure out my issue.

This parallels computer science debugging in that programmers encounter really weird stuff all of the time. Programming languages and runtime environments are complicated pieces of engineering; not all bugs can be logiced out the standard way. Sometimes, one must be creative to fix a bug.

Inductive reasoning

A difficult, hidden bug is a riveting puzzle to solve, a true exercise in logic. Programmers maintain a mental list of likely reasons for the error and systematically check different symptoms to determine why the computer is not doing what they want.

This process and method of thought is similar to what a lawyer uses in oral argument or what a doctor uses in diagnosing a patient. (Extending the analogy even further, you could easily think of a patient’s sickness as a bug in their system that must be fixed.)

This may be the most powerful point in this blog because the mentality of inductive reasoning is not easily taught. The context of computer science and programming is one of the most effective ways to build true inductive reasoning skills, skills that transfer to almost any other profession.

My friends and acquaintances that have moved into investment banking (and, more generally, high finance) tell me that their computer science skills give them a huge leg up on their coworkers — not because banking necessarily requires coding skills, but because they know how to diagnose and solve an issue. They have the critical thinking skills that their finance and econ major brethren do not. Programming occurs in an open system, whereas one performs finance / econ problem sets in a closed system. Open systems introduce bugs that require these skills.

Consequently, those exposed to programming come armed with real-world abilities that give them a true competitive advantage in the workforce.

Conclusion

If everyone became a software engineer, the world would stop. Accordingly and obviously, this blog is not a call for everybody to enter the field of software engineering. However, you owe it to yourself to study programming — if not to gain a sense of technical literacy, to properly learn how to solve unexpected problems.

Attracting bright students to computer science

I stumbled upon computer science by accident. In a literal quest to 5 as many AP exams as humanely possible, I took AP Computer Science A on Florida Virtual School. Before that class, I had never considered computer science as a major. After that class, I knew it was something I wanted to do.

The absolute upper echelon of students entering university programmed throughout middle and high school. However, there is absolutely no reason why computer science should be a major reserved for these top gunners. My experiences at Penn have shown me that computer science is a field that many people can relate to and succeed in, but a field that most people would not consider studying since they are never exposed to it in high school.

I attended this high school, a school full of bright and creative students bogged down in the procedural world of AP Calculus, AP Physics, and AP Biology. At no point are they ever told about popular and useful majors such as computer science, finance, and statistics. My gut feeling is that most public schools offer this curriculum of traditional APs — sure, useful background knowledge to know, but a syllabus truly a mole wide and a molecule deep. Here, students are never informed of collegiate and career opportunities that fall outside the archetypal AP exams.

My question to the reader is — how do we attract these intelligent students to the field of computer science?

I personally believe in the power of grassroots activism, which is why I took it upon myself to visit my high school and deliver a guest lecture in my old calculus teacher’s 5th period AP Calculus BC class. This group of bright sophomores, juniors, and seniors is both curious enough to learn for fun and capable enough to learn on the fly.

My guest lecture had three structural components: explain what computer science is, show why it is useful, and field further questions from the students.

What is computer science?

When I asked this question to the class, one girl raised her hand and said, “My mom teaches computer science at a local college, C and C++ I think.” I smiled and shook my head. “Those are programming languages. Programming is an important application of computer science, but there’s much more to it than that.” And indeed, there is.

Computer science is the art of taking stupidly easy problems and spending a stupid amount of time figuring out how to solve them.

Obviously, this is a massive generalization, and an incorrect one at that. Extremely important computer science work is done every day on challenging, (NP-)hard problems. However, the initial appeal in computer science is that many of the algorithms taught in a traditional undergraduate sequence are solutions to simple problems. One could come up with these just by playing. That’s the angle I wanted to take with these students.

“For example, let’s say that I have a list of ten numbers.” I wrote down ten arbitrary numbers. “I want you guys to put these numbers in increasing order. Surely an easy task you guys do all the time, in one way or another. Have you ever stopped and asked yourselves how exactly you sorted these?”

A student raised his hand. “I took the smallest number and put it first, then the second-smallest number and put it second, and so on and so forth.” Ah, selection sort, exactly the answer I was hoping for!

I grinned and said, “Great answer.” I proceeded to discuss the number of “steps” we’d have to take to run that algorithm, essentially exploring the intuition behind Big-Oh notation and asymptotic growth.

Why is it useful?

I posed to the class, “Let’s say that we’re Facebook, and we need to spit out a list of your friends in alphabetical order. Can we do this any quicker?” Of course, I wasn’t expecting anyone to answer with “merge sort,” so I led them through how to derive merge sort and how to prove that it is fundamentally quicker than selection sort. For a class that had never heard of an inductive proof before today, I was impressed with how quickly they picked it up. Moreover, they understood the rationale behind quick algorithms – if your website or application takes too long, nobody’s going to use it.

Any further questions?

I ended up fielding a ton of questions that the students had, from how to count in binary to how Anonymous takes down websites. I explained what hackathons were, what good hacking versus bad hacking was, and what some of the hacks I’ve done at hackathons were. At the end of the class period, I definitely think I turned some students onto the idea of computer science. They were able to see its relations to math and its interesting applications.

Conclusion

While I don’t subscribe to the belief that everyone should code, I definitely think that a lot of bright kids that go pre-med or major in a pure science or other engineering discipline could really succeed in computer science, had they known more about it. In an attempt to expose more students to this material, I gave a similar lecture last year on the RSA algorithm and how they can use it to send secret messages. This is academic and practical content that most public schools simply will not ever explore with their top students. I think it’s a travesty.

How else can we encourage bright students to explore computer science and programming? Leave a comment with what you’ve done or what you think.

Fold as a chain of endomorphisms

A few months ago, Tom Ellis showed how to write foldr' as a chain of endomorphisms. The relevant code is pasted below, with a couple of changes I’ve made for clarity’s sake:

compose :: [b -> b] -> b -> b
compose [] = id
compose (f:fs) = f . compose fs

foldr' :: (a -> b -> b) -> b -> [a] -> b
foldr' combine base xs = compose (map combine xs) base

I originally saw Ellis’s blog post on Reddit, tried to qualitatively understand it, shrugged my shoulders, and moved on. I acknowledged that his implementation worked, but I definitely missed the intuition behind it. I’d Googled the term “endomorphism” (essentially a function of type a -> a), but I failed to make the connection between concept and code.

By coincidence, I recently had a short conversation with Andrew Braunstein about Haskell, and the notion of folding came up. He mentioned that the idea of folding could be understood by imagining replacing every (:) in a list with combine.

It was at that point that I put two and two together! First, I’ll show by example. Let’s say that you have a list of integers 1:2:3:4:5:[], and you want to sum them. You can conceptually think about summing the list by replacing every (:) with (+) (and replacing the empty list with the additive identity, zero). You obviously get 1+2+3+4+5+0.

Ellis’s code represents this idea of mapping one function into another, albeit in an abstract way. compose itself takes a list of endomorphisms and a starting value, and it feeds the result of one function into another. Remember, since an endomorphism is a function with the type a -> a (or in the sample code’s case, b -> b), we can easily achieve this chained computation.

All we have to do is map combine over our input list. In the example of summing integers, we’ll have a new list of functions that can be thought of abstractly as 1+ : 2+ : 3+ : 4+ : 5+ : []. Note that each function in the list takes an integer and returns an integer, hence we have a list of endomorphisms.

Finally, when we call compose (map combine xs) 0, we’ll recurse our way down to the end of this list of functions. When we reach the empty list at the end, we’ll return the base case, 0, and feed that into the last function of the list, 5+. Of course, 5 + 0 == 5, so we feed that result into the previous function, 4+, and so on and so forth.

In practice, this is the same thing as replacing each (:) with `combine` and evaluating right to left.

I plan on using this idea, in a less formal way, to teach students new to functional programming how folding works.

Pretty cool stuff, if you ask me!