There are many paths to learning to program. I decided to reflect on mine and thought it might be valuable to share. This post was inspired by Dan Luu’s How I Learned to Program.
For me, this reflection underscores that craft knowledge is learned by doing. The essential way to get better is to practice.
HELLO $NAME. YOU ARE $AGE.
I didn’t do anything much fancier than that, but the whole idea was amazing to me - I could program a computer!
My first big programming project was intended to manage a personal library. My brother and I labeled all of our books with call numbers, and I wanted an application to manage the library. I wanted the following functionality:
- Search for a book by author or title
- Allow a book to be checked out and returned
I had a couple of problems though:
- I didn’t know how to set up a development environment
- I didn’t know how to have my program interact with data
I can’t remember now whether I ended up writing my code for this project as a macro in Microsoft Office, or whether I used Visual Studio Express, but what I definitely remember is that I implemented search with a series of
if statements that were checking exact matches of search queries. 🤯 And I don’t think I figured out how to store book checkouts.
Later in the 2000’s, I started learning how to build websites with Microsoft FrontPage. I was also constantly tinkering with other computer things (printer setup, network setup, etc.).
I had lots of ideas for things I wanted to build - including a Web application for the family business, RC WATT - but little idea of how to do so.
At some point, I also picked up WordPress because I wanted customers to be able to update their own sites. I learned some more PHP from that.
I also built my first few e-commerce sites around this time - one for the family business and one for a side project. The former actually facilitated several large online purchases, and the latter had none at all. I guess I was learning about product validation too.
Reflection: I was finally starting to learn some fundamentals of Web development, but still lacking knowledge about system design, database design, etc.
High school (2010-2014)
High school is when I started building Web apps. In 2010, I was studying for the National Bible Bee and had to memorize 500 Bible verses for the competition. A friend told me about a free app, Memverse. I created an account and added the verses I wanted to know. The app helped me study efficiently with the Ebbinghaus Forgetting Curve: New verses would be reviewed daily, while verses I barely knew might be reviewed every few days, and so on. The idea was to review a verse just before it would be forgotten, to maximize efficiency in studying and to cement them even more strongly. We tend to best remember what we reinforce when we are about to forget.
A week before the competition, I felt prepared, partly due to the app, so I emailed the creator about volunteering. I won the competition the next week and spent much of my free time contributing to the project for the next couple of years.
One of my favorite projects was designing a “live quizzing” feature for Memverse, using WebSockets. At a scheduled quiz time, people would log on to answer timed questions. There was a live scoreboard and a chat system. This project taught me a few new technologies and improved my debugging skills. It was one of the more complex features I built.
One of the most valuable skills I learned was getting comfortable with the stack below me. Sometimes I had to fix a bug in a library I was using. Other times I just needed to read docs carefully, or even read the code for a library because the docs weren’t clear enough. Being able to jump to the right layer of the stack, and gather context by reading code, is an underrated skill.
One of my biggest growth moments as a programmer was realizing that libraries I use are just code, and I could read them directly rather than puzzling it out from the docs.— Greg Brockman (@gdb) February 20, 2022
Even today, I am surprised how much faster I move every time I start reading a layer I'm building on.
Around 2012, I created my first vanilla Rails app. It solved some business operation problems for RC WATT, and is still in production today. I learned so much from this, building on my experience with Memverse.
I also took the AP Computer Science exam in high school. I bought a prep book and self-studied since I was homeschooled. The main thing I got from the course was learning to generalize some of the concepts I’d learned in a single language (Ruby) by understanding them more generally in the context of another language (Java).
Reflection: Building software that people wanted to use gave me a ton of motivation and taught me so much. There is nothing like knowing that what you built helped someone. I was also learning how to learn and figure things out - a skill I’ve needed every day of my programming life.
In 2014, I entered Grove City College as an Electrical Engineering major. My Computer Science courses were some of my favorites. I especially liked the programming homework. I did nearly all my coursework in C++, another great language to learn. I had a lot of fun projects over my time there - one of my favorites was a group project to write a console Game of Hearts in C++.
Some of my courses pushed me to do things I would have never otherwise done. In Computer Architecture, I learned to write Assembly. Another memorable project was writing a prefix notation calculator in C++. That project blew my mind, largely because I got to write a parser and deal with input processing that was less straightforward than what I had done with Web programming - take this value and dump it to the database. In general, I was beginning to learn that there was more to programming than gluing things together with frameworks - there were also opportunities to create abstractions from very simple primitives.
As much as I learned from college about programming, I learned as much or more from internships.
My first internship was probably the hardest to get traction. I wrote a mix of Java and Python and a little Ruby. I remember not feeling nearly as productive as I wanted to be - it took me so long to write that Python client - but I know I learned a lot. I learned about what it’s like to write software for work, how to navigate a large system with multiple services, etc. I was glad to have a fellow intern to learn with, and ask all my dumb questions first.
My second internship was my most “intern-y”: I was one of just over a dozen interns, and we were all given laptops and stuck in a conference room for the summer. I learned a lot from my project - especially about communication. My favorite part of this internship, though, was getting to know all the other interns, learning about their projects, and helping where I could. It was this internship where I learned how much I enjoyed working with other people and passing along things I had learned.
My third internship was with a startup. It was about as unlike the other two internships as possible. Because it was a robotics startup, I got to do a little bit of soldering and a little bit of testing of the overall system, in addition to coding. Since I had the most experience building Web apps of anyone at the startup, I got assigned to update the Web app that customers used to view their robotic inspection data. I migrated the app off Kubernetes onto Google App Engine, added user accounts, and enhanced the online inspection reports to include the photos the robots captured.
Screenshot of current Gecko Portal. As an intern, I built an earlier version. Source: Gecko Robotics
Reflections: I learned a lot from my Bachelor of Science in Electrical Engineering. Critically, I learned about designing systems - both analog and digital. This education provided a stronger foundation for my continued pursuit of programming. I also learned a lot from my internships. From one to the next, I could see my practical skills increasing. I was getting better at debugging and picking up new technologies. I was getting more opportunities to design systems too.
After graduating, I spent the next three years at the startup, Gecko Robotics. I wrote all kinds of software there. Half of this was because when your company is small, you naturally get asked to do a lot of different things. The other half was because when I saw a problem that seemed important and wasn’t being worked on, I started working on it.
Here I started to learn Python better as a language, and I got to know several tools like Django and pandas quite well. I designed systems, and made lots of mistakes - like not spending enough time prototyping. I learned firsthand about technical debt - it was my first experience writing software at a fast-growing company, where the software you wrote a year ago was no longer the thing the company needed, and you wished you had already rewritten it.
Reflections: Writing software that you maintain over an extended period of time is very different from writing software for a school project or an internship, where your involvement ends when the summer ends. The value of good hygiene like tests, documentation, and planning becomes much more apparent.
As I write, I am one year into engineering at Shopify. I’ve learned a lot more about software engineering here. I’ve come to love test-driven development. I’ve gotten to see software at a whole new scale. I’ve paired with lots of people here and picked up a lot of things I would never have learned otherwise. There are tons of wonderful people here - they are the reason I joined, and I learn from them every day.
Reflections: Coming from a startup, I am learning a lot from writing software at Shopify’s scale. Apps I built before never had more than low thousands of users, but the software I work on now has millions. At this scale, it’s important to spend even more time reading code and understanding existing abstractions. I find that although my team focuses on one part of the whole system, my experiences building smaller systems end-to-end help me to traverse Shopify’s stack. I’m excited to continue learning to program here.
If I could do it all over
I’ve tried to reflect on each stage of my journey, but as I think about the whole, if I could do it all over again, I’d tell myself:
- Find mentors. They can save you time, in some cases years, by pointing you to the right resources. My growth started to accelerate when I found people who told me what I needed to be looking for.
- Bite the bullet. There are many things I avoided learning early on, because they seemed too hard (SQL, Linux command line, debuggers, etc.). I would tell myself to set aside time, at work even, to go deeper on the things that I didn’t know. I would tell myself that they are not as scary as they seem - they just require some intentional practice.
- It’s never too late to learn. At times I wondered if it made sense for me to keep learning about software. Once I started meeting other people who knew how to program, I immediately started to feel imposter syndrome. Everyone seemed to know more than me - they were seemingly always talking about things I didn’t know and had never heard of. I wondered if I’d fallen too far behind, and should just move on to something else. I’m glad I didn’t.
What I think I did right
Here are some things that I think helped me learn:
- Build things from scratch. Harder and harder things with time. I learned so much in high school from building my own Rails app.
- Hours of practice. There’s really no shortcut, and the fastest gains come at the beginning.
- Learn the stack below you. Running into issues in dependencies is just a matter of time - bugs, constraints, performance issues. Being able to identify and resolve issues at the right level of the stack is an important skill.
What about you?
I’d love to hear about your programming journey and whether anything resonated with you. I’m alexcwatt on Twitter!
Thanks to Ignacio Chiazzo for reading drafts of this.