Why is engineering so hard to learn and does it need to be?
As a self-taught programmer who moved from finance to engineering, the most common question I get is “what’s the best way to get started?”After it became unscalable to provide tailored advice for everyone I met, I created a resources page on my blog. Recently, I’ve been writing a book on Java with some fellow engineering friends and have developed strong opinions on how this stuff should and shouldn’t be taught. The problem is that most resources are written by incredibly bright and experienced engineers. And sadly, most of them suck at teaching it.
It’s a problem of unconscious competence and it’s not just a problem in engineering. Psychologists refer to the “stages of competence” to describe the process one goes through when learning a new skill. At first, you don’t know what you don’t know. As you learn you start to get a better idea of what you’ve learned and how far you have to go. As you move into expertise, however, things become so second nature you don’t even realize what you know or how you know it. And this is when people decide to write books.
But more problematic than unconscious competence is that programming just is really hard. The operational process of development is designed to best suit those who already have an advanced skill-set. Designed for programmers by programmers. Simply put, it’s not a user-friendly process and there’s no incentive to make it so.
First, we desperately need to rethink the common metaphors used to explain programming. They’re are a powerful way to grasp abstract concepts, but bad metaphors, do more harm than good. They need to be air tight or one is left to incorrectly fill in the gaps. We often explain programing as writing a recipe given to a chef, or driving a car. While these get a couple core things right, the rest of the environment; the kitchen, the driver, the chef, is left to interpretation. And the problem isn’t just in metaphors used to teach, but metaphors used in programs themselves. Git commands like “push” and “pull” feel unintuitive, but we eventually accept them and move on, trying to conceptualize how “rebasing” is like “rewriting history,” since time travel is such an easy concept to visualize.
Visualization is not a novel concept in programming. Something new programmers learn very quickly is the importance of good debugging techniques. From fancy debugging tools inside IDEs down to adding print statements to functions, visibility is imperative to success. And yet visibility is exactly what’s lacking in the way programming is taught. New programmers are told that “Hola! Me llamo Kari” means “Hello! My name is Kari” Then told to switch out “Kari” with a different name and notice how now the sentence means something entirely different. You’re left to guess what the rest of the words even are or how they function.
There’s a story I’ve always loved about how the University of Florida accidentally designed incredibly efficient sidewalks on campus. They spent so much time analyzing possible traffic patterns that a few weeks after classes started students had worn paths walking through the grass and they just built the sidewalks over them.
The lesson here is to build a system that enables us to easily do what we naturally do anyway. When I first started in functional programming, I would leave the text editor and use wire-framing software to map out data flows that were particularly complex. The fact that IDE’s don’t visually represent data flow feels like a huge miss. Worse though, is the sense of pride among engineers to be able to read through code bases without needing visualization. To suggest something like this isn’t seen as innovative, it’s seen as complaining about something you just “have to go through.”
When I first started writing algorithms in Ruby, I insisted on writing all of the basic functions myself, before I’d let myself use any of the magic built in. So no .length or .iseven? unless I understood how it worked. It made me wonder if there was a way to see the code for things like .length. But not being able to read C yet, I asked around to see if there was anything that translated ruby functions back into ruby. The confused looks and “why would you WANT that?” led me to believe I must be asking something stupid, so I gave up, feeling demotivated and reluctant to ask questions.
None of these ideas are in new by any means. Programming models that solve some of these basic problems were being used in the 70s and never caught on. Unfortunately, since then, we seemed to have forgotten that you can have new ideas about programming models in the first place. We defined it, created a curriculum to learn it and closed the door.
So my advice to new programmers is to remember this: there will be a beautiful and fleeting phase in your journey where you know enough to actually do stuff but you won’t really know what you’re doing. This will inspire the creativity to try anything you can think of and for a time, you’re mind will be completely receptive to all ways of thinking. Once you think you know what you’re doing, however, you’ll stop looking around for other ways to do it. You accept the world at face value and start telling the next class of new programmers to suck it up and get with the program (ha… sorry).
So trust anytime you feel like something is harder than it should be. Trust every time you wonder if there’s a better way of doing something. Trust every question, every insecurity and every idea that feels out there. Do not trust in the status quo. Do not trust that the solution in the book is the best one. And don’t, even if and especially if you are one, trust the experts.