Beej's Guide To Learning Computer Science
Beej's Guide To Learning Computer Science
1 Foreword 1
1.1 Audience . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.2 Official Homepage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.3 Corrections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Email Policy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.5 Mirroring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.6 Note for Translators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.7 Copyright and Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.8 Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
3 Growth Mindset 6
3.1 Tenacity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.2 You Gotta Want It . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.3 It’s Not Easy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.4 Chapter Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4 Problem Solving 10
4.1 Understanding the Problem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
4.2 Coming Up with a Plan . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4.3 Coding Up a Solution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.4 Reflect on Improvements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.5 Think Like a Villain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4.6 Use in Interviews . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.7 Cost per Phase . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4.8 Chapter Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
i
CONTENTS ii
8 Debugging 28
8.1 Mental Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
8.2 Reproducing the Bug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.3 Finding the Bug . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.4 Print Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
8.5 Debuggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
8.6 Chapter Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
10 Use of AI 36
10.1 How Not to Use AI as a Student . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
10.2 How to Use AI as a Student . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
10.3 How to Use AI at Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
10.4 AI and the Jobs Market . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
10.5 Chapter Reflection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
Chapter 1
Foreword
Are you getting into Computer Science, or thinking about it? Or maybe you’re in it already. This super-high-
level guide is for you!
I’m not going to talk about how to write code (much). I’ll I’m going to talk about in these roughly 40 pages
is more about how to learn when you’re a nascent software developer.
Now, as much as I’d like to know exactly the way that everyone learns (and manage to wedge that into 40
pages), I, to be perfectly honest, don’t.
What I do have is 40+ years of programming experience (self-taught before college), 20 years of industry
experience, and 8+ years of teaching experience. And a BS and MS in Computer Science.
And I have opinions about how to best way to learn how to program!
Now, let’s get this right out of the way: you might completely disagree with what I have to say here. And
I’m okay with that.
But I have had the opportunity to see students make a wide variety of mistakes. And hopefully I can head
some of these off at the pass for a number of readers.
Students and teachers, alike: if you find something you disagree with or something vital that is missing,
please don’t hesitate to let me know1 so I can improve the guide.
Disclaimer: like with all the guides I write, I’m not the master of the subject. And with a squishy topic like
how humans learn, I’m even less so.
But give it a read and take what’s useful and leave the rest for the boids2 .
1.1 Audience
Undergrad students just getting into programming are the people I had in mind while writing this. So give-
or-take a bit around that target audience. People in high school or just looking to learn how to program are
also probably out there in the audience, as well.
1
Chapter 1. Foreword 2
https://beej.us/guide/bglcs/3 .
1.3 Corrections
I make these guides available for free in the sincere hope that people will find them maximally useful. If
there’s something that’s not maximally useful (or, you know, “wrong”), I’d love to hear about it so I can fix
it in furtherance of my mission.
• Email me4
• Report an issue5
• Submit a pull request6
Thank you!
1.5 Mirroring
You are more than welcome to mirror this site, whether publicly or privately. If you publicly mirror the site
and want me to link to it from the main page, drop me a line at beej@beej.us.
With specific exceptions for source code and translations, below, this work is licensed under the Creative
Commons Attribution-Noncommercial-No Derivative Works 3.0 License. To view a copy of this license,
visit:
https://creativecommons.org/licenses/by-nc-nd/3.0/
or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
One specific exception to the “No Derivative Works” portion of the license is as follows: this guide may
be freely translated into any language except English, provided the translation is accurate, and the guide is
reprinted in its entirety. The same license restrictions apply to the translation as to the original guide. The
translation may also include the name and contact information for the translator.
The programming source code presented in this document is hereby granted to the public domain, and is
completely free of any license restriction.
Educators are freely encouraged to recommend or supply copies of this guide to their students.
Contact beej@beej.us for more information.
1.8 Dedication
The hardest things about writing these guides are:
• Learning the material in enough detail to be able to explain it
• Figuring out the best way to explain it clearly, a seemingly-endless iterative process
• Putting myself out there as a so-called authority, when really I’m just a regular human trying to make
sense of it all, just like everyone else
• Keeping at it when so many other things draw my attention
A lot of people have helped me through this process, and I want to acknowledge those who have made this
book possible.
• Everyone on the Internet who decided to help share their knowledge in one form or another. The free
sharing of instructive information is what makes the Internet the great place that it is.
• Everyone who submitted corrections and pull-requests on everything from misleading instructions to
typos.
Thank you! ♥
Chapter 2
“The illiterate of the 21st century will not be those who cannot read and write, but those who cannot
learn, unlearn, and relearn.”
—Alvin Toffler
What are we learning in school? How to be a Flutter developer? How to be a React developer? How to be a
Rust developer? How to be a JavaScript developer? How to be a C++ developer? How to be a C developer?
How to be a Pascal developer? How to be a LISP developer? How to be a FORTRAN developer? How to
be a COBOL developer?
See what I did there? Besides ask a lot of questions?
Yes, you might be wanting to go to school so you can work on web development or embedded systems in the
latest and greatest languages. And maybe if you’re lucky, you’ll do some of that in school.
But here’s the problem:
1. There are too many technologies to cover in four years.
2. All that stuff is going to be obsolete soon, anyway. See how I added COBOL1 to the list2 ?
So what can you as a student do? There’s no way you’re covering it all.
This is where the main goal comes into play. Your job as a student is to do one thing:
Learn how to solve any programming problem.
Even if you’ve never seen the problem or technology in your entire life.
That’s the whole goal.
Importantly, it’s not to learn to be an iPhone developer or an Android developer or a Go developer. All that
stuff is covered by the main goal. You might not learn Go programming in school, but you’ll learn how to
learn Go programming on your own.
Learn how to solve any programming problem.
That’s it. Everything else is window dressing.
1
https://en.wikipedia.org/wiki/COBOL
2
Joke’s on me. There are still tons of COBOL jobs out there.
4
Chapter 2. The Main Goal 5
Being able to learn things on your own is a required skill when it comes to software development. It’s
really unlikely that your first job will solely use technologies you’ve used in school. And, in fact, recently-
graduated students might be surprised to find out that none of the technologies they’ve used at school are
present in their first gig.
So why on Earth did we just spend four years learning all this crap about operating systems and assembly
language and algorithmic analysis and—?
EERRRNT! [buzzer sounds] You didn’t just spend four years doing that. You just spent four years learning
to solve any programming problem.
And think about it. How would you teach people to solve any problem? Well, you can’t exhaustively teach
them all zillion programming languages3 , frameworks, and techniques. So that’s off the table. And whichever
ones you do pick might or might not be used for a particular person’s job.
So we have to get more fundamental. We have to practice solving problems so many times that we develop
and enhance our problem-solving skills. Because you’re going to be faced with problems in an interview or
at work that are completely unfamiliar. You won’t be able to draw on any specific languages or algorithms
you’ve learned. The one thing you will be able to use is your problem-solving skill.
Finally, there’s a bit of a corollary here: when you’re learning to do something (even if you’ll never use it
at work), don’t cheat. The goal isn’t to learn how to delete the head of a linked list. The goal is to practice
solving programming problems! And just looking up the answer deprives you of that practice. Cheat your
way through all the assignments at school and you’ll never develop the one fundamental skill of software
developers: being able to solve any programming problem.
3
https://en.wikipedia.org/wiki/List_of_programming_languages
Chapter 3
Growth Mindset
This is a tough one for me, personally. I don’t like failing at things, even if no one can see me doing it,
and especially when people do. It knots my stomach and then I say all kinds of bad things to myself that I
wouldn’t ever say to anyone else.
And I do this even though I know it’s a losing game and it contradicts the exact advice I give in this section.
What should I be doing, instead?
Psychologist Carol Dweck1 popularized the term growth mindset.
The gist of it is:
• You can expand your skills with effort
• Embrace lifelong learning
• Challenges are growth opportunities
• Learn from criticism and failure
• Never give up, never surrender!2
That kind of thing.
It’s the opposite of what I tend to do when I lose my bazillionth game of Go3 . How could I have made so
many stupid mistakes? I’ll never be good at this!
But that’s what Dweck would refer to as a fixed mindset. It’s my mistaken belief that no matter how much
I play the game, I’m up against my own intrinsic limitations that I’ll never get past no matter if I study for
500,000 hours!
And when I put it that way, it’s kinda silly. No one can spend 500,000 hours doing anything without getting
better at it.
Lose your first 50 games as quickly as possible.
—Go proverb
So what about 50,000 hours? 500 hours? 50 hours? 5 hours?
Come to think of it, it seems like any amount of practice is going to be an improvement.
Even when you’re completely stuck, you’re still exploring avenues. Even if they turn out to be dead-ends,
you’ve at least learned that they are!
1
https://en.wikipedia.org/wiki/Mindset#Fixed_and_growth_mindset
2
Yes, I’m a Galaxy Quest fan.
3
https://en.wikipedia.org/wiki/Go_(game)
6
Chapter 3. Growth Mindset 7
“Isn’t it the same thing, like ‘flammable’ and ‘inflammable’? Boy, I learned that one the hard way.”
—Woody, Cheers
3.1 Tenacity
“The master has failed more times than the beginner has even tried.”
—Stephen McCranie
I think this is one of the main attributes of anyone who grows to excel at anything. (How’s that for a gener-
alization?)
Who is going to get farther, the person who gives up after a failure, or the person who fails and fails and fails
and fails and keeps getting up, dusting themselves off, and trying again?
This is what separates the exceptional devs from the unremarkable devs. The exceptional devs have had their
asses kicked over and over and over, and they kept attacking and attacking and attacking until they solved
the problem. And they learned something from every single failure.
“I have not failed. I’ve just found 10,000 ways that won’t work.”
—Thomas Edison
And something that’s related here that students might not realize: your instructors failed and failed and failed
and failed, too! Sure, they can live-code the linked list delete in class and have it work on the first try…
except that wasn’t the first try, was it? It was, like, the 100th time they’ve done it. You code up a linked list
delete from scratch 100 times and you’ll be getting it right on the first try, too!
When watching an instructor make something look effortless, you might become disheartened because this
material seems so impossible for you. And you start to think that your instructors and some of your peers
have a natural ability to code that you simply weren’t born with. What magical skill were they endowed with
in the womb that you will never have? (Hear that fixed mindset talking?)
But here’s the secret: there’s no difference between you and your instructors other than the number of failures
you’ve had. You’ll need to fail a lot more to get as good as they are!
Very, very few people are “natural” coders. 99.999% of the rest of us have to work really hard to learn this
stuff.
Relentless tenacity is one of the prime qualities of the top coders of the world.
My brain just shuts down the minute people start talking about it. Imagine something that bores you to tears
that you hate. Now imagine spending four years studying it in excruciating detail.
Speaking for myself and projecting broadly, I think it’s a lot harder to motivate to put in the work to do
something you hate.
I caught a lot of flak on Hacker News for this assertion a while ago. Several people commented that they
hated programming and still managed to have a career at it.
First, that’s a… bummer. But secondly, I still argue that people who love computer science have an easier
time getting their degree than people who hate it.
And the people who seem to be “naturals” are the ones who really love it. They think about computer science
all the time (because who wouldn’t?) and, as such, get a lot of practice in. Rather a lot more than the people
who hate it tend to.
So, while it’s clearly possible to have a career in a lucrative field you dislike, it’s (a) going to be harder for
you than for people who like it and (b) maybe you should consider a field that you do like?
You gotta want it. Do you want it enough to go through the tremendous amount of effort it takes to learn it?
Maybe you hate programming, but you want the money enough. Maybe you don’t care about the money, but
you want to program every second of the day.
Just make sure you have the drive to make it happen.
job might actually get so easy as to be boring. And then you’ll look for another one with new, exciting
challenges to tackle.
Problem Solving
This is an idea completely stolen from the book How to Solve It1 by George Pólya. It’s a book about attacking
math problems. And since computer science is just math under the hood, it completely applies!
Actually it doesn’t completely apply, and I just said that because it sounded so good. But it can be bent into
shape pretty easily. And I recommend reading the book.
So what is it? It’s short and pretty easy to memorize:
1. Understand the problem
2. Plan how you’re going to solve it
3. Code up the solution
4. Reflect on what you could do better
That’s it.
And if you think about it, that’s really just a four-step process for solving just about any problem at all. Is
your living-room light not working? You can solve it with these steps.
“Math ain’t about numbers. If you think math is about numbers, you probably think that Shakespeare
is all about words. You probably think that dancing is all about shoes. You probably think that
music is all about notes. Math ain’t about numbers. Math is about logic, it’s about beauty, it’s about
connections, it’s about how you get from one place to another.”
—Cliff Stoll
Programming ain’t about writing code. Steps 1, 2, and 4 do not involve coding2 . These steps are all in
your head and on paper. I would argue that solving programming problems does not involve a computer.
That seems clearly nonsensical, but that’s where the action actually is! Especially in step 2, coming up with
a Plan. That’s the hard part. That’s why you get paid the big bucks. Anyone can type a program in once the
problem has been solved.
Step 3, Coding it up, is simply writing the solution down. The hard work isn’t writing the solution down; the
hard work is coming up with it in the first place!
Also, you’re unlikely to progress linearly through these steps. You’ll probably have to pop back and revisit
earlier steps from time to time, but hopefully your overall progress is in the forward direction.
Finally, as a student, you must resist the urge to look up the answers. The goal here is for you to exercise
your problem-solving muscles (because no one will hire you as a dev without those skills). Virtually every
problem any instructor will come up with has been extensively covered on the Internet or can be solved by
1
https://en.wikipedia.org/wiki/How_to_Solve_It
2
Sometimes they can, actually, but only to write small, throwaway, exploratory proof-of-concept programs.
10
Chapter 4. Problem Solving 11
AI. Remember that getting the correct answer isn’t the point; the point is to practice problem-solving so that
you can get an answer to any problem that’s thrown at you.3
Let’s explore the steps.
Given the inputs "abc" and "xyz", the result will be the number f319c2c6dcfb.
I coded it up (it was easy since the algorithm pseudocode was given), and it computed the answer
correctly. I added the code to transmit the 6-byte number to the server and that was it.
3
I don’t think AI can solve all problems that get thrown at it, meaning that you’ll still have a job, but they can solve the relatively
basic problems that are commonly used in computer science curricula. It’s 2025 now and we’ll see how well this footnote ages.
4
I could stand to be more wise, myself.
5
Once on a programming challenge website I coded up perfect solutions to two problems that weren’t the one I was meant to solve.
I misunderstood it twice. Took me three-times longer than it should have to get the actual solution in place.
6
This is actually part of your job description as a dev. People will expect and rely on you to do this in the workplace. So don’t be
afraid of doing it; be afraid of not doing it.
7
You didn’t say how to choose who moves first, if it could be played by three people, or that my “X” couldn’t take up more than one
square. For example.
Chapter 4. Problem Solving 12
Except the person writing the server wrote me and said that I was sending garbage.
We had some back and forth, and it turned out they thought the spec meant I’d send a string with those
hex digits in it, and I thought the spec meant that I’d send the raw bytes of the result. The spec was
no help—it was ambiguous and neither of us caught it.
The easiest thing was for me to convert the number to string and send it, so I added that line of code
and the problem went away. But we could have caught it earlier with more careful examination of the
spec.
confident it works. And you can write high-level pseudocode. Bounce your plan off a few rubber ducks9 to
see if it holds water.
Code reviews are fantastic if you can coax someone into taking the time to do it for you. They will make
suggestions for things you can improve, and you can fix them now and remember them for next time. And
you might disagree and not make those fixes; that’s okay, too.
Again, we can leverage AI to help with this. Once you’ve solved a problem and have it working, ask the AI
for suggestions for improvement12 and see if there are any worth following. This technique is effective on
small pieces of code, not large projects, but that makes it a great assistant for undergrad work.
But, very importantly for undergrads, you need to solve the problem first, and only then ask the
AI to help you improve it. Your goal in school training (just like in gym training) is to get a workout
with feedback, not have someone else do the work for you.
Code can be bad in a number of ways. It can be buggy. It can be inefficient. It can have bad formatting. And
it can simply be unreadable. Remember that in order for your code to be maintainable, it needs to be easily
understandable by other humans. Make it look sharp. The compiler might be happy with unreadable code,
but humans shouldn’t tolerate it.
You’re done with this phase never. Well, practically you’re done with it when you give up and decide you’ve
learned enough about improving the code. But you’re probably not going to find the Ultimate Solution to
the Problem Ever because you’re still building your skills throughout your life.
That said, this phase is where a lot of learning happens. This is where you can effectively build your stats
with relatively low effort. And it’s your loss if you don’t spend just a few minutes after a project to take
advantage of it.
At work, this takes the form of a post-mortem, where the people involved in the completed project look back
and study what went right and wrong.
Then when you get to the Plan phase, changes are still pretty cheap. Not free—if you need to make a change,
it might influence other parts of the plan, and those will need to be replanned, or maybe more understanding
becomes necessary.
Next, getting to the Coding phase, now changes are starting to be painful. Maybe a change involves throwing
away and redoing code for thousands or millions of dollars in developer costs. Companies make changes
like this on the fly all the time, though. They just do the cost-benefit analysis and decide if it’s worth it.
Finally, after the code ships, now changes are really expensive. Not only do we have to re-plan, reprogram,
rebuild, retest, and reship a bunch of code, but our customers hate the fact that we’re requiring updates, and
so we have all kinds of hidden secondary costs associated with the change.
From a student perspective, you don’t worry so much about how much money your software project is
going to cost your company. You’re more worried that you’ll have enough time to complete it (along with
everything else—don’t your teachers know you have more than one class?) with a decent grade.
So what you need to do is focus your attention on Understand and Plan where changes are cheap in terms of
time. This will get you the best results quickly and efficiently (and hopefully by the due date) with the least
programming pain.
17
Chapter 5. Breaking Down Problems 18
For example, a carpenter with modest experience might only need to break down building a table into our
second set of steps, above, and not go into such detail.
Like everything, breaking down a problem is a skill, and you get better with practice.
When breaking down problems, think back to our earlier consideration: “This problem would be easy if the
input data were in this form.” That’s a hint that you should break out a subproblem that converts the input
data into that form, thus making the problem easy.
And once you have a subproblem, pretend that it’s the entire problem, just for a bit. Focus closely on it and
see if you can solve it in isolation. If not, ask yourself what would make it easy to solve, and break that out
into a subproblem.
Repeat.
The more you practice breaking down problems and coding solutions, the better you’ll get at it. Soon you
won’t have to break down problems quite as far as you needed to before, and, like an expert, you’ll start
recognizing patterns you can reuse.
However, it’s not always obvious how to break down a problem.
One technique is to imagine a physical manifestation of the thing you’re trying to code. (For example, you’re
writing a sort? Imagine a bunch of alphabet blocks on a table and you have to sort them.)
And then, to push it farther, imagine that you’re teaching a non-technical friend how to solve it. How would
you describe the steps? The conditionals? When they’re done?
If you can physically sort the books on your shelf (whatever “books” are), you can write an algorithm to do
that exact same thing. You just need to break down the steps.
5.1 Pseudocode
One of the bigger tools that devs use to explore ideas is to write pseudocode. This is “code for humans”.
Computers can’t read it. (Though some might argue that Python is pretty close to pseudocode.)
But you can use it to outline steps of an algorithm or process to do a sanity check or just explore how you
might get something done.
You could write some pseudocode to insert a value into an already-sorted list of values.
But that’s not really descriptive enough. We might have to break it down.
Getting there.
And we’re getting dangerously close to being able to translate our pseudocode to real code. Maybe it’s still
unclear how we’re going to shift all the values to the right, and we should break that out a bit more.
Sometimes devs add the pseudocode to their real code as comments and implement the real code under them.
This is a powerful tool to use during the Plan phase. It can really help solidify your thinking on the overall
process.
The best developers have a lot of tools in their belt, and they know how to use them.
So when you find yourself saying, “This language sucks and I hate it compared to that other language that
I love!” consider the use cases for that language that you hate. Because it was created for a reason, and
identifying it can let you know when you should use it.
And since you’re dying to know, my favorite language is Rust.
Or Python. Or C. Or JavaScript. Or SQL. Or AWK. Or Bash. Or… well, it just depends on what problem
I’m solving!
6.1 Be Opinionated
Didn’t I just finish telling you that you should give all languages a fair shake and not play favorites?
1
https://en.wikipedia.org/wiki/Shell_script
21
Chapter 6. Right Tool for the Job 22
2
https://en.wikipedia.org/wiki/Turing_machine
Chapter 7
There are a number of tips and tricks for maximizing your speed of durable learning. Devs know these help,
and yet we stubbornly ignore them all the time.
But just in case you want to get faster at learning, here are a few things that work for some people. No
guarantees; everyone’s different, and you might have your own path that works better.
Music is one of those things. Some people swear by silence or white, pink, or brown noise. Some
people listen to classical music, or electronica, or metal. Do what works for you.
7.1 Flow
Flow1 is a mental state you get in where you’re focused and ideas are connecting freely. There are no
interruptions.
Programmers like to get in flow for maximum productivity.
Here are the characteristics of that state stolen directly from Wikipedia:
1. Intense and focused concentration on the present moment
2. Merging of action and awareness
3. A loss of reflective self-consciousness
4. A sense of personal control or agency over the situation or activity
5. A distortion of temporal experience, as one’s subjective experience of time is altered
6. Experience of the activity as intrinsically rewarding
You’ve probably already experienced this in some aspect of your life. Keep in mind that it can be very
beneficial for programmers.
23
Chapter 7. Hacks and Techniques for Learning 24
What this does is prime your brain with the information. You won’t retain it or understand it all, but your
brain will start chewing on it in the background and will make the project easier to tackle when you finally
get around to it at 9 PM Sunday night.
And when you do start the four-stage problem solving process, the material will seem less foreign and more
approachable.
A powerful variant of this is to complete the Understanding phase early. Don’t need to Plan or Code it up
yet.
Coming back and getting the questions answered later can help build a more complete picture of the systems
you’re working with and make you a more effective developer.
Beginning developers solve programming problems through sheer logic and reasoning.
Experienced devs also use logic and reasoning, but they primarily rely heavily on pattern matching. What
coding pattern do I know that best solves the type of problem that I’m currently facing?
In short, they rely on their interconnected tapestry of knowledge they’ve built up over their years of program-
ming.
As you learn to code, look for ways that the thing you’re learning about now connects to the rest of the
programming world you’ve already explored. Make those connections so you can exploit them later.
But remember to always be opinionated about the feedback you get, and use critical judgment when deciding
whether or not to incorporate it.
Debugging
Before we begin, the best way to debug a program is to not have bugs to begin with. Though we’re only human
and we’ll certainly mak mstakes, the best way to avoid bugs is to adhere to the problem solving framework.
Remember that the programming battle is in the Understand and Plan phases. The more completely and
correctly you complete those phases, the fewer bugs you’ll have when coding it up.
That said, let’s talk about what to do when the inevitable happens.
def foo(n):
i = 0
while i < n:
i = i + 1 + (i % 2)
print(i)
foo(5)
Read the nonsense Python code, above. Mentally compute the output. Then see if you’re right. (I wrote the
code, and it still took me a solid minute to mentally model the answer. But I was right!)
If you cannot “run” the code in your head, you cannot debug. Yes, I’m going that strong. I’m sure some
people disagree with me, but I want to drive home how important this is.
Debugging is the art of finding the part of the code where your mental model of the computation and the
reality of the computation diverge. And then fixing it.
If you don’t have a mental model, you don’t have anything to compare against and you’ll make little progress.
How do your improve your mental model of computation?
• Study code. Trace through it. There’s a ton of code out there to practice with, e.g. on GitHub, on
HackerRank, your peers’ codebases, your own stuff that you wrote four months ago and have forgotten
how it works, etc.
• Predict the output. As you learn the code, try to predict how it will behave when run.
28
Chapter 8. Debugging 29
• Manually trace a run. Use a whiteboard to manually track what values variables take on, what
functions get called, and what line of code is executing.
• Write a specification. Study some code and “reverse engineer” it. Figure out what it does, then write
a human-readable spec that perfectly describes the algorithm or codebase to the degree that a reader
could reimplement it from scratch.
• Single-step through with a debugger. Have the computer show you how the program is flowing.
We’ll talk more about that, below.
You’ll definitely improve this skill with practice.
Therefore you know the bug is somewhere between the input and the output.
You could just start changing random things in the code to see if it gets fixed. This is sometimes called
shotgun debugging or prayer debugging, and it very, very, very, very, very rarely works. Way more often
you’ll just mess things up and make the problem even harder to find. It’s like trying to fix your car’s electrical
issues by randomly adding and cutting wires. It’s not even worth debugging this way.
And yet despite that, it’s a very common technique practiced, in vain, by students worldwide. You, however,
should not use it.
Instead, it’s time to be systematic. Somewhere in that pipeline of computation the intermediate computed
values diverge from your mental model. Your job is to find out where.
So you start probing inside the program at various points to see where things go off the rails. Binary search
is great—jump to the middle of the process and examine the values during a run (see below). If they are as
expected, the bug must therefore be between the middle of the program and the end! You’ve just halved your
search space. Now do it again until you narrow it down far enough to see the bug.
I would contend, though some might disagree, the bug is not found until you understand it. That is, you
must understand exactly how your program was giving the output 299792458 instead of the expected 3490.
Gaining that full understanding has a number of benefits:
• You can be more confident you’ve fixed the bug for-realsies.
• You will learn to recognize the patterns that led to this bug, allowing you to better avoid it in the future.
• You’re working out your problem-solving skills while you do this.
Once you understand how the wrong output was produced, then decisively and correctly fix the issue, and
know why the fix will work.
Finally, if you’re just filing a bug report (i.e. someone else will fix it), being able to give them the minimum
steps needed to repro will make you their hero for the day. Consider it from the reverse perspective; would
you rather fix a bug with a vague, long sequence of steps to repro, or one with a few steps that caused it to
repro every time? The more specific things are, the happier the bug-fixer is, whether that’s you or someone
else.
print("A")
x = foo()
print("B")
if x == 3:
print("C")
x *= 2
else:
print("D")
bar()
Chapter 8. Debugging 31
print("E")
Notice that when I run the code, I can see how far it gets before a crash, and I can determine if x were
3 or not.
process_sensor_data(data)
Don’t f---ing use profanity in your debugging statements. Murphy’s Law says that if you do use
profanity, you’ll forget to take it out, and even though it was in some part of the code that you’re
certain will never run, it will inevitably pop onto the screen while you’re doing a client demo with
your boss on the day he’s assessing you for a raise.
I know as well as anyone how infuriating programming can be. And when I’m feeling that way and
forget to take a deep breath and recenter, I print this:
print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
Not only does it stand out nice and clear on the screen, but it’s really easy to type in frustration and
helps dispel some of my bad energy. And if the client sees it, it’s a minor transgression.
Another friend of mine suggested printing various non-offensive emojis, as well, which seems like a
fun way to diffuse ones frustration.
Now, print debugging is kinda frowned upon as a lesser means of debugging compared to using a real debug-
ger (as in the following section). But everyone does it at some point or another, and some people even swear
by it.
The place that I think it really shines is when you need to gather a lot of data about the run to see a larger
pattern emerge, or when you need to catch an infrequent event. If something happens one run in 10,000, single
stepping through with a standard debugger is going to take forever. You can add some print statements and
script a run 10,000 times and watch the output to see when it manifests.
One thing to watch out for is that if you’re printing a lot, it can be tough to visually parse the output, and
error messages might be lost in it. I’d recommend redirecting the output to a file and then bringing it up in
an editor to search.
And, finally, don’t forget to remove all your print statements before you ship your work!
8.5 Debuggers
Debuggers are tools that help you find bugs. There are many different debuggers, but virtually all of them
share a common set of features. The main features are:
• Add breakpoints where the program will stop running and you’ll get control in the debugger
Chapter 8. Debugging 32
1
https://en.wikipedia.org/wiki/Integrated_development_environment
Chapter 9
The first language you learn is the hardest. Not only are you learning the language, but you’re also learning
the concepts that are used within the language. By concepts, I mean things like how to organize functions
and pass arguments, how to run loops, how to do conditionals, etc.
All languages have these same concepts (more or less—more on that later), and so learning the second
language is just learning how to apply those same concepts you already know.
It’s like if you already know Spanish, learning Italian isn’t that big of a jump.
This chapter is about learning additional languages after you’ve learned your first one. This is important be-
cause you’re going to be learning new languages your entire career. Luckily, though, learning new languages
it itself a skill, and the more new languages you learn, the easier it becomes.
There are two big pieces to learning a new language in a paradigm you already know (procedural, object-
oriented, functional, etc.)
1. Learn the syntax. Like if and while, and how to declare variables and functions, etc.
2. Learn the standard library. This is the built-in functionality that you can take advantage of, like
reading and writing a file, or printing to the screen, or connecting to a web server.
Learning the syntax is often the easier of the two. Most languages have relatively simple syntax.
By analogy, you can learn what verbs, nouns, and adjectives are, and how to diagram sentences1 . But that’s
not enough to write a masterful literary work. You also need to know what words you have at your disposal.
And that’s the more complex part. Many standard libraries have a lot of built-in functionality. Scroll through
the Python standard library for an example2 .
fn main() {
if (1 == 2) {
println!("Something is horribly wrong.");
1
https://en.wikipedia.org/wiki/Sentence_diagram
2
https://docs.python.org/3/library/index.html
33
Chapter 9. Learning a New Language 34
} else {
println!("That's correct.");
}
}
$ rustc foo.c
warning: unnecessary parentheses around `if` condition
No, they aren’t! It’s a toy program; we’re just using it to learn.
To learn all the necessary syntax, take the concepts you already know and look up how to apply them in the
new language.
• The main function
• Variables
• Conditionals
• Loops
• Classes
• etc.
It will be frustrating to you at first because you have to look up every. Single. Thing. Like with a new human
language, you know conceptually that you want to go to the supermarket, but you have to look up all those
Italian words if you don’t know Italian.
The good news is that the syntax of a computer language is way simpler than a human language. And you
can get it down pretty quickly.
My main piece of advice here is to use a lot of examples to see how that language performs basic tasks. That
is, gather and study a lot of toy programs.
Then come up with related challenges (or find some online, or ask an AI to generate some) that allow you to
work out to build your skills and find gaps in your understanding.
4
https://en.wikipedia.org/wiki/Health_(game_terminology)#Hit_points
5
https://en.wikipedia.org/wiki/Programming_paradigm
Chapter 10
Use of AI
As of this writing in 2025, AI is the new hotness1 . Everyone is using it, and no one can stop talking about it.
The question no one seems to have an answer for is what’s going to happen. Sam Altman2 and others will
tell you that AI is any second now going to take over the world and solve everything and humans will be
rendered obsolete.
I like to think that will not happen, and that even if AI starts solving everything, people will still want to use
their ingenuity to push the envelope farther than AI is able to.
What does all that mean for you as a computer science student (as of this writing)?
Let’s talk about how you should use an AI as a student and at work, because those are two different things.
But before that, let’s talk about what you’re not supposed to do.
36
Chapter 10. Use of AI 37
I want you to name an activity that, aside from being at the gym, involves lifting weights all day. Answer:
there are none (generally speaking for the majority of the population). Then why do we spend time lifting
dumbbells at the gym if there are zero other activities that involve it?
The weights, of course, are just tools we use toward the greater goal of being generally stronger.
School is exactly like this. The programming problems you get in school are dumbbells. They’re not real.
They’re designed to give you a workout so that when you get to the job, you have the strength to do the work.
And because the problems aren’t real, AI can solve them all really easily. There’s tons of training material
out there for them to learn from.
But don’t be fooled. Just because AI can solve your school problems doesn’t mean it can solve the real-world
problems you’re going to face in your work. (As of now, it can’t.)
(And if it could solve all those problems, how much do you think devs would earn? There’s a reason being
a dev pays well, and it’s because the work is hard. If it was as easy as typing in an AI prompt, it would pay
minimum wage. That should clue you in to the fact that if all you can do is prompt AI, you’re not getting a
high-paying gig.)
But that’s not to say you shouldn’t get good at using AI; it’s just that while you’re a student, you have to use
it the right way to maximize your skills development.
The TLDR of this section is this: never ask AI to solve your entire programming project. It probably can do
that, but you’ll learn nothing. The goal of the project is not to complete the problem; it’s to get a workout
while you complete it.
I’d mentioned earlier that new devs solve problems with logical reasoning, but experts, in addition, recognize
patterns. As a more-experienced dev, you have a better understanding of which building blocks make up a
problem. You recognize the pieces that you need, and you logically reason about how to assemble them.
In other words, experienced devs are better at Understand and Plan. (They’re better at all phases, but recall
that Understand and Plan is where the battle is.)
As such, they can leverage AI to help them write the code for those building blocks. They can say things like,
“I need to filter those results for anything that matches this regular expression”—and then they ask an AI to
code up that building block, they expertly verify that the code is correct and modify it to suit their needs, and
then move on.
Even with technologies they aren’t familiar with, this can help them get the job done. But they still need
to rely on their expertise to know when they need to learn more. That is, experienced devs have a nose for
dangerous code and know when they need to proceed carefully and gather more knowledge.
In this regard, AI can be really useful for doing proof-of-concept work and rapid prototyping where the code
is often throwaway.
“Let us hurry! There is nothing to fear here!”
“That’s what scares me.”
—Satipo and Indiana Jones, Raiders of the Lost Ark
Again, as a student, you can’t bring that experience (that you haven’t yet acquired) to bear, and if you just
try to use AI like a seasoned dev, you’re going to have buggy, fragile code that you don’t know how to fix.
And worst of all, you won’t be developing the skills you need.
But as you gather more experience, you can definitely rely on AI to write a large amount of boilerplate code
for you that you already know the logic behind, anyway.
But the catch is that everyone has access to the same AI and they can all make the same request. Where does
that land us? We’re back to square one where we’re on equal footing.
As a capitalist, though, I don’t like equal footing. I want to get an edge on my competition. So I start thinking,
“What can we do that’s slightly different than what the AI is telling my competitors?”
And just like that, humans are back in the game!
I think that trend’s going to continue, maybe forever.
What will happen, I predict, is that the easy boilerplate jobs that exist now will experience a massive tighten-
ing. AI can solve lots of those easy problems, and you don’t need a big team of engineers behind them. The
more novel problems will still need a lot of human work.
But maybe not as much work as before. AI can help in a variety of ways, outlined above, so it helps speed
things up.
Going back in time, consider when most programs were written in assembly language5 and it took a lot of
specialized knowledge to get these error-prone programs written. And then compilers became popular and
now no one6 writes in assembly any longer; those jobs are toast, destroyed by the faster, easier coding that
compilers afford.
In short, I think we’re going to keep pushing it, and AI will become a very useful tool, but only with humans
at the helm. I think. We shall see.
“And… Always look on the bright side of life…”
—Lead Singer Crucifee, Monty Python’s Life of Brian
5
https://en.wikipedia.org/wiki/Assembly_language
6
Well, a few people do. You should try it for fun. It’s something else.
Index
Interviewing, 15
Juggling, 8
40