Rethinking Computer Science Education
There is an old Chinese proverb — 授人以魚不如授人以漁. Translated literally, it means “Giving a person a fish is not good as teaching a person to fish”. If you prefer, here is the more poetic version:
Give a person a fish and you feed them for a day; teach a person to fish and you feed them for a lifetime.
Let’s take a moment and appreciate the beauty of the Chinese language here. The proverb is written in the form of a parallel comparative structure — something is not as good as (不如) something else.
If you look closely, the only difference between the two parallel clauses is in the last character — 魚 (“a fish”) verses 漁 (“to fish”).
There’s actually a pretty cool easter egg here that is lost in translation — these two characters are homophonic, meaning that they have exactly the same pronunciation. If you just heard this from somewhere without having seen the written words, the proverb wouldn’t make any sense to you!
The first character (授) used in both clauses is also quite interesting. Even though they are exactly the same character, used in the first position, it means “to give”, but used in the second clause, it means “to teach”. This character also has the meaning of “to grant” or “to gift”.
It’s no coincidence that all of these concepts share the same character in the Chinese language — teaching is really giving out a gift in the form of a skill. The best thing a teacher could teach is the meta-skill of self-learning, a gift that feeds a person’s intellect for a lifetime.
All of these are pretty uncontroversial. Every educator thinks that this is what they are ultimately trying to accomplish. However, our 21st century economy makes things pretty difficult. As it turns out, most of us are not farmers or fishermen anymore. In today’s economy, what is the fish? What does it actually mean to teach someone to fish?
In tech, the line is even more blurry. If we teach someone to, say, build Rails applications today, is that teaching them a skill, or is that just giving them a fish that would perish in a few years? What about teaching programming? Many cities have announced plans to bring programming into their regular school curriculum. Is that teaching students to fish? In our industry, what does it really mean to “learn to fish”?
Our industry is in love with the idea of disruption lately. Startups like Uber and AirBnB identified some inefficiencies in existing industries, came up with fresh, technology-centric approaches, ignored all the rules along the way and changed the game entirely for their sector.
For the most part, it’s a change for the better. When I arrived at Singapore the other day, I took an Uber from the airport to the place I was staying — which happened to be a room I found on AirBnB. As a consumer, I love their products.
Unfortunately, while there are plenty of rules that are just creating friction and inefficiency in the market, there are also a lot of rules that existed for very good and very important reasons. As a society, we have encoded decades of learnings into these regulations — throwing all of them away and starting over means having to relearn these lessons painfully along the way.
In tech education, we have a similar phenomenon. There are some clear inefficiencies in our education system. Programmers and software engineers are in very high demand these days — we need a lot more of them, and we want them now. A Computer Science degree takes 3-4 years in most schools, which is way too long and costs too much.
Besides, CS programs don’t even produce that many good programmers — everyone knows about the disconnect between academia and the industry. A lot of CS graduates don’t even have the right skills to fill the jobs that are actually in-demand.
So what do we do? We disrupt the education system of course. We came up with new programs like code schools and bootcamps, training new entrants on exactly what our industry needs right this second, in the shortest amount of time possible.
Just like Uber and AirBnB — I love the idea. At my company, we recently hired a new employee who came from a code school background. She’s an excellent fit for the role we were hiring for and we couldn’t be happier with the result.
Yet, just like Uber and AirBnB, I can’t help but feel that we might be throwing out the baby with the bath water. Computer Science as an academic discipline is much older than you might think, not to mention that the university education system itself is literally hundreds of years in the making.
While the traditional system is far from perfect, perhaps there are some good reasons it is structured the way it is? Perhaps there is a reason why fundamental CS curriculums have barely budged in a decade despite the rapid changes in the industry?
I came from a traditional CS background. I went to a Candian school called Simon Fraser University for a CS degree and also spent some time at the National University of Singapore as an exchange student. They both have excellent CS programs, and I am very grateful for my education there.
On the other hand, as a CS graduate, I can definitely understand where a lot of the criticisms are coming from.
Come to think about it, I didn’t even learn that much about programming at school — there weren’t that many programming assignments at all, I was mostly just taught and tested on the conceptual and theoretical level.
By that standard, my CS education was terrible — I was never once graded on the clarity of my code, or given any feedback on the code quality in my programming assignments; all I needed to do was submit programs that work. The words “refactor” and “unit tests” never once came up during my academic career.
It’s like, not only did they not teach me to fish — all we did was sit in a room and be like, hmmm, given a few different ways of catching fish, how can we mathematically prove that one of them is more efficient than the rest?
As it turns out, computer science isn’t really about programming. In fact, it might not have that much to do with computers after all. Edsger Dijkstra, a famous computer scientist, once said this:
“Computer Science is no more about computers than astronomy is about telescopes.” — Edsger Dijkstra
So, if Computer Science isn’t really about programming and computers, and if I didn’t learn most of the work skills I needed from school, does that mean the critics were right and I wasted 5 years of my life?
Well, I can’t speak for everyone, but personally, I’m really glad I did it. I happened to enjoy learning about the topics they covered, so, if nothing else, I had a lot of fun.
But I think there is more to it.
Somehow, I am pretty sure I wouldn’t be able to work on the stuff I do today without my CS background, or it least it would have taken me much longer to get here. I’m not just talking about the knowledge — like most people would tell you, I didn’t end up using most of things I learned in school; even for those things that are useful, I have long forgotten the details by the time I needed them and had to relearn everything anyway.
Despite all that, there is something magical about the experience I went through — something that really changed the way I think and the way I learn, in ways that really helped me later on in my career. I think, during my time in school, I might have actually taught myself to fish.
Now, I am certainly not saying a CS degree is the only way to acquire this magical skill of fishing. During my career, I have had the privilege to work with and learn from a lot of smart people who didn’t have a CS degree, and yet they have definitely cracked the same nut.
On the other hand, this is far from a skill that you automatically pick up just by going through a four-year CS program. Sadly, I have also seen plenty of CS graduates who didn’t leave school with this skill and had to struggle a lot when transitioning into industry work.
Nevertheless, since my CS education seems to have helped me develop the magical skill of fishing, maybe I could try to figure out what it actually is and which aspects of my education helped me get there. If we can identify this skill, if we can talk about it concretely, perhaps we could figure out ways to make that easier to pick up or even try to replicate those elements in code schools.
Spoiler alert: I think I might have an answer for you — my education has helped me to develop a framework for thinking about programming problems. But we will come back to that later; for now, I would like to take you on a detour.
Besides Computer Science, I also did a minor in Cognitive Science while a was at school. For those of you who are not familiar, Cognitive Science is the interdisciplinary study of the human mind; in English, it means “a study of how human thinks”.
Sitting at the intersection of Computer Science and Cognitive Science is a field called human-computer interaction, also known by other related names like user experience design or user-centered design.
The best way to tell you what this field is all about is to show it to you.
We recently bought a new trash can in the office. It’s not just any trash can, it’s a smart trash can. It has buttons!
There are two physical buttons on the trash can. One labeled “open” and one labeled “close”. They pretty much do what you would expect — seems pretty straightforward.
But there is a problem. Sometimes, the “open” button doesn’t work; pressing it does nothing. Hm, maybe it’s broken? No problem — there is an indentation above the buttons that allows you to manually open the lid with a finger. That works, but doesn’t that defeat the purpose of a smart trash can?
Eventually, we realized something odd. There is an LED in between the buttons. Sometimes, the LED will turn green — whenever that happens, the “open” button stops working.
As it turns out, the smart trash can is actually a finite state machine. At any given moment, it either believes that its lid is in the “opened” or “closed” position. Naturally, when the lid is opened, the only possible action is to close it. Conversely, when it is already closed, the only possible operation is to open it. The LED is supposed to indicate this internal state — green means “opened” and blinking red means “closed”.
The problem is that this internal state can drift out-of-sync with reality. When someone used the button to open the lid, but decided to slam the lid close by hand, the trash can will incorrectly believe that it is in the “opened” state while the lid is physically closed. When this happens, the next person will not be able to open the trash can using the buttons.
But actually, none of these are supposed to matter, because we shouldn’t even be using the buttons in the first place.
There is an additional sensor hidden between those buttons. The expected interaction is that you would go up to the trash can and wave your hand above it— the trash can will open its lid briefly and automatically closes it for you after a few seconds. The buttons are only there in case you need the lid to stay open for some reason.
Even though this example does not involve a computer, it showed almost all the important principles that makes or breaks a good interaction design. I won’t get into too much details here — if you are interested in learning how to design better trash cans (and user interfaces), I strongly recommend reading The Design of Everyday Things from Don Norman.
What interests me here is the process of how we eventually learned to use this trash can, something Norman calls the human action cycle, a model for describing how humans see, understand and learn about the world. It’s a loop involving a few steps — goal formation, execution and evaluation.
When we interact with an object (or an user interface) for the first time, you generally don’t have a very good idea of how anything works. So, the first thing you do is to form a high-level goal — in this case, I am trying to throw out the garbage from lunch.
The next step is to formulate a plan for achieving your goal based on your fuzzy understanding of the world, and to execute that plan. In our case, you might try to press the “open” button and put your garbage into the trash can.
The last step is to observe the results of your plan and interpret the outcome. Did it work? Did it match your expectations? If not, you go back to the first step and start over, this time adjusting your goals and plans taking into account the learnings from the first time.
Under the hood, we all operate on mental models — our own understanding of how things work. You start with a pretty fuzzy model, but as you repeatedly go through the human action cycle, you continue to pick up new insights and adjust your mental model to match the reality, continuously refining your understanding of the world.
Whether it’s a physical object or a user interface, a good design naturally guides its users into forming the correct mental model and steers them away from the incorrect ones — by making expected interaction obvious, providing appropriate feedback along the way and so on. When a design fails to do that, you will end up with some pretty confused users, as seen in the case of our trash can.
This is sometimes summarized with the user experience iceberg.
The part of the iceberg that sits above water represents things that are visible to your users. Visual things like graphic design, the user of color, typography and your logo makes up about 10% of the overall experience. The interaction is also important — does scrolling and animations feel smooth and natural? This makes up another 30% of the overall experience.
While the look and feel of your UI is what your users sees, most of the iceberg is actually sitting underneath water, hidden away from your users eyes. This represents the user model.
Despite being largely invisible, it actually makes up the remaining 60% of the whole experience. Does the “flow” in the UI matches users’ expectation? Does it give the right cues to help the user develop the right mental model, or does it mislead the user down the wrong rabbit hole?
There are a lot of similarities between designing the perfect user experience and programming. This is perhaps not very surprising — after all, programming a computer to do stuff is a form of human-computer interaction; the source code you are reading and writing is an user interface!
For instance, I think the iceberg analogy applies to programming just as much as it applies to UX.
At the tip of the iceberg, there are visual things like coding style. Underneath that, there is the interaction layer. Does it “feel like” Ruby? Does it follow Ruby conventions? Does it use common idioms found in the language?
But more importantly, the invisible part that sits under water is what makes or breaks the experience — the user model. Does the code flow naturally? Does it do a good job of breaking up different concerns into their own objects and methods?
Just like a well-designed user interface, well-factored code naturally guides the reader into forming the right mental model. In fact, the Ruby community have realized this long ago — we call this “the principle of least surprise”. If your code guides your users to form a different mental model than the one you have in mind, they are going to have a bad time.
So how do we build a good user model in our code? Having good comments and documentation help, but things like good naming, code structure and code organization are also very important.
Convention over Configuration is also helpful here. By establishing a set of common conventions shared by the entire community, we can build a mental model just once and take it with us wherever we go.
But there is an even more powerful that more directly influences the way your users thinks — abstractions.
Abstractions is a very useful tool for managing complexity in computer systems. Computer Scientist John Guttag has summarized its purpose quite eloquently:
“The essence of abstractions is preserving information that is relevant in a given context, and forgetting information that is irrelevant in that context.” — John Guttag
High-level abstractions like Rails are especially valuable, since they allow you to start building from the 50th level right from the get-go. The higher up the stack, the more value you’re adding to your business and delivering to your end-users. As these high-level abstractions have become commonplace, it’s perhaps no coincidence that startup valuations and engineer salary are higher than every before.
While these high-level abstractions are great, the tides are slowly turning against them. Abstractions are getting a pretty bad rep these days. Joel Spolsky, who coined the term leaky abstractions said this in his essay:
“…while these great tools […] let us get a lot of work done incredibly quickly, suddenly one day we need to figure out a problem where the abstraction leaked, and it takes 2 weeks.” — Joel Spolsky
In other words — all abstractions leak.
Many of us have been burned by bad abstractions before. When you get burned, the emotions are so vivid, it leads us down to conclusions like abstractions can never work; they cause us to not understand what we are doing — the only way out is to start from the group up. As an industry, we have disrupted the idea of abstractions and began promoting micro-libraries and “build your own framework” as the ultimate answer.
In my opinion, while all abstractions leak is indeed a correct observation, the way it is being cited these days is really missing the point.
In science and statistics, there is a similar banner slogan — all models are wrong. However, that was not the end of it, the key insight is in the second part of the aphorism:
All models are wrong, but some are useful.
For example, if you studied physics in high school, you were probably taught to ignore the effect of friction and air resistance in your homework.
Now, this is obviously the wrong model — friction and air resistance are real, non-negligible forces that exist in the real world. However, this does not make it a useless model. In fact, quite the contrary — they give us the ability to start forming a good enough mental model to start understanding the world.
This is not just limited to the toy model we made up for high schoolers either, it exists at a wider scale. Even if you do take into account friction and resistance, the Newtonian mechanics model you learned from high school is actually still wrong. There are lower-level models — such as thermodynamics, quantum mechanics or relativity — that offers a higher-fidelity explanation of reality.
However, just because relativity is a better approximation, it doesn’t mean you would want to think about the world in terms of the spacetime fabric when designing a car.
Therefore, even though everyone knows that all models are wrong, Scientists are explicitly taught and trained to build models. The world we live in is too complicated; we will not be able to understand anything or make any predictions if we don’t try to simplify them. The fact that these models are lossy approximations is a feature not a bug.
Abstractions serves a similar purpose in our field — they exists to help us simplify problems and to help us form the right mental model. Just like any other kinds of models, all mental models are wrong. Therefore, even though all abstractions do leak, it is merely pointing out a rather uninteresting fact:
All abstractions leak, but some are useful.
As humans, our cognitive resource is very limited. Since we can only keep so many things in our head, we can quite easily get overwhelmed. Therefore, we need to be strategic about what to focus on. Abstraction is a good hack that allows you to group several related things into a smaller high-level mental objects, freeing up valuable brain slots for other more important things.
Good abstractions help you form the right mental model by establishing clear boundaries, as well as hiding away details that are unimportant to the current task at hand. Of course, whether something is important or not is highly contextual. If you ignore the effect of friction when designing a car, you are gonna have a bad time in the real world.
So, what do you do when they inevitably leak? What happens when the details they are hiding became relevant for your task? What if the abstraction start behaving in ways you didn’t expect?
That’s called debugging, a core part of every developer’s day-to-day life.
One way to deal with bugs is to keep making little tweaks to your code until it works. I’ll admit, I do this myself from time to time — “I probably made a stupid mistake somewhere, I just want to find it as quickly as possible and get back to what I was working on”.
More often than not, you will quickly exhausted all the obvious places to look, and at that point you are just randomly flipping bits and moving code around. This strategy works a surprising amount of time — after all, most bugs are indeed fixed by applying very small patches to the code.
Once the problem ceased to exist, it is very tempting to just move on. However, even if you have arrived at a working solution, fixing a bug this way often means that you have absolutely no idea why things were broken in the first place. This indicates a potential hole in your mental model, and that should be deeply concerning to you.
When working on big codebases, we have to lean very heavily on our internal mental models to keep us from feeling disoriented. These mental objects are often very coarse — they could be anything from “the billing subsystem” to “the backend”, or even “Rails” and “the OS kernel”. Obviously, when you cast a nest so wide, it results in some very leaky abstractions, but just like scientific models, the simplification here is a feature not a bug.
However, since we are leaning so heavily on them, when they are not aligned with reality, the result could be quite problematic. All the assumptions you made along the way could have been wrong, which could jeopardize a whole day’s work, leave behind subtle bugs or even harm your ability make further progress in the codebase. Therefore, when you noticed this happening, you should make it a priority to understand the root cause and make corrections to your mental model.
Now, this is not always going to be your fault — sometimes the abstraction is just poorly designed, just like the smart trash can in our office. Still, bad designs are everywhere, and you can’t always avoid them. Having the ability to notice this and recalibrate your mental model allows you to work around these problems.
If you are lucky, fixing your mental model could be as simple as carefully re-reading the documentation. But more often than not, the only way to figure things out is to dig in, and that requires us to understand the abstraction we are sitting on:
“When you need to hire a programmer to do mostly VB programming, it’s not good enough to hire a VB programmer, because they will get completely stuck in tar every time the VB abstraction leaks.” — Joel Spolsky
Traditional CS education tries to solve this problem with a bottom up approach. In most CS curriculums, you usually start from the bottom-most layer and learn your way up the stack of abstractions.
In your first year, you will probably do a mix of programming, math and computer architecture classes. Once you have these foundations in-place, you can move up to things like data structures and algorithms. In your third year, you may learn about operating system and databases. Finally, in your forth year, you can take all of these knowledge, and apply them to things like networking and information systems.
The nice thing about this bottom-up approach is that even though you rarely have to work directly with the low-level abstractions at the bottom of the stack, should you ever encounter a problem higher up, you will always be able to dig back down into these layers and feel comfortable there.
There is a problem though. Since there are so many different topics to cover, you don’t really have time to build that high during your 3–4 years at school. As soon as you start working in the industry, you will realize that no one actually starts from the bottom layers in the real world. Instead, everyone works with very high-level abstractions like Rails that allows them to build from the 50th level up. Suddenly, what you learned in school seems like a laughably short stack.
Since we are so used to building up from the bottom in baby steps, often spending a whole semester on each layer before moving up to the next, the sudden jump from the 20th level all the way up to the 50th level is just too much to handle for a lot of CS graduates. Many of them fell off the “CS cliff” here and struggled to connect the dots between their education and the industry work they do.
From here, you can draw two possible conclusions.
Option A: high-level abstractions like Rails and Ember are the problem. As you can see, they are hiding so much stuff from you, you can’t possibly understand everything — there are too much magic. Therefore, the solution is to stop pretending we can get away with that.
Instead, you should build your own stack from the bottom-up, using only micro-libraries as components, perhaps even rolling a few of your own. By going through that exercise yourself, it guarantees your ability to understand the abstractions you are building on, just like the good old days in school.
Option B: since everyone builds from the 50th level without understanding most of the things underneath — and they seem to be doing just fine, we must conclude that understanding the low-level details is not actually that important for our job.
Therefore, starting from the bottom-up is useless and a waste of everyone’s time. Instead, we should focus our effort on teaching and learning 50th level abstractions like Rails — which is the approach taken by code schools and bootcamps.
Both sides have made some good observations here, but I think neither of them got the conclusion quite right.
Indeed, building your own stack is a great exercise for understanding the layers you are building on. However, as you dig in, you will realize that these abstractions are handling a lot for you, including things that requires specialized expertise — such as performance and security. On top of all that, there are also meta-problems like documentation, composition and maintainability. Most importantly, there is always going to be another layer underneath your current set of tools, so where does this end?
On the other hand, abstractions like Rails are definitely not perfect. As Joel rightfully pointed out to us, all abstractions do eventually leak. To understand why your queries are so slow, you will probably need a basic idea of how databases and operating systems work. A good understanding of data structures and algorithms is also pretty helpful for intuiting the problems. If you treat all of these as opaque black boxes, you would end up building a tower of awkward contraptions that eventually collapses on you one day.
Where does that leave us? In my opinion, what you actually need in order to survive in our industry is the ability to pop up and down the stack of abstractions as needed.
Regardless of your education background, it is simply not realistic to expect yourself to know everything about the abstractions you are sitting on, and that’s perfectly natural. On-demand learning is totally fine — but you will need a good framework for doing that, as well as not be intimidated by the idea of digging in.
That all sounds great, but how do we get there?
With all of these laid out, I think we are finally ready to discuss education. I would like to argue that the skill of fishing in our industry is the ability to think abstractly.
The ability to work with and author abstractions is a concrete example, but it goes deeper than that. More generally, it is the ability to operate and think in terms of mental models, acknowledge their utility while being mindful that they intentionally omit certain details, and knowing what to do when they inevitably leak.
For me personally, the structure of the traditional CS curriculum really helped me to pick up that skill. By carefully building up from the bottom, one little piece at a time, semester after semester, it helped me to discovery the existence and boundaries of these abstraction layers, as well as how everything fits together to form larger pieces.
Throughout the journey, I was constantly exposed to hard topics that initially seemed unapproachable. Yet, the classes always followed the same pattern — we would start with a few basic principles, building up a little every week, and by the end of the semester everything would come together.
By doing this over and over again, it also gave me a pretty good framework on how to keep learning up the stack beyond what they taught me in school. More importantly, it gave me the confidence I needed to believe that I can dig into seemingly difficult things and know there will always be an answer if I try hard enough.
Now that we have figured out the secret sauce of my CS experience, perhaps we can start thinking about how we could funnel some of these elements back into code school programs.
While the traditional CS curriculum happened to work well for me, none of the things I mentioned are intrinsically tied to a four-year program. In fact, since a lot of CS graduates didn’t leave school with that skill, it probably indicates that we need to do better than just having this implicitly encoded in the structure.
In the spirit of teaching students to fish, the primary concern of any tech education program should be about demonstrating and teaching the framework for learning — the skill of researching and understanding a well-defined but unfamiliar technical topic. The specific set of topics covered in the curriculum are secondary to that goal.
In a traditional university program, students have a few years to come to this realization. Not that it worked out amazingly, but since code school students do not have that luxury, it is even more important that this subtlety is communicated explicitly and upfront.
As a student, it is important to realize that, whatever topics you happened to learn at your school do not matter that much. Since there are always more to learn, the specific set of topics covered in your curriculum is just one of the many possible combinations. In the grand scheme of things, the classes you took are merely fishing exercises; the topics covered in these classes are only important in that they provide context for keeping your learning grounded in reality.
Speaking of context and reality, there is an even bigger problem with the traditional CS program.
Remember the human action cycle? There is actually a broader version of this concept called the hermeneutic circle, which was originally used to describe how scholars study the Bible.
The idea is that, in order to understand the text as a whole, you must first understand the individual parts. However, to understand the the individual parts, you must first understand what the whole text is about.
Therefore, the only way to achieve true understanding is to keep circling between the big picture (things like the historical context and culture), a holistic view of the whole text, and the individual parts. As you repeatedly go through this circle, you will continue to gain new insights and refine your understanding of the text.
This pretty much describe how humans learn about things in general. Most of us do not learn well in a vacuum; in order to achieve true understanding, we need to take the theoretical knowledge, apply them to real-world problems and circle back to learning more theoretical knowledge based on our experience out there.
For a lot of people, spending four years in a traditional university without real-world applications is too long — the circle is getting way too big! When you get to the end of the circle, you already forgot what brought you here in the first place. Learning about compilers might be cool, but it doesn’t really mean much to most people without seeing how that knowledge could be applied to real world problems.
Code school students, on the other hand, have the opposite problem. It is great to have a short cycle, so that you get to apply the knowledge into real-world problems while the memory is still fresh. But once you have done that step, how do you loop back into the next round of learning?
On one hand, with initiatives like iTunes U, OpenCourseWare and websites like Coursera, learning resources are more easily accessible than ever before to a highly-motivated individual. But that’s part of the problem — once you left the schools’ support network, it requires a lot of dedication and determination to keep going. Besides, as a novice, how do you know what to learn next? Do you just try to learn whatever happens to be trending on Hacker News that month?
When I was in school, I enrolled in the cooperative education program where I was expected to spend my summers working at industry internship positions. This allowed me to close the hermeneutic circle much faster and helped me avoid the CS cliff upon graduation.
There are probably similar opportunities to be unlocked in these new-wave tech education programs.
For example, after teaching students about HTML, CSS and jQuery, perhaps they could be put on a short internship to build real-world marketing websites. When they return to the program, they would learn about Rails, then spend some time helping small companies and non-profits automate their workflows — the kind of automation that are usually taken on by convoluted Excel spreadsheets. Then, they could come back to learn about unix, servers, databases for another month followed by an internship at a web hosting company.
Of course, this simplistic straw-man proposal is leaving out a lot important practical details. My point is that by departing from the standard university structure, code schools have even more freedom (and therefore the opportunity) to iterate towards closing the hermeneutic circle.
Before we wrap up, I would like to briefly discuss the social implications of the new wave tech education movement.
Just like Uber and AirBnB, code schools and boot camps are fixing some very real issues. The disconnect between academia and the industry is certainly there, and I’m glad they are here to address the problem. Perhaps more importantly, they are giving a second chance for a lot of people who weren’t so lucky to have figured out what their ideal career the first time around.
But just like Uber and AirBnB, they are also throwing out a lot of regulations and wisdom encoded in the existing system, thus reintroducing some of the problems we already solved before.
For example, most University programs had to go through a somewhat rigorous accreditation process, which sets a basic but uniform standard and expectations among CS programs in different schools.
Now, it far from a perfect system — anyone who has hired college graduates would know that a CS diploma is a pretty leaky abstraction. Nevertheless, it is still useful to have some abstractions, at minimum, it makes hiring and training easier.
Code schools, as they exists today, are extremely non-uniform. Some programs are much, much better than the rest, and some are just downright chaotic. Unfortunately, without any form of accreditation, it is usually not very easy for employers and potential students to tell them apart until it is already too late.
Besides accreditation, we have also decided that it is important to give people fair access to education regardless of their socioeconomic status, which is why we have student loans to help even out the playing field. Although it is also not a perfect system, at the most basic level, it does its job — if you are poor, you can still go to school with some help from the government.
In addition, we have also encoded other important things like anti-discriminatory admission policies and affirmative action requirements in the existing systems. While certain code schools should be applauded being a solution to our industry’s gender and and racial achievement gap, this is by far not a common consideration across the board.
Are code schools and bootcamps just a temporary patch to our labor supply-chain problems, or does it look like they are here to stay for the long term? If so, we might have to start taking the “bath water” more seriously. If this code school thing takes off big times, are we going to accidentally regress on these implicitly-encoded goals as an industry?
Finally, I would like to close this on a more positive note — something a little bit more personal.
As they say, it takes a village to raise a child. This is definitely true in my experience.
Like I mentioned, during my time at SFU, I enrolled in the cooperative education program, which comes with mandatory internship requirements. Along the way, a lot of people have took lots of risk and invested in me before I have anything to prove — without these opportunities, I might have very well fallen off the CS cliff the day after my graduation ceremony.
My CS education didn’t end there at SFU. During my last year in school, I was able to attend RailsConf for the first time via the opportunity scholarship program, which really opened my eyes in and unlocked many opportunities for me. Later on in my career, I became an active open-source contributor, during which my open-source mentors have invested a lot of their personal time helping me level-up, without expecting anything in return.
My CS education didn’t start at SFU, either — I cheated.
I taught myself programming in high-school, so when I went to most of my CS classes, it was already my second or third pass through the hermeneutic circle. Needless to say, that was a huge advantage for me. This all started when I met my first mentor — my computer teacher at elementary school, who spent time outside of school hours and curriculum to teach us how to build websites (and also handed me my first programming book).
Actually, that’s not really the beginning. My CS education probably started when I decided to delete all the system files on my computer out of curiosity as a kid. Instead of getting yelled at, my uncle decided to teach me how to reinstall windows so I could do it over and over again.
But that’s still not all of it.
I wouldn’t be able to do any of these without a supportive family, that tells me it’s okay to explore my interest even though I grew up in a culture where getting top grades from school is the be all and end all of everything. I wouldn’t be able to do any of these if I gave in and let the weight of the education system deprive me of my free time.
I wouldn’t be able to do any of these if I was in an environment where I would get bullied at school for begin a geek, and I most certainly would have given up long ago if I was repeatedly discouraged from doing programming just because I am a girl.
Therefore, Computer Science education is not just about teaching abstractions and programming literacy. It’s also about standing up against bullying, fighting for gender equity and reforming our education system to support our kids to develop their interests rather than just drowning them in homework and exams.
If it takes a village to raise a child, it certainly takes no less than an entire fishing village to raise a 21st century fisherman. You have all made it into the village, which means you probably all have something to give.
Whether you like it or not, the landscape of our industry’s education pipeline is undergoing some revolutionary changes. If you had the privilege to spend four years in a Computer Science program, and if you believe those fundamentals are important, it is up to you to spread to knowledge around. On the other hand, if you managed to learn your way up without the luxury of the well-paved golden path, you are probably in a unique position to help many others in a similar position.
Pay it forward, be the village.