How necessary are the programming fundamentals?
I've been meaning to write an article about computer science fundamentals and how it can improve a programmer's career for a long time, but I always had trouble finding a good way of introducing this topic. The reason I'd like to talk about this is first that, well, I really like this field and I feel that most of my programming ability today is a result of having studied this, but also because I feel like there's a lot of misinformation around this topic and I've been hoping I could address that in a way that could be convincing even for those who can't stand hearing the word "algorithms" anymore.
Developers, and their hatred for theory
The context, for those who are unaware, is that part of the tech community hates this topic so much that they actively fight against it, particularly due to how the interview process of large companies like Google are shaped. When regular-sized companies hire programmers, they usually look for people to perform a specific role on a specific platform (such as iOS development). In this case, it's very common for the interview processes to focus on the practical aspects of these platforms, such as understanding how the platform works at a high-level, the details of certain APIs, and the person's overall ability to work with that platform's tooling.
Traditional large companies, however, focus more on the theory of computer science, asking questions not about what you can do in a specific platform, but about your understanding of the building blocks that allow such platforms to exist in the first place. You are tested for your understanding of the functionality of basic data structures, your knowledge of the fundamental algorithms that accompany said data structures, your ability to explain the functionality and impact of your code in a very low-level/theoretical way (often in the shape of a programming puzzle), and sometimes even your knowledge of your software's underlying layers, such as compilers. The theory we're talking about here is composed of many major fields, but is usually referred to as Computer Science Fundamentals.
The thing though is that these companies tend to run puzzles so hard that even talented engineers would have trouble answering them without preparing in advance. They require you to have extensive knowledge of very specific pieces of theory that are usually unrelated to the position being interviewed for, and while people used to be unbothered by this in a past where we had way fewer layers of abstractions and that the only way you could learn engineering was by going to a traditional college that would require you to study those concepts, in today's modern world where most programmers tend to be self-taught and work with platforms that are extremely abstracted (e.g iOS/Android development) this practice became considered unfair and outdated, and is now heavily frowned upon by the tech community. This interviewing practice is referred to by the community as "LeetCode", in reference to the popular interview training website with the same name where most of these questions tend to be pulled from.
The hatred is misplaced
Bruno, it looks like you agree that this is an outdated practice. So what is it that needs to be addressed?
Yes, I hate LeetCode interviews as much as everyone else. But the problem is that the community misplaces this hate in dangerous ways. The negativity around this interview format became so large that developers today now feel resentment towards the theory itself, even though it has nothing do with with the obscure programming puzzles that these companies employ! To this day this misunderstanding has been causing both beginners and experts to actively avoid learning the theory, which in my opinion is a big career mistake I have seen countless developers regret in the long run.
I believe it's critical for us to separate our disdain for those outdated interview practices from the theory itself, so I've written this article as an attempt to fix this misunderstanding and to prevent further developers from making the mistake of skipping learning the fundamentals.
To do this, I'd like to show you how the theory is used in practice using an analogy, and follow-up by explaining why large companies care about CS fundamentals (despite their outdated interview practices). I hope that this will give you the tools to not only understand how the theory can make you a better programmer, but also to help you determine if this is something you should be studying right now to achieve your personal goals.
This is not an attempt to convince you that LeetCode interviews are a good thing; much to the contrary. At the end, we'll wrap-up by using what we learned to see how we can design better interview processes.
Separating the knowledge from the bad practices
Here are some common complaint points you hear in discussions about computer science fundamentals:
- Theory is useless if you work in a highly-abstracted platform. Why would an iOS developer ever need to know what a graph is?
- Theory doesn't reflect what the person will actually do in their job.
People who feel this way then claim that this field is something that only academics should worry about, and practical programmers should not have to deal with this as part of their daily jobs.
I can see why someone would have these views. If you have never been introduced to this field, it can definitely look like it's all about pieces of obscure knowledge that aren't relevant to the actual role. They are called fundamentals, but you can learn how to code without them. Are they really that fundamental?
Analogy: Becoming a professional musician
To explain this, I would like to draw an analogy with a person's journey of learning a musical instrument. This is because musical instruments are accompanied by music theory, and I find the relation between them to be very similar to the one between programming and CS fundamentals.
Music theory defines the fundamentals of music, providing a theoretical explanation of what things like notes, chords, and scales are, how to find and manipulate them in a particular instrument, and how it all ties together in the songs you hear today.
A person who wants to learn an instrument like the electric guitar will be introduced to the concept of music theory, but also be told that they don't really need to learn it to learn how to play the guitar. Although they will need to learn some of the basics in order to be able to use the instrument, they can generally skip the deeper details if the student isn't interested in that. The student will be perfectly capable to learn how to play their favorite songs, and maybe even play in a cover band with their friends. You may notice that this is very similar to what we see in programming today.
But ask expert musicians what they think of this, and most would say that skipping this knowledge is a mistake the student will regret in the long run. How can this be? If you can learn how to play the guitar without the theory, why would they regret it?
The problem is not that the lack of it prevents you from learning something, but that the student will be making their life harder for no good reason. Although they can learn how to play the instrument, chances are that they won't really have any idea of what they're doing in practice, which will prove to be a constant obstacle in that student's journey.
If the student were to decide to dedicate some time to understand the fundamentals of music, they would greatly simplify their journey, because people who learn music theory are better musicians overall. Even if the student might not be interested in composing their own songs, their understanding of music would greatly speed-up their learning process in general. Why? Because they would understand what they're doing. They will have a much easier time learning how to play new songs and figuring out what they need to do improve further, because they wouldn't require as much external help as someone who didn't study the theory.
Another benefit of learning music theory is that it applies to every instrument. People who understand music theory usually have a much easier time mastering different instruments because most of their knowledge from previous instruments can be applied to new ones. All they need to learn is how the instrument is played.
The same is true for programming
I find that this analogy translates perfectly to programming and CS fundamentals. Just like the musician that knows music theory is generally better at playing an instrument, the programmer that knows CS fundamentals is generally better at coding.
To understand why that would be the case, let's reason about the the role the theory plays in your programming ability. Let's take a look at the first complaint point again:
- Theory is useless if you work in a highly-abstracted platform. Why would an iOS developer ever need to know what a graph is?
Many developers today believe that the purpose of theory is to teach you extremely specific structures and techniques that are pointless for most roles. But again, this is a misunderstanding caused by the outdated interview practices. The theory has nothing to do with that!
Similarly to the music example, the purpose of programming theory is simply to allow you to understand your code. People don't study data structures and algorithms so that they can go and start literally adding them to their projects like those outdated interview practices might imply; they do it because most of the problems we face today are essentially more abstracted versions of those same fundamental concepts, and being able to notice that can provide you with many insights on how your code should be designed. Developers who know theory may not necessarily make less mistakes, but they will have a much easier time finding solutions to difficult problems and determining what they need to study to improve at their work. Just like in the musician's example.
To top it off, similarly to the music example again, CS fundamentals apply to every platform. Developers who know the theory usually have a much easier time picking up other platforms compared to those who don't, because they can seamlessly carry over this knowledge to the other platforms. This is why you'll find that developers who know theory tend to identify themselves as generalists, while those who don't tend to become ultra-specialists in a specific platform or framework. Since they never need to start from scratch, the barrier to learn a new platform becomes quite low, so many end up doing it multiple times over the course of their careers.
You probably already know the theory
The fact that you can become a programmer without formally studying the theory gives people the impression that it's pointless, while in reality, they're using them all the time! I cannot tell you how many times I've heard an iOS developer say "I never needed to use a graph data structure in my job" and then proceed to happily talk about something interesting they worked with involving UIView
hierarchies. These are literally graphs!
Here are some other iOS-specific examples of theoretical programming concepts people claim to have no knowledge of but actually use all the time:
- Graphs/Trees:
UIView
- Linked Lists:
UIResponder
- Hash Tables:
Dictionary<K,V>
and theHashable
protocol - Bit Manipulation:
OptionSet
It can be quite common for developers to not make this distinction between what part of their knowledge is platform-specific and what is actually a platform abstraction of a fundamental structure/algorithm; you as a programmer who never formally studied the theory probably knows a great deal of it, it's just that you didn't know that it was theory. To further solidify the analogy, this also happens with musicians.
I hope that this example was able to make it clear how learning theory can make you a better programmer, but we still have a couple of important points to cover. What about the necessity of knowing this information? Given that we know that developers can do just fine with not having this enhanced problem-solving ability, is this something that you truly need to study to achieve your goals?
Who really needs to learn the theory?
If we go back to the music example, we can say that the necessity of studying music theory in a musician's career will heavily depend on what the musician wishes to achieve:
- Do I want to learn it as a hobby, and never go beyond playing in my couch for fun?
- Do I want to play in a band, and solidify myself as a musical artist?
- Do I aspire to go beyond the mere title of a "musical artist" by living and breathing classical music, becoming an integral part of the Vienna Philharmonic, traveling the world, and going down as a legend that literally shaped the concept of music itself?
It should be clear that our two non-orchestra-dreamer-fanatics don't need music theory, as they can definitely achieve everything they want without it. They can still benefit from it if they want; learning it would allow them to master their instrument, as well as open the door to every other musical instrument. However, from a pure career necessity standpoint, we can safely say that the theory is just a bonus thing they could learn to be a better musician. They don't really need it.
The dreamer, however, has a completely different objective. This person is not looking to simply have fun, they want to be part of a group of people who dedicate their entire lives to perfecting music as an art form. A famous orchestra will not accept some random joe who picked up a violin weeks ago, you must be exceptionally good and versatile as a musician. Even though some professional musicians might argue that even in this case it's technically possible for the person to achieve this goal without formally studying the theory, it's clear in this case how not having a deeper level of knowledge about music would be a major setback in this person's career. In fact, orchestras are so serious that having formally studied music is often a minimum requirement.
Just like in this analogy, the necessity of studying computer science fundamentals in your career depends on what you as a programmer want to achieve. If you learned programming as a hobby and don't really want to work with it, then the fundamentals are not necessary at all. Similarly, if you see yourself working at small startups, then it's also likely that you will not face a situation where the fundamentals would make a big difference. You could still learn it to become a better programmer in general, but from a pure necessity standpoint, you can survive without them.
However, if you aspire to learn multiple platforms, work in a global tech company with state-of-the-art technology and incredibly smart people who are at the top of their field helping them literally define what tech is, then it should be clear to you that even though this is technically achievable with pure programming talent and zero theoretical knowledge (and I'm certain the community can point many who have done so), you'd only be making your life harder by doing so. You would likely have a much easier time getting there if you were to channel your talent into having a deeper understanding of your work.
Why are top-tier companies obsessed with the fundamentals?
To understand why larger companies are so obsessed with the theory, let's focus our attention on the second complaint point:
- Theory doesn't reflect what the person will actually do in their job.
When referred to interview processes this point is correct for obvious reasons; even state-of-the-art projects usually don't require having obscure knowledge on how to make a particular data structure slightly more efficient.
But before we continue, we have another point of confusion that must be separated. Just like I urged you to not treat theory and the infamous interview processes as being the same thing, I'll now ask you to take some time to separate the difficulty of the interviews from the fact that those interviews are themed around the theory. This is because these are also wildly different things; one has a legit practical reason, and the other is corporate hiring bullshit.
The reason the questions are hard and convoluted is because of corporate stupidity. These companies have so many candidates that in order to reduce the possibility of false positives and save time and money, someone decided that the way to go was to make the questions so hard and so specific that if they pass, there's a good chance they know what they're talking about. I believe this was somewhat true 15 years ago, but today, with the existence of numerous platforms that promise to quickly teach you obscure programming subjects for the sole purpose of passing these interviews, this is so detached from reality that it's hard to grasp why they haven't changed this format.
But when it comes to testing theory the itself, you have to keep in mind how these companies operate. While in regular companies you are likely to be hired to perform a very specific role as a specialist, larger companies like Google are almost always focused on engineering T-shapedness and generalism. This means that even though you might be hired to do something specific like iOS development, it's still expected that you'll have the ability to work with different platforms if needed. I work in one of these companies -- even though I work primarily with iOS, there were many cases where a task I was doing involved checking code that was outside of iOS, like a relevant piece of Android code, the functionality of a C++ library, or even writing a new data pipeline inside our backend. This is expected to the point where it's a minimum requirement in promotions after a certain level.
I'd say that the reason why this happens is the nature of these companies. While a regular company is trying to solve a small-scale problem that has likely been done before, top-tier companies have to deal with enormous problems that nobody has ever faced, which often requires them to be masters in multiple platforms. It's not interesting for a company like Google to hire someone who dedicated their life to understanding all about UIKit in iOS -- their problem is not that they don't know which UIKit APIs to use, is that the APIs they need don't exist at all. These problems are not solved by a person's platform knowledge, but by their understanding of computer science and their ability to craft new and efficient solutions.
Another reason why these companies like to test your knowledge of theory is due to what we mentioned previously about how CS fundamentals apply to all platforms. They essentially prove that you can work with anything, so even if you never worked with a certain platform, your knowledge of the theory proves you probably wouldn't have a hard time picking it up.
This is why these companies like theory. While in a regular company you can prove your ability by answering questions about a specific platform, in the larger companies' world of generalists it's your understanding of programming as a concept that proves you're the person they need.
Creating better interview processes
Bruno, you're claiming that the problem with LeetCode interviews is not the concept of testing that you know the theory, but how these companies are making the questions unnecessarily difficult for corporate reasons. How would you fix that?
The simple answer is that I don't know, and at the moment I don't think anyone else knows either.
One important thing you must be aware of is that hiring is hard. No matter how you shape it, it's simply impossible to properly evaluate a person's engineering skill in an hour-long conversation. The only way to do that is to actually hire the person and work with them for a large period of time, and while some people do suggest that this is how hiring could be done in modern times, this would never work for several reasons. First of all, if you don't pay the person, then I doubt any sane person would sign up for this. On the other hand, if you do pay the person, then it would take little to no time for scamming rings to rise and abuse the process.
Second of all, time is expensive both for the candidate and the company. Even though we know that interviewing the person for a large period of time is the only proper way to have a legitimate view of their skills, both the candidate and the company want this to happen as quickly as possible. The company obviously wants this for financial reasons, while candidates want that because 1) interviewing is in general very stressful and annoying, and 2) the majority of people interview for multiple companies at the same time, making it important for them to be over quickly so that the candidate can start more interviews with other companies.
To optimize for these needs, companies opted to make a trade-off between accuracy and time spent. While speeding up the interviews makes everyone happy, it has the immediate consequence that you become unable to accurately measure the candidate's ability, making you need to make an educated guess instead. Because we know it's impossible to make a 100% accurate guess with a heavy time constraint, the most critical component of a good interview process becomes how you can maximize the accuracy of your guess without creating downsides on other fronts.
We know how traditional large companies maximize their guess: they make the interview as hard as possible. However, this artificial difficulty comes with many downsides that we cannot call it a good solution. So what are the good approaches?
From a tech community standpoint, I don't think anyone knows for sure. But I can share some formats that I currently personally believe in.
No trivia
Any question that can be answered with a five second Google search is a terrible question that should be decomissioned immediately. These are referred to as "trivia" and are generally use to describe simple questions like "what is the difference between X and Y?", but I find that most LeetCode-style questions also fall under this umbrella.
The reason trivia questions are terrible is because they say nothing about your engineering ability; they are just measuring how good your memory is, which is a pointless thing to evaluate for a software engineering position because if you don't remember what X API does, you can quite simply just look it up.
The important thing to measure is not what a software engineer knows, but what they understand. These sound similar, but are not the same thing.
Anyone can look up what an API does. But when confronted with multiple possible solutions to a problem, how do you know which one is the best one for your specific case? This ability to reason about a problem and evaluate different possibilities is not something you can just look up on the web, it's an ability that takes years of experience to develop, and is what good interviewing questions measure.
There are infinite ways in which you could potentially test someone's understanding of something, but one particular format that is gaining popularity as of writing is to have an open-ended conversation with the candidate. This is because if you ask the candidate something that has no right or wrong answer, they will be forced to speak from their personal experience, which should tell you everything you need to know about them.
Another reason why this format is gaining popularity is because having conversations is much easier than having to write complex code on the spot, meaning candidates feel a lot less pressure and end up enjoying/appreciating the process more overall.
Here are some examples of such questions:
- Asking questions about the candidate's experience with one of their past projects
- Asking the candidate what they think about something, and having a conversation about it
- Showing a piece of code and asking the candidate what they think the code is doing (here's an amazing example of this)
- Programming puzzles that have multiple possible approaches and right answers, meaning having less focus on the code itself and more on having a conversation about why the candidate went for a particular approach/answer over other ones
No generic questions. Always relevant to the product
In addition to staying away from trivia questions, I believe questions should always be non-generic and related to what the job actually consists of. Some people might think that this would make you unable to evaluate a person's understanding of deeper programming concepts, but this is not the case at all. To understand why, refer back to one of the first points of this article: people often know the theory, they just don't know it's theory. To evaluate a person's understanding of a deeper concept without making it immediately unfair to candidates who didn't formally study theory, all you have to do is wrap the question around something that is familiar to them and make it relevant to your product.
Let's use iOS development as an example and pretend that I want to have an idea if the person knows a thing or two about graphs. The generic way of doing so could be to give them a generic graph data structure and ask them how to search for a node in that graph, but this has two problems. First, as already mentioned, someone who hasn't studied theory would have an extremely hard time answering this question. Second, most people would immediately question what the hell this thing has to do with the position they're interviewing for.
To fix this, we can do two things. First of all, remove all the references to generic terms and replace them with something that is familiar to everyone: In this case, we could simply replace "graph" with UIView
and "search for a node" with "find a subview in the hierarchy".
Second of all, make it relevant to the product: instead of wording it like a general problem, use an actual feature of your app where this is or could be a legitimate necessity as context for why this is being asked. This second step is not always necessary as in my experience simply making it non-generic already does a great job at making people feel comfortable with solving a particular question, but I find that making it relevant makes people actually enjoy the process more as they can see exactly why that particular knowledge is important for the position.
Ask layered questions
In addition to everything we've already said, another thing that seems to have very positive results for both candidates and companies is to always layer your questions. What this means is that instead of having "simple" questions where you get your answer and move on, you should aim to back up every question with multiple follow-up questions that are each slightly harder than the previous one, starting from something extremely easy and ending up with something so hard that only an extremely experienced engineer would be able to answer it properly.
The reason you'd want to do this is because while your candidates will have wildly different levels of experience, chances are you only have one or two set of interview questions. By "layering" questions like this, you gain the ability to measure a candidate's level without needing to have different sets of questions for junior/senior engineers. You can ask everyone the same questions, and then infer each candidate's level by noting at which point they started having trouble answering the follow-ups of each question.
Keep in mind that if you do this, you need to tell the candidate upfront that answering everything correctly is NOT the objective of the interview, because if you don't tell them this, many candidates will mistake failing to answer a follow-up and having failed the entire interview. Since the questions are intentionally designed so that almost no one is able to truly "clear" them, you need to be upfront that you fully expect them to fail to answer at one point. This way they won't feel pressured/nervous when reaching a part that is above their level, which will allow them to perform better.
Moving forward
I hope this article was able to make it clear to you the importance of learning CS fundamentals and how it's important to separate it from our resentment towards bad interviewing practices. While we've seen that almost no one truly requires to study theory in order to have a successful career, I think it's clear how beneficial it can be to do so, so it's important for us as a community to not incorrectly drive beginners away from it.
While I'm certain that some people will still not agree with this article, I hope that this has given you new interesting insights on the practical applications of theory and what we can do to build better interview processes.