September 02, 2016

nullprogram.com/blog/2016/09/02/

Update June 2019: Dan graduated from college and is now my full-time colleague.

Over the past two years I’ve been mentoring a high school student, Dan Kelly, in software development though my workplace mentoring program. It’s been one of the most rewarding experiences in my life, far beyond my initial expectations. It didn’t just go well, it went extraordinarily well. One of my co-workers described the results as, “the single most successful technical investment I’ve ever seen made in a person.” Last week the mentorship effectively ended as he became a college freshman. While it’s fresh in my mind, I’d like to reflect on how it went and why this arrangement worked so particularly well for both of us.

Students come into work for a few hours at a time a few days each week throughout the school year, typically after school. They’re supplied with their own computer in a mentor-arranged work space. In my case, Dan sat at a smaller makeshift desk in my office. The schedule is informal and we were frequently making adjustments as needed.

An indispensable feature is that the students are unpaid. Based on my observations, the primary reason many other mentorships aren’t nearly as effective is a failure to correctly leverage this. Some mentors put students directly to work on an existing, funded project. This is a mistake. Real world, practical projects are poor learning environments for beginners. The complexity inhibits development of the fundamentals, and, from a position of no experience, the student will have little ability to influence the project, stifling their motivation.

If being unpaid sounds unfair, remember that these students are coming in with essentially no programming experience. For several months, students are time sink. Maybe they fiddled around with Python on their own, but it probably doesn’t really amount to anything meaningful (yet).

Being unpaid means students can be put to work on anything, even if unfunded — even if it’s only for the student’s own benefit. The very first thing I did with Dan was to walk him through an install of Debian (wiping the near-useless, corporate Windows image). I wanted him fully in control of, and responsible for, his own development environment. I never sat at his keyboard, and all exercises took place at his computer.

From here I took a bit of an unconventional approach: I decided he was going to learn from the bottom up, starting with C. There would be no Fisher-Price-esque graphical programming language (yes, some mentors actually do this), not even an easier, education-friendly, but production-ready language like Python. I wanted him to internalize pointers before trusting him with real work. I showed him how to invoke gcc, the various types of files involved, how to invoke the linker, and lent him my hard copy of first edition K&R.

Similarly, I wasn’t going to start him off with some toy text editor. Like with C, he was going to learn real production tools from the start. I gave the Emacs run-down and started him on the tutorial (C-h t). If he changed his mind later after getting more experience, wanting to use something different, that would be fine.

Once he got the hang of everything so far, I taught him Git and Magit. Finally we could collaborate.

The first three months were spent on small exercises. He’d learn a little bit from K&R, describe to me what he learned, and I’d come up with related exercises, not unlike those on DailyProgrammer, to cement the concepts. I’d also translate concepts into modern C (e.g. C99).

With K&R complete, he was ready to go beyond simple exercises. Unfortunately, I wasn’t able to involve him in my own work at the time. His primary interests included graphics, so we decided on a multi-threaded, networked multi-processor raytracer.

It was a lot more educational for us both than I expected. I spent a significant amount of personal time learning graphics well enough to keep ahead: color spaces, blending, anti-aliasing, brushing up on linear algebra, optics, lighting models, modeling formats, Blender, etc. In a few cases I simply learned it from him. It reminds me of a passage from The Moon is a Harsh Mistress (the namesake of this blog):

I liked Prof. He would teach anything. Wouldn’t matter that he knew nothing about it; if pupil wanted it, he would smile and set a price, locate materials, stay a few lessons ahead. Or barely even if he found it tough—never pretended to know more than he did. Took algebra from him and by time we reached cubics I corrected his probs as often as he did mine—but he charged into each lesson gaily. I started electronics under him, soon was teaching him. So he stopped charging and we went along together until he dug up an engineer willing to daylight for extra money—whereupon we both paid new teacher and Prof tried to stick with me, thumb-fingered and slow, but happy to be stretching his mind.

Since this was first and foremost an educational project, I decided we would use no libraries other than the (POSIX) C standard library. He would know how nearly every aspect of the program worked. The input (textures) and output formats were Netpbm PPMs, BMP files, and YUV4MPEG2 (video), each of which is very easy to read and write. It loaded 3D models in the easy-to-parse Wavefront .obj format. It also supported a text rendered overlay, initially using our own font format and later with fonts in the Glyph Bitmap Distribution Format — again, easy to parse and use. The text made it possible to produce demo videos without any additional editing (see the above video).

After a year on the raytracer, he had implemented most of what he wanted and I had an opportunity to involve him in my funded research. By this point he was very capable, quickly paying back his entire education.

Together we made rapid progress — much more than I could alone. I can’t go into the specifics, but much of his work was built on lessons learned from the raytracer, including an OpenGL display and SIMD-optimized physics engine. I also taught him x86 assembly, which he applied to co-author a paper, ROP Gadget Prevalence and Survival under Compiler-based Binary Diversification Schemes (slides).

To reiterate, an important part of this entire journey was the influence he had over his own work. He had say on the direction of each project. Until he started earning a college intern pay (post-graduation), I had no ability to make him do anything he didn’t want to do. I could only rely on his motivation. Fortunately what motivates him is what also motivates me, so to find the framing for that motivation I only had to imagine myself in his shoes.

An important aspect I hadn’t noticed until the second year was respect. Most of Dan’s interactions with other co-workers was very respectful. They listened to what he had to say and treated it with the same respect as they would a regular, full-time co-worker. I can’t emphasize how invaluable this is for a student.

I bring this up because there were a handful of interactions that weren’t so respectful. A few individuals, when discovering his status, made a jokes (“Hey, where’s my coffee?”) or wouldn’t take his comments seriously. Please don’t be one of these people.

What’s comes next?

In many ways, Dan is starting college in a stronger position than I was finishing college. The mentorship was a ton of vocational, practical experience that doesn’t normally happen in a college course. However, there’s plenty of computer science theory that I’m not so great at teaching. For example, he got hands on experience with practical data structures, but only picked up a shallow understanding of their analysis (Big O, etc.). College courses will fill those gaps, and they will be learned more easily with a thorough intuition of their context.

As he moves on, I’ll be starting all over again with a new student.