June 16th, 2019
This is an excerpt of the teaching statement I sent as part of my application to Stanford. Yeah so it's a little cheesy! But I think it accomplishes the job of explaining my philosophy and approach to teaching someone to code.
– – – – –
Sometime in my early twenties, I decided it was time to wear contact lenses.
I had worn glasses since the third grade. I loved my glasses, but after twenty-something years, I figured it would be nice to see the world glasses-free sometimes. Plus, it occurred to me that I didn't really know what my glasses-free face looked like. That seemed like an odd state of being, twenty-something years old and unsure of my own face.
I went to the eye doctor and the optometrist greeted me. "What are you here for today?"
Sitting in the office, I started feeling squeamish about the whole thing.
"I wanted to try contacts, but now that I'm here, I'm… not sure if I can do it."
The optometrist smiled. "Anyone can learn to wear contacts."
"Well but like, the thought of putting something in my eye is … freaking me out a bit, now that I'm here. I'm thinking I might be one of those people who just can't wear contacts?" I started tugging on my hair. My palms were sweating. I regretted everything.
The optometrist remained unfazed. "No, anyone can learn to wear contacts." She proposed the following thought experiment: "Imagine you were locked in a dungeon by some terrible wizard, and the only way you could get out is if you put on a pair of contacts."
"Do you think you'd make it out of the dungeon?"
"I guess so?"
She nodded. "So, you are capable of doing this. If you can put in a pair of contacts in a dungeon, you can do it here and now."
Sure enough, I left her office wearing contacts.
* * *
That thought experiment in the optometrist's office had an impression on me. Where else might the "dungeon test" apply?
I thought about introductory programming concepts. Is there anything we teach that's so intrinsically complicated?
If a student were locked in a dungeon and had to prove mastery of nested for-loops, or pointers, or binary trees, or recursion in order to escape, how many students would fail?
Imagine if they were given access to the internet, to lectures and lecture slides, to TAs and office hours and all the examples they could find.
They would probably make it out of the dungeon, right?
Thus I begin my teaching statement: Anyone can learn to code. I say this with the indifferent certainty of my optometrist. Anyone can learn to code. They simply need the proper resources to succeed.
I say this with the indifferent certainty of my optometrist. Anyone can learn to code. They simply need the proper resources to succeed.
Surely a dungeon is not the ideal learning environment. Yet, at least in theory, some aspects of a dungeon are, well, … effective.
What are those qualities?
In a dungeon, there are no due dates for homework nor final exam times. The instructor might have spent 15 minutes on nested for-loops during lecture, but you are free to spend as long as you want.
We do not have the luxury of infinite time in a college course. But this does offer an interesting way of framing the problem: if a student could learn any concept given infinite time, then learning is a time optimization problem. When I am working with a student one-on-one, perhaps someone struggling with parameters or pointers, I encourage them to take things slowly. Premature optimization is the root of all evil, after all.
No one is watching you. There's no one peering over your shoulder and judging your mistakes. There's also no one who will eventually give you the answer if you give up. You might as well try anything and everything to aid in your understanding.
Experimentation is crucial to programming and software engineering, and mistakes are required for progress. From the first day of class, it's incredibly important to establish an environment where experimentation and mistakes are encouraged and celebrated.
An expectation of success
The dungeon test may be silly, but there is one especially critical quality about this exercise: it is an existence proof for success. The hypothetical dungeon isn't meant to be intimidating; it's meant to make the expectation of failure seem ridiculous. If you were in medieval times and some heartless queen locked you in a dungeon until you grokked binary trees, would this be such a hopeless fate?
In other words, my eye doctor had an unemotional, unromanticized, completely unyielding expectation that I would succeed. Her confidence became my confidence, and the contact lens problem shifted from if to when.
The idea that high expectations result in better student performance has been long backed by research, perhaps most famously by the Rosenthal-Jacobson study entitled "Pygmalion in the Classroom," which showed students scored higher test scores when teachers expected their success.
It is our duty as teachers to have confidence in every student's ability to learn, and to instill that same confidence back into the student.
Everything in computer science stands on the shoulders of abstraction. As a result, teaching computer science is a delicate balancing act between abstract and concrete concepts.
I've found that students of all backgrounds and experience levels — including first-time programmers and Google engineers with 10+ years of experience — learn the most while doing exercises and solving problems, or in other words, by applying the abstract to the concrete. It's not to say lecture or reading materials are pointless; rather, they are quite critical, but they serve a different purpose from exercises.
I categorize my teaching style roughly as an iterative 3-step process:
1. Teach the primitives.
By "primitives," I'm referring to the fundamental concepts, or the building blocks, of the subject you're trying to teach.
In Computer Programming I, one "primitive" for the course is arrays. On the day to teach arrays, I would start the class with a motivating example of the need to declare n variables at once. I'd then introduce arrays as the new tool we need to know about, and spend time on the definition and syntax, with pictures and accompanying explanation on indices and the like. I would live-code examples for the students and have them help me solve simple problems using our newly learned primitive.
This is where I'd argue lecture and reading materials are most important: to introduce building blocks. In these situations, I think a purely exercise-driven teaching approach is unnecessarily frustrating.
Consider a purely-exercise driven approach. We could teach arrays by simply posing to students a motivating problem and have them try to solve it on their own without any prior instruction. If they get stuck, we could tell them to "just Google it." After all, isn't that what "real" computer scientists do all the time?
But even if the student realized the abstract need for declaring a variable number of variables, how would we expect a student to figure out that an "array" is the solution if they've never heard of such a thing before?
Of course it's doable, but the challenge for the student would be in constructing just the right search query to produce the crucial information they lack, rather than a true computer science challenge.
At this point in their CS journey, their time as students (and our time as teachers) is much more valuably spent in wrangling algorithmically tricky array programming problems, rather than in tedious search query refinement. We should teach students the primitives directly, and eliminate the unnecessary frustration that comes from a lack of basic programming vocabulary.
2. Develop mastery of these primitive operations through exercises.
After the primitives have been presented and explained, now mastery of these concepts comes through exercises and homework, and not through books or lecture. Exercises should be carefully scoped and should scale in difficulty, from almost excessively trivial to Google interview-calibre difficulty. This is a great way of addressing different skill levels in a classroom by providing easy wins for the struggling students and challenges for the advanced students.
I make it a rule to only assign "fair" exercises — that is, exercises where the student has already been provided with all the knowledge needed to solve them. Again, we want the student to focus on computer science challenges, not on the challenge of writing effective search queries to fill in their knowledge gaps.
It's also important for the teacher to solve every problem before assigning it. This might sound like an obvious point, but it's especially crucial in computer science, where a seemingly trivial problem can end up unreasonably difficult or tedious in an educationally uninteresting way.
3. Review and compare a variety of solutions.
Finally, the solution to select exercises should be discussed in class or section, carefully and deliberately, with alternate solutions, best practices, and common errors pointed out along the way.
The review and critique of programming solutions is also standard practice in industry. At Google, a code review is required before checking in any code into a repository. This is an essential part of the engineering process, not only to ensure code quality, but also as a way to teach and develop fellow engineers by giving them specific design advice on the code they've written: how could they have written an algorithm more efficiently, what's a better way of composing a function, how could the code have been more readable?
In many ways, computer science is an art as much as a science. There is never one "right" solution, but there are certainly better and worse designs. It is important to review different solutions and designs for the same problem to instill our students with good engineering practices.
Just as there is never one right solution to a programming problem, I believe there is no one right way to teach. Teachers do best when they follow the methods that fit their teaching style.
I personally employ a mixture of slides with live coding examples. I like a lively and conversational classroom environment, and I strive to make lectures interactive and engaging by asking questions and having students direct me in my coding examples every step of the solution.
I also believe that building a community is a very important part of our field, and in school and at Google, I've enjoyed creating opportunities for people to engage after work and class.
* * *
(my full teaching statement was a bit longer but references stuff that's now out of date. so cutting it off here!)