Philip Guo (Phil Guo, Philip J. Guo, Philip Jia Guo, pgbovine)

How I Learned Programming

I summarize my 20-year journey to learning computer programming, written at a time when my rate of new learning has slowed down significantly.

Last night I read Dan Luu's fantastic article, How I learned to program, which recounts his 20-year-ish journey to learning computer programming. I especially liked how Dan described both the technical skills that he learned along with the meta-skills that generalized beyond the slew of ever-changing technologies. Since we're about the same age, I got inspired to write up my own learning journey before I forget too many of the details.

Since timing is everything, this is the ideal time for me to write such an article. This is my fourth year working as a professor, and despite my best efforts to keep writing code regularly, I realize that my days of heavy coding and code-related learning are coming to an end (watch PG Vlog #48 - Programming as a Professor for details). Besides my rate of learning programming slowing down considerably, I'm also on the verge forgetting the details of how I got here, so it's best to write it all out now.

As someone who loves programming, it's bittersweet to admit that I've reached a point in my life where my rate of learning new forms of programming has ground to a halt. Nowadays, coding for me involves using my prior skills and making incremental advances on my existing legacy codebases rather than learning brand-new technologies. In my current career as a full-time research manager for my lab, my main goal is to facilitate my graduate students' learning and execution of programming-related ideas. My own learning must take a backseat for now. At the end of this article, I'll reflect on how I'm trying hard to remain technically-relevant even though I no longer have the time (or the career incentive) to write large amounts of code. OK, here we go!!!

Childhood (1994–2001)

I had no early childhood exposure to programming since neither of my parents knew how to code and I had no access to relevant mentors. I made my first foray into learning BASIC in 1994 (6th grade) when I picked up my dad's copy of Teach Yourself Qbasic in 21 Days. He had to take a BASIC-based programming course back in business school, but he never talked about it; I think he barely eeked out a passing grade by copy-pasting code (pre-StackOverflow!) without understanding much of it. My dad probably encouraged me to read that book since it was lying around the house, but he didn't know enough about programming to personally tutor me. I tried following that book by myself but got stuck as soon as it introduced functions (subroutines? what were they called in BASIC?). I remember grokking arithmetic, variables, and control flow—essentially using the computer as a glorified calculator. But as soon as procedural abstraction was introduced, my head exploded, so I quit.

Fast forward to 1997 when I was in 8th grade. Our dial-up internet service provider (ISP) gave subscribers a tiny amount of space to host personal websites (maybe 1 megabyte?) at some tilde-filled ~URL. I remember buying a book called The Complete Idiot's Guide to HTML, using Notepad.exe on Windows 95 to hand-write my first HTML webpage, and using some flaky FTP GUI to upload it to the ISP's server. I was amongst the first of my friends to have a personal website (which made me super popular in middle school, NOT!). Soon afterward, I “obtained” copies of Microsoft FrontPage (a GUI-based webpage builder) and Adobe Photoshop and then went wild making terrible-looking websites with Photoshopped graphics. Here's what my old websites looked like. They were all pure-HTML and images, with no CSS or JavaScript whatsoever. My love for web design carries over to this day, even though I'm still not that good at visual design.

I didn't get back into learning programming until 11th grade (1999) when AP Computer Science (taught in C++ back then) was offered for the first time in my high school. (Actually an older Pascal-based version was offered a long time ago, but that teacher was long gone.) One of our math teachers, who had never used C++ or taught programming before, attended a C++ bootcamp that summer to prepare to teach that class. He installed the Borland Turbo C++ IDE on a fleet of Windows machines in our high school's computer lab, and off we went!

AP Computer Science was my favorite class in high school, not only due to the content but also to the fact that we were learning the material right alongside our teacher; we were all in it together trying to dissect the messy guts of C++. We probably learned more about C++ edge cases than actual core computer science concepts. Several of my friends and I spent the next year (12th grade) serving as teaching assistants for that class, which gave me lots of hands-on experience helping novices debug their code. (We also hid copies of Quake 3, Counter-Strike, and other games within system directories on the lab computers so that we could play them on the LAN when our teacher wasn't looking. We were, uhhh, learning about networking protocols. He would sometimes hear us cheer loudly and assume that we had helped a student fix a tricky coding bug.) Read My Unexpectedly Awesome AP Computer Science Class for more details. That class cemented my desire to major in computer science in college.

I graduated from high school in 2001 and prepared to start as a college freshman that fall. At that point, I had a good academic background but absolutely zero real-world programming experience beyond making HTML-only personal websites.

College Years @ MIT (2001–2006)

I spent five wonderful years at MIT (2001–2006) in the combined bachelor+masters degree program in Electrical Engineering & Computer Science. That was the period when I learned most of my programming skills that I still use today.

People have this perception of MIT students as uber-master-computer-hackers, but that's only a tiny sliver of the student population. Like many private U.S. universities, MIT has a four-year residential living system where incoming students pick a dorm or independent living group to live in for all four years of college (in contrast to many public universities where students live in dorms for only one or two years). This policy meant that each dorm could forge a unique identity with long-lasting traditions. Most of the uber-hackers lived in a few select dorms, which I didn't choose since I wasn't an uber-hacker. As a result, when I started college, my friends were mostly people like me who did well in high school but didn't have much prior programming experience. At most, some had learned Perl or PHP to do server-side scripting for their personal websites (which was already more advanced than my HTML-only skills at the time).


I enjoyed the academic challenge and rigor of most of my college classes (see here for a list of all the classes I took), but almost none of them formally taught programming. Most of the time, we were expected to learn the relevant programming languages on our own (or already know them). The one notable exception, which still remains one of my all-time favorite classes, was the Scheme-based SICP: Structure and Interpretation of Computer Programs (free textbook online). That class is no longer offered since MIT (and other SICP schools such as UC Berkeley) revamped their introductory curriculum to become Python-based.

My other programming-intensive class in college didn't go as well. I took the Java-based software engineering lab class (6.170) at the start of my second year, which in retrospect was a bit too early for me. I couldn't internalize the core lessons at the time because I hadn't needed to build real software systems yet. My four-person project team consisted of all second-year newbies like myself. We hacked together something that barely half-worked, and we didn't even know how to use version control (CVS was all the rage at the time, but it was painful to set up, especially on Windows).

In the end, college provided the setting for me to learn programming, but the vast majority of that learning happened outside of the classroom in three main venues: summer internships, research labs, and personal hobby projects.

Summer Internships

I interned in software engineering roles for all three summers in college. I wasn't able to land internships at the hottest companies (at the time, Microsoft was by far the most coveted place, followed by a young startup named Google) for several reasons: 1) family constraints kept my job search only to the Los Angeles area, 2) the dot-com bubble burst right as I started college in 2001 so there were relatively few job openings, 3) I didn't have as much programming experience as the top applicants.

Nonetheless, I took whatever jobs I could find in L.A. and ended up writing C++ (the only language I knew decently at the time) at companies you've never heard of. Even though I learned some C++ in my high school AP Computer Science class, it was good to finally get a chance to learn it better in real-world settings. During my first summer, I used Linux for the first time and spent most of my days installing and testing the company's printer driver product on various distros. I also got to write a really crappy sketch recognition GUI for an early Linux-based tablet using the Qt UI toolkit (eight years before the first iPad). During my second and third summers, I used Microsoft Visual Studio to write C++ simulator code for semiconductor tester hardware.

I was grateful for the hands-on learning opportunities, but those internships were pretty boring overall. The highlight of that era was wasting a bunch of time at the office chatting with a colleague who was an aspiring actor in L.A. doing web programming gigs to pay the bills while trying to land his big break. If I had gotten internships at more exciting and higher-profile companies (with perks like free gourmet food and intern field trips), then I would've probably joined full-time after graduating like most of my friends did instead of going to grad school for my Ph.D.

Research Labs

At the start of my second year of college (Fall 2002), I was craving more hands-on programming experience, so I scoured online job postings for on-campus research assistant positions. I cold-emailed a bunch of professors, and Eric Klopfer (a young assistant professor back then) was the only one who agreed to meet with me. Eric wanted someone to port a suite of existing educational games from embedded hardware into “new” (at the time!) Palm PDA devices (think smartphones but way way way more primitive). Even though I had never even seen a PDA before, I jumped at that opportunity and gave it everything I had. He bought me the original K&R C book since C was the language used to build apps for those devices. Throughout the year, Eric also bought me half a dozen different Palm devices to test my code on. This was a super-fun experience and gave me a sneak peek into a future of ubiquitous mobile devices that we now take for granted. Here's my year-end project write-up with tons of screenshots.

In my third year of college, I did a brief stint in Fredo Durand's computer graphics lab making a C++ GUI (again using Qt like in my first internship) for an image processing tool and then found my way into Mike Ernst's software analysis research lab. Over winter break, I saw an online job ad asking for someone with C and C++ skills, and since I had a moderate amount of C and C++ work experience, I was up for the challenge. Mike wanted me to build a C/C++ frontend for his Daikon invariant detector. This tool was supposed to take C/C++ source code, instrument and run it, and then produce a detailed run-time value trace that can be fed into Daikon.

I spent the next 2.5 years working on this project in Mike's lab, which was by far the largest and most technically challenging piece of software that I had built up to that point. I ended up creating a 10,000+ line C plug-in atop the Linux-based Valgrind code instrumentation infrastructure. The coding was really hard at times; there were moments when I had absolutely no idea how to proceed, but fortunately Mike's Ph.D. student Stephen McCamant patiently showed me the ropes and helped me debug even the nastiest of memory corruption errors. I became a fairly adept C and Linux systems programmer after those 2.5 years in Mike's lab. Read my masters thesis for all the gory details.

Personal Hobby Projects

As I approached my senior year of college in 2005, I was developing into a solid low-level C/C++ Linux programmer, but something still gnawed at me: I still had never written any code for fun. Programming was merely a tool that I used for work, but I wasn't at all passionate about it. In the years prior, I had a few false starts where I tried using C++ to make some hobby projects, but I never knew what was the “right” way to get started. The initial barriers to entry were too daunting; I couldn't simply start writing code and see cool things happening on screen. There was too much friction involved in getting anything non-trivial to work. Programming just wasn't fun for me ...

... and then I discovered Python.

I forgot how I first got exposed to Python, but it definitely wasn't from classes or research. At the time, I had only seen people use Perl for scripting and sysadmin tasks but never learned it myself. In early 2005, I remember buying the O'Reilly Learning Python book by Mark Lutz (2nd edition, which covered Python 2.3). Maybe it caught my attention while I was hanging out at the MIT Coop campus bookstore, which had a well-stocked O'Reilly section for onlookers to browse. I love how bookstores encourage such serendipity in ways that online retailers can't emulate.

It's a major cliche by this point, but something just clicked in my head as I was learning Python from that book. For the first time ever, programming felt intuitive, easy, and ... fun. I had always assumed that doing anything non-trivial took a ton of painful coding and debugging (from my endless battles with C and C++), so I was amazed at what I could accomplish with just a few lines of readable code in Python. It almost seemed too easy to be true.

During the second half of my senior year (early 2005), I took only one class so that I could focus more on research. I ended up having a lot of free time, so I dived into using Python to create hobby software projects around my longstanding personal interests in photography. I wrote Python scripts to organize, categorize, resize, and tag my thousands of digital photos. More ambitiously, I wrote scripts to generate custom web-based photo albums since nothing existed that had the features I wanted (see Personal Software Projects for details).

This was the time when I first started falling in love with programming. For those final two years of college (and the summers surrounding them), my “day job” in the research lab involved tons of gross C and C++ code, but when I went home to hack for fun, I lived and breathed Python.

Finally, to fully realize my dreams of creating the kinds of dynamic web-based photo albums that I envisioned, I had to learn JavaScript and CSS to complement my basic HTML skills. My XML Photo Gallery project came out of those early forays into web frontend programming without using any modern frameworks or helper libraries like jQuery. Back then, there were no browser developer tools or cross-browser compatibility libraries, so I had to debug with pop-up alert() statements and look up arcane code snippets (pre-StackOverflow!) to make my web apps work across the three major web browsers at the time: Microsoft Internet Explorer, Mozilla Firefox, and (in a distant third place) Safari.

Since it was cumbersome to hack on open-source software on Windows, around this time I installed Linux and FreeBSD on my personal computer in my dorm and used Linux on the lab machines. I also got used to writing shell scripts and using other Unix-style command-line utilities. In summer 2005 before starting my fifth year at MIT to finish my masters degree, I bought my first Mac (a first-generation Mac Mini) and have used macOS almost exclusively since then.

By the time I graduated from college in 2006, I felt comfortable programming in several languages (C, C++, JavaScript, Python) and, more importantly, had the confidence that I could pick up new languages and libraries on demand. I wasn't yet an expert, but I knew that I could learn more whenever the need arose.

Ph.D. Years @ Stanford (2006–2012)

I spent six years working on my computer science Ph.D. at Stanford. During that time, I wrote a ton of code, both to implement novel software prototypes and to analyze experimental data. The Ph.D. Grind describes all of those projects in gory detail.

As I'm writing this article, I just realized that I didn't actually learn many new programming skills during my Ph.D. years; I merely extended the prior knowledge I had built up from my college days. Specifically:

  • Learning more C and C++ to build software prototypes such as KLEE extensions (atop LLVM), IncPy and SlopPy (extending the CPython interpreter), and CDE (extending strace).
  • Using Python and R to analyze experimental data. R was the only new language that I sort of learned during my Ph.D., but I picked up only rudimentary base R ... long before the modern R tidyverse ecosystem came on the scene.
  • Improving my JavaScript, web development, data visualization, and database skills to build interactive web apps for HCI research projects.

These languages and accompanying ecosystems were enough for me to complete the work that led to all the published papers from my Ph.D. years (everything from 2008 to 2012), eventually culminating in my Ph.D. dissertation.

Why didn't I learn more new programming languages and paradigms in grad school? Probably because what I already knew felt expressive enough to get the job done in terms of implementing software prototypes and analyzing data for my research. I dabbled a bit in functional programming since some of my friends were into it, but the sorts of research that I worked on didn't require those languages. I also didn't need to build mobile or embedded apps for my Ph.D., so I never dove into those ecosystems either.

I'm biased, but I feel that C, C++, JavaScript, and Python (the four main languages I learned in college) cover enough ground for me to do what I need to do in terms of producing useful research in my chosen field. Those aren't the only viable choices; they're merely the ones that I chose due to my personal history. For instance, here are some popular alternatives from TIOBE:

  • Some people prefer Java or C# over C++ for desktop apps,
  • Ruby or PHP over Python for web apps or scripting,
  • R or MATLAB over Python for data analysis,
  • and Go over C for low-level systems hacking.

These options are all fine, but none were compelling enough for me to learn in addition to the languages I already knew well. In the end, doing a Ph.D. was more about improving my existing programming skills rather than developing brand-new ones.

By the time I graduated in 2012, I had been programming seriously for about 10 years, so I felt confident in my ability to both execute on challenging programming tasks and to learn new skills on demand. I wasn't at all an expert compared to my friends who were professional programmers, but I was pretty good at coding for being a researcher. In sum, I no longer felt like programming was a limiting factor in getting things done.

Epilogue: Post-Ph.D. Years (2012–present)

After a brief stint as a full-time software engineer at Google, I returned to academia and have been programming less and less (and doing more and more lab management) as the years pass.

It's a running joke that professors are fixated on the technologies they learned back in school. Even though that trope bugs me, I have to admit that it's kind of true. When I was a student, many of my professors were devoted Perl hackers who came of age in the 1990s. My own formative university years in the 2000s were spent immersed in C, C++, JavaScript, and Python; I'll probably never again have the dedicated time and energy to pour myself into new programming languages with that level of intense focus.

That said, in recent years, I've been trying to keep up with the blistering pace of change in the JavaScript web programming ecosystem. Specifically, I've had some luck in upgrading my almost-decade-old Python Tutor codebase to a TypeScript-based workflow. I've also kept an eye on the fast-moving data science and machine learning ecosystems (mostly in Python and R), but I'm sure that I'm developing enormous blind spots everywhere. Furthermore, these are still all incremental advances to languages that I already know, not brand-new paradigms.

To further stave off atrophy, I've been spending more and more time learning about the latest programming-related news, even if I don't personally get to practice what I learn. I still read a lot of good programming blogs, listen to technical podcasts, and watch tons of industry conference talks on YouTube to keep an eye (and ear!) on what programmers find most important at the moment. Best of all, the students in my lab are perhaps my most direct source of knowledge on what emerging technologies are coming down the pipeline. And since I've been in this game for almost two decades now, I've gotten fairly good at cutting through all the noise to figure out what could potentially have lasting impact and what's simply overblown hype.

As someone who manages a research lab where my students are the ones doing most of the programming, the operational model I've settled into for myself is one of being a technical project manager. In the coming years, I still want to remain technically competent enough to know what the heck is going on and what rabbit holes to avoid getting stuck in, but I fully admit that my own students' programming skills will soon surpass my own.

Finally, what about the T word: teaching? How can I possibly teach students the latest and greatest in technical content without being on the ground myself hacking away on version X of framework Y with corner case Z? Such a discussion can take up an entire article, but in short, that's not my job. I think university professors are best suited for teaching the fundamentals of their fields (which don't actually change much over time), research-based subjects, and broader holistic topics (such as tech ethics and history) that aren't valued as much by the industry marketplace. Most hands-on programming skills are picked up on the job (just look at how little I mentioned classes in this article!), and specific technologies change every year. Thus, to make the most of college, one should ideally optimize for learning what can't be easily learned on the job, which are usually the topics that commercial interests don't directly value.

Keep this website up and running by making a small donation.

Created: 2017-12-25
Last modified: 2017-12-26
Related pages tagged as programming:
Related pages tagged as computing education: