I’ve got years, not decades, of experience writing code, so this overview is likely to be lacking in many ways. But people keep asking me this, so I thought I’d write up my thoughs. The idea is for this to be accessible to people new to the field, so I’ve simplified where I thought it would be helpful. For readability I’ll refrain from pointing this out every other sentence. In fact, should you come back to this after having learned more, you might enjoy noticing the points at which I omitted some nuance.

The trusted OED says1

software engineering n. the practice or process of designing, developing, and maintaining software; the field of study concerned with this.

Sounds simple enough. It gets tricky when ‘software’ is the thing making all trades for a financial institution, or the thing (in fact, many things!) that makes it possible to watch videos on the streaming plattform of your choice. Or your operating system. In those cases the software has many different pieces doing different things, sometimes running on different machines that are all constantly talking to each other. In some cases the stakes are very high (people’s lives, or billions of dollars). These are the challenges.

I’ll talk first about the different skills a good software engineer should have. In the second section I talk about how you can go about acquiring them. If you’re just here for a list of resources, feel free to skip to there. When you start building software, you will acquire many of those skills naturally, but you might do so quicker if you go into it knowing what is out there.

Before I get started, a note on terminology. Some people use programing and software engineering interchangeably. I like to think of programing as one of the many activities of software engineering.

What skills does it involve?

I’m going to give a relatively in-depth outline of the skills that software engineering involves. This should not be treated as a TODO list of things to learn. I will give a few pointers2 about that in a later section. This section serves to motivate those pointers.

Programing languages

Perhaps the most obvious one of the lot. Programing languages are how you tell computers what to do. Most user-facing computers3 – like PCs, laptops, or phones – can show images, play sounds, take inputs from you (where you click or tap, what you type, audio and video input, etc.), and talk to other computers via the internet. Programing languages tell the computer exactly which images etc. to show in response to those inputs. There are different ways of doing this, which is why there are many programing languages.

Here is an example program written in the language Python that reads a number from you, calculates its factorial, and prints the result back out to you.

n = int(input('Enter a value for n: '))
n_factorial = 1
for k in range(1, n+1):
    n_factorial = n_factorial * k
print(f'{n_factorial} = n!')

Programing languages are designed by people, based on their (personal, industry, research, …) needs, their personal preferences, and the knowledge available to them at the time of designing them. Some languages are quite old. Java was started in 1990. The first version of C was invented by Bell Labs in 1972. A quick search reveals that assembly languages can be traced back to the 1940s. This is why there is a large variety in programing languages, and things don’t always make sense from today’s perspective.

Also, languages get updated over time to incorporate new ideas, fix old issues or add more functionality. This is why the same programing language can exist in many versions.

And finally, sometimes there are multiple variants of a language that share (most of) the same grammar (the common term is syntax). These are sometimes called dialects of a language. This is not very common.

Programmers tend to have strong opinions on which languages are better than others across a variety of criteria. Learning multiple languages is worthwhile because it broadens your perspective on how computation and programs can be structured and expressed. Understanding the role and context of each language is also valuable because it can help you decide what to learn and is a good first step for building a mental model of the software engineering space.

I suggest starting with learning one programing language (see First steps), and then eventually learning at least one language out of each of the following groups, though of course you should prioritize according to interest/need. The first language listed is my recomendation, but rankings of languages are very controversial (probably most of the next paragraph is).

  • Functional languages: Haskell or Lisp. Completely different from all the other languages. A very clean, mathematical style of programing. Some of the best software engineers I know have a background in functional programing and apply it to how they structure their non-functional programs. Fair warning: functional languages are rarely used in industry, Jane Street who use OCaml are a notable exception.
  • Compiled languages: C++ or C or Rust4. These languages talk very directly to the computer hardware, and force you to manage computer memory. Learning them will teach you how all of that works. Compiled languages are the usual way of writing code that needs to run really fast.
  • Scripting languages: Python or Ruby. These languages are well-suited for writing a small amount of code quickly. This is useful for small projects, tools5, and prototypes/experiments. Python is also the de facto language of data analysis and machine learning, so you will get a lot of mileage out of it. Ruby is aruably the better language. Life be that way some times.
  • Backend languages: Scala or Go or Java. These languages are made for running large code bases with thousands or hundreds of thousands of lines of code. They are good at managing the complexity of such projects. You will inevitably encounter them if you ever work in tech for a larger company. Java in particular is known for being … uhm … slightly clunky6. This category is less useful in terms of learning than the other things, but more likely to be directly applicable to internships or jobs.
  • Web languages: HTML and JavaScript and CSS. These three languages control web browsers to make them display websites (like BBC News™) and webapps (like Calendly™ or Google Docs™). If you want to build those sort of things, and/or want to understand how websites work, these three are essential.

Architecture

By this I mean the physical and software architecture your program will run on, as opposed to the architecture (i.e. design) of the program itself. I’ll talk about the big-picture designing of programs in the next section.

A useful way to think about this is in terms of layers of abstraction. There are many perspectives you could take, for instance, on running the python code above. Here is one way of splitting it up. This is just an example to suport my argument, don’t worry if you don’t understand much of it at this point.

  1. User. You run the program, you enter a number, the program prints the factorial of that number.
  2. Python. The program runs expression by expression. In the first line, input() reads text from the user. int() turns it into a number. In the second line, the variable n_factorial is set to 1. Etc.
  3. Python (deeper). input() and int() are actually library functions that run more python code, and not magic back boxes.
  4. Python interpreter. Python is an interpreted language which means that python code is run by another program called the python interpreter. This is a program running ‘bare-bones’ on top of your operating system (OS). It will analyze (parse) the code to determine it’s meaning, it will keep track of the value of all of the variables, it will talk to the OS to get user input, and it will do all sorts of things to make the code run faster.
  5. Machine code. The operating system translates the executable of the python interpreter into instructions that get executed by the CPU one-by-one. CPU instructions are very different from the high-level operations described in the previous steps. It could, for example, instruct the CPU to copy the value at memory address 0x00000045 to CPU register eax, or to call the function stored in memory at 0x0000002A.
  6. CPU. The CPU will not, in fact, execute CPU instructions one-by-one, but will do some clever optimizations on its own, to make everything run faster. It is also responsible for isolating the OS from programs running on it, so that one program cannot simply take over the entire system.
  7. Circuit level. Hundreds of millions of transistors, composed into logic gates that together form the CPU, RAM, mainboard, etc.
  8. Physical level. Wafers of sillicon with currents running through them. Also some weird quantum stuff. Probably lots of it.

Why should you care? Part of software engineering is that the programs don’t always do what we want them to. In a process called debugging (see later section) we then need to figure out what went wrong. Undesired behaviour of our program can be caused, in principle, by issues on any of those levels. I try to always roughly understand all the layers of the software stack I’m currently using7. Realistically, the deeper down the stack you go, the less likely it is that this is where your issue comes from (this is especially true if you have the experience and freedom to pick a good stack for your project). On the other hand, the more interesting (i.e. challenging) the thing that you are trying to achieve is, the more likely it is you will have to go deep down the stack.

There are other areas of computing architecture that software relies on. One of them is networking, which studies how computers talk to each other, mostly over the internet. Modern software engineering is to a large extent concerned with solving a small to mid-sized computational problem and passing on the results to another computer over the internet. In my opinion understanding networking is about as important as understanding your execution environment, if not more.

The architecture gets more complicated if you work on an enterprise project, where the software will run on a company server or in ‘the cloud’. Architecture in this case will be specific to the project. The same point applies though: Knowing what talks to what, and what runs on what, will make your work much easier.

Design / Maintainability

When you run code, having it do what you want is only one of the goals. As you write a program, you often discover that you actually want it to do something different from what you had originally thought. Maybe you spend a long time working on it, and start forgetting how everything works (this will almost certainly happen if you work on something that’s big enough and is a normal but serious problem to deal with!). Maybe you are collaborating on a project with other people. This imposes additional requirements which I’ll summarize by saying that your code needs to be maintainable. It needs to be easily understood by something else (or you in a couple of months, which is remarkably similar), it needs to make it easy to find problems, and it needs to be easy to change. This is a much broader topic than I can cover here, but it will accompany you through most of your work. Maintainability starts at laying out programming code in a text file neatly and readably and giving names to components of your programs that will make sense to the whole team in a year. Maintainability will also guide how components talk to each other and even how data flows through and between organizations.

This isn’t an exact science, and there is no consensus on how to do it right, which, of course, means that many people have very strong opinions on this subject. My recommendation is to get some coding experience so that you get a feel for how hard keeping your code maintainable is, and then reading some of the classics in the field (see below). Object-oriented programing is a paradigm for laying out programs in suitable languages that is widespread and worth studying, together with its shortcommings. Another popular paradigm is the so called microservice architecture.

To make code quickly readable, languages have style guides. If you stick to them (not religiously, but perhaps 95% of the time), your code will look like everyone elses code, which is good if someone is to help you, and it will tend to be ‘easy on your eyes’. This last point is important, because while programming, you will spend a lot of time reading code. Anything you can do to make that quicker and more pleasant is both a productivity and a quality of life iprovement.

Another technique for making code maintainable is testing, although it does a bit more than that. Testing means ensuring that your program does what it’s supposed to. A common practice are unit tests, which check small components (units) of a program, to make sure they work correctly in isolation. More complex project will require more kinds of tests. How many tests to write exactly is again more art then science, but I’d advise erring on the side of too many tests, and adding more tests in proportion to how fiddly a bit of code is, and how big the whole project is. Testing is another huge topic. First step: figure out what unit tests are and how to write them in the language of your choice. Then figure out how to run them conveniently. Then write lots. (And then think about if you’re spending too much time on the margin writing tests, or hunting for buggs. Adjust your approach accordingly.).

Tooling

Software isn’t developed in a vacum. Instead, engineers have built tools to make it easy to create software. There are a couple of functions that tooling can help with:

  • Reading code. It’s folklore that a programmer spends most of their time reading code. Not sure that’s always true, but it’s certainly a lot. The right text editor can help by coloring in different parts of the program depending on their meaning (known as syntax highlighting), by making it easy to jump around relevant sections of the files comprising a program (the codebase) or by providing hints about the code that aren’t part of the file itself.
  • Reading documentation. Most code editors make it easy to view documentation pertinent to the bit of code you’re working on right now. Besides that, some people use documentation browsers like Zeal to store documentation locally on your machine instead of looking for it on the internet.
  • Writing code. Some common utilities here are autocompletion, which means that the editor will fill in something you have started to write, and refactoring which is a fancy word for making your code neater and easier to work with.
  • Orchestration. This means running the right programs in the right way and in the right order (it’s got the same root as orchestra). Often, when creating software, you will find yourself doing the same things over and over again. For example, you might modify your code, turn it into a progam, copy it to the right computer, run it there, and test if it works correctly. If it doesn’t, you do it again. And again. Whenever you find yourself doing something tedious like this a lot, you should ask yourself if there is a way to automate it. One particularly powerful method of automation is the shell. It is a program which takes text commands to do things on the operating system, like moving, copying or deleting files, processing text, talking to computers over the internet or running programs. Such text commands can be combined into scripts which are tehmselves programs that will execute the commands within in order. Learning to use the shell effectively can be a step change in productivity.
  • Version control. When writing code, you sometimes want to go back to a version from a few days ago. You also want to make regular backups, so you don’t accidentally delete or destroy your work, and so that you can quickly run a program even if it’s not working correctly because you’re tinkering with a new fewautre. And if you’re working in a team with other people, you all want to be able to work on the code at the same time, without constantly copying files around and interfering with each others work. Version control software (which these days almost exclusively means Git) takes care of all of that, by keeping track of all the versions that ever existed of the code at the same time, by allowing you to jump to a particular version quickly, and by merging different versions (e.g. created by different people) intelligently.
  • Finding issues. I’ve already mentioned debugging earlier, and it will get its own section later on. Suffice it to say that there are tools for finding issues in code. Debuggers allow you to walk through a program step by step, and there are other more specialized tools that allow you to find different kinds of issues (e.g. profilers).

A term that you’ll often encounter in the context of tooling is Integrated Development Environment (IDE). IDEs are specialized text editors for code. Some of them, for example Eclipse, Visual Studio or the IntelliJ suite of IDEa (get it?), PyCharm, CLion, IDEa (get it?), try to provide all of the tools I mentioned above in one applicaton. Others, like Notepad++, Visual Studio Code (which is completely different from Visual Studio), or vim, are more light weight, and provide features and integrations with othere tools through plugins.

The first approach hides some of the complexity of what’s going on from the developer, which can be good to start out with. The second approach is more hands on, and gives more control to the developer, which makes it easier to figure out causes of problems, if something does go wrong. However, there is no right answer. Try out different tools from both approaches and see what works for you8.

Finding information

Writing programs requires talking to many different digital components like databases, the file system, scientific libraries, servers, … Nobody keeps all of that in their heads. In order to be an efficient software engineer, you must be able to study up on things you don’t know quickly, in a targeted way. Sometimes it’s appropriate to read the entire manual on something, but much more often you’ll just want to skim it to find the information you need, try it out, and move on. From the moment you realize you need some information to putting it into your program, often less than 30 seconds will pass, and you will do it dozends or hundreds of times over the course of a day of coding. I’d say that this skill involves three sub-skills.

  1. Knowing how to identify good sources of information. If you put something like how to add numbers to a list in python the results are probably going to be terrible. This is because websites can make money by displaying ads. Some websites will take advantage of this. It is in their interest to 1) appear as if they have the information you are looking for but 2) not show you that information for as long as possible, so that you stay on the website for as long as possible looking at ads. Python is a very popular programin language, so there are many people looking for how to do things with lists in python, and it is profitable to try and lead them to your website. Okay, so what can you do to escape this surveillance capitalist hell? In most cases the developers of the tool or language you’re using will point to resources that have been written by the community. They are made to be helpful, and not to make money. If you go to python.org, it should be relatively straightforwrad to find both tutorials and the documentation. Tutorials serve to provide a gentle introduction to a topic, tool, or language. The documentatino lists all of the features of something and is a reference for finding specific bits of information. StackOverflow is a forum with strong community guidelines and is an invaluable resource for finding answers to specific questions. They sometimes aren’t very nice to newcommers, but don’t let that deter you. To go back to our example, in order to find out how to add numbers to a list in python (don’t worry if you don’t know what any of this means), a way to avoid getting bogged down by the attention-sucking dark forest of the internet would be the following search: python list documentation. The official site should be one of the top results. It’s a long article that tells you everything you’d ever want to know about lists. To find what you’re looking for, you’ll have to skim it quickly. A final note: When you’re looking for the solution to a problem because a program you wrote is failing with an error message, you’ll want to throw the part of the errormessage that is universal to everyone encountering it into your search engine in quotation marks. For example, if you try to open the file myfile.txt in python and get the error: FileNotFoundError: [Errno 2] No such file or directory: 'myfile.txt', you’ll want to search for: "FileNotFoundError: [Errno 2] No such file or directory". The quotation marks make sure that you only get results that contain the whole thing, and not things that just contain file or other FileNotFoundErrors.
  2. Extract information quickly from those sources. Manuals, documentation, and RFCs (if you’re fancy) are usually very long, and mostly not worth your time to read in their entirety (although there are exceptions). To work effectively, you’ll want to be searching them, making aggressive use of your browsers text search function. A workflow I recommend (I use firefox, but other browsers have similar features) is to press Ctrl+F, select Highlight all and type in your search term (in our example the possibilities are insert, add, append, put). Then use the PageUp and PageDown keys to look for sections that look useful. (Personally I use a plugin called vimium to use my browser quickly from my keyboard, but learning SWE will involve learning about many things at the same time anyways, so I don’t necessarily recommend you add vimium keybindings to the list right at the start).
  3. Know the right words to use. Programmes will use specialized terminology. You’ll want to try and remember it, since it will make it easier to communicate about your programs, and to find information. The technical term for adding things to the end of a list is append. Also, if you understand python lists enough to know that adding numbers to a list isn’t any different from adding other types of things, you can adjust your search. python append to list will get you much better results than how to add numbers to a list in python.

A note on language. If English isn’t your native language (it isn’t mine), I still recommend learning all the terminology in English, and looking for information in English, because this is where the highest-quality resources are.

Security

Software can have issues, so called vulnerabilites, that allow hackers9 to make it do things it wasn’t supposed to do. For example, they could steal users data and use it to file fraudulent tax returns, or get access to their bank accounts. Or they could get access to company systems, encrypt all the data and then hold the company ransom (so called ransomware).

Some awarenes of how that’s done will help you write software that doesn’t allow that to happen. Also it’s suuper interesting.

Management

Software programs have a tendency to grow bigger and bigger. Even if you are not coding professionally, you will often find that there are more things to do on a project than you have time for. Personally, I have a file called todo.txt with every slightly larger project where I keep a list of things I want to do, and that’s enough for me. When you work for an organization, things get more complicated. I’m not super qualified to talk about this, but one of the things you will eventually encounter is :sparkle: Agile Development :sparkle:. It’s a way of running softwawre teams. It’s not that deep, but consultants try to make money off teaching it to large organizations, so discussions of it often have a weird flair to them. That being said, it’s actually a useful technique. If you plan on working for a company, reading a short summary of the methodology and you’ll be set.

I will (begrudgingly) grant, that there is some wisdom in Agile though, and that is the workflow of continuously iterating on a minimum viable product. It goes like this: If you’ve got a grand idea for building something, think of the minimum thing that will give you some output and build it. Then think of the next complete feature you can add to it to make. Repeat until you’ve got something cool.

For example, if I was writing a plattformer, I’d start with writing a program that opens a window and paints a black background. Then I’d add a white square to it. Then I’d make it so that I can move the square with my cursors. Then I’d make a floor for that square, and add gravity. This breaks down “Make a plattform” into steps I can easily (figure out how to) achieve.

Debugging

A lot of the time when you write a program, it will either not work at all, or not do what you want it to do. At the beginning, most of your time will be spent figuring out how to fix those issues. As you gain more experience with the tools you are using, and with programming in general, you will learn how to avoid the issues in the first place.

If you get an error message and don’t understand what it means, your first course of action should be to throw it in your search engine, as described in th Finding information section.

If you understand what the error message means, but still don’t know how to fix your issue, of if the issue isn’t producing any error message at all, you have two main tools at your disposal

  • Logging. This means printing out information about the state of your program somewhere you can read them and see if it matches your expectations.
  • Using a debugger. A debugger is a piece of software that allows you to attach to the program that you are developing while it’s running, and walk through it step by step, to see if it’s doing what you are expecting it to.

Your goal should be to isolate the exact part of the program where something goes wrong, then figure out why it goes wrong, and then try and fix it.

More rarely, when these don’t work, you might want to result to a different set of techniques:

  • State the invariants of your code and verify them. This is useful only in a very narrow set cases, but in those cases it can be invaluable. This is mostly relevant if your code is doing something algorithmic (i.e. something hard that feels a bit (sometimes a lot) like a maths puzzle).
  • Read a tutorial on the tool you are using. Sometimes nothing works because you are misunderstanding how the tool you are using wants to be used. Reading a tutorial can put you on the right track.

Making it work

I’m not quite sure how to describe this. Sometimes things just really don’t work. This doesn’t necessarily have to be the code you are working on. Perhaps you need to use a library (a collection of software tools for a particular goal) and it Just. Won’t. Install. Sometimes you’ll need to persevere and look for information about it for 8 hours. Sometimes you’ll need to ask someone for help. Sometimes you’ll just need to find another tool for the problem. I guess you need grit, combined with the ability to avoid having to rely on it most of the time.

Here’s a habit that has saved me many (hundreds?) hours of time: Whenever I notice that I’m going down a rabbit hole on trying to get something to work, I ask myself two questions. 1) What is the problem that I’m actually trying to solve? 2) Given what I know right now, what is the fastest way of solving that problem?

Often the answer will be to continue going down the rabbit hole, but more commonly I’ll think of something that is much quicker.

Algorithms

If you study computer science at university, you’ll inevitably end up in a course called Algorithms and Datastructures. If you’re unlucky, it might even be Algorithms and Datastructures I, implying that there are many more modules like this to come (in Sweden, or so they say, that number goes up all the way up to V). What’s that all about, you might wonder?

When you write programs, there are some categories of problems that you will encounter over and over again. Maybe you have a road network / social graph / set of linked documents and you need to find the shortest path / how many friendships away two people are / how many clicks it takes to get from one to another. It turns out that this is all the same problem, and a standardized algorithm exists to solve it.

Algorithms can get very complex and mathematical, so they many smart people enjoy studying them, and thus they end up being taught a lot at universities. They aren’t super useful in practice though, since most of the heavy lifting has already been done by the people writing the tools you use, so I’d recommend studying it if you find that sort of thing interesting, and leaving it alone at the beginning otherwise.

There are three caveats to that, however. The first is that basic algorithmic knowledge is often tested at job interviews (or not-so-basic, if you’re applying for a prestigous place). The second is that sometimes when handling larger amounts of data you will run into performance issues that can only be solved by using a specialized algorithm. You should be familiar with what algorithms exist, and with the concept of computational complexity which will allow you to estimate if a way of solving a problem that you have in mind is feasible or not. The third is that learning how algorithms work is a great way to develop the mental skills you need to reason about computer programs in the abstract.

User Experience

User experience (UX) means designing your programs in a way that is simple for people to use. This is mostly relevant for website/webapp designers, app designers, and developers of desktop applications (i.e. software that actually has a non-technical user at the end of it). I don’t feel qualified to speek to this, but if you work in one of those areas, I’d recommend studying up on the area, including on how you can make sure that the thing you’re working on is usable by people with accessibility needs (e.g. people who move much slower than you, blind people, color blind people, people susceptible to epilleptic seizures, people who find it painful to type or use the mouse too much…).

One thing I do want to say though is that often you will create software that people will have to use. (If you write software for a company, for example, its employees will likely just have to deal with it or quit their jobs, which is really hard for pretty much everyone who does not work in software. If you write a social media app, many people will be socially preassured into using it. If you write an operating system, many people will have to use devices with that system pre-installed. Etc.) Please respect those people. Respect their time, their intelligence, their dignity, and maybe even their privacy.

That’s nice, but how do I learn software engineering?

The good news is that you’re pick up on bits and pieces of everything I mentioned here naturally, when you are creating programs. So the first step is to start making stuff. In order to make stuff, you need two things: a rudimentary grasp of programming, and a thing to make (more on that below). Once you’re in the feedback loop of coming up with cool things, trying to build them, fixing issues along the way, and making your tools nicer, you’re golden. (I’ts like with language learning, where you have to reach a certain level of ability and then can leverage immersion to start learning much more quickly). Once you are there, you might want to read up on some stuff that you wouldn’t naturally encounter, but that will help you. I’ve collected some resources below.

Programing 101

For a starter language, I would recommend Scala. It is modern, conceptually simple and includes paradigms like functional programing and object-oriented programing which are commonly used in industry projects. It is a real language used commercially, it has a nice-ish build environment (suit of tools that help you manage external software components you might be relying on), and it lives in the Java ecosystem, which is widely used in practice. Most importantly, it is a statically typed language (what that means is a bit beyond the scope of this, but essentially you always know what kind of data you are dealing with, and your tools know it to, so they can help you if something doesn’t work). Types are an important concept to understand, no matter what kind of language you end up using. Python, which many people recommend to beginners, is not statically typed, which is why it would not be my first choice (even though I use it daily).

I say I would recommend it, because there’s a caveat: I couldn’t find any good resources for beginning programmers that teach scala. If you can, go for it! If you cannot, my second choice would be Java, because that’s what I did it’s also statically typed, it’s syntax is essentially the same as that of C, C++, Objective-C, C#10… It’s object-oriented which is a thing that matters, it’s got tons of resources, and it will … make you understand why more modern languages exist. If you’re a book person, I can recommend Head First: Java. If you’d rather do a free online tutorial I can’t give any recommendations, but you’ll probably find something decent here. You probably don’t need to spend money. Once you’re comfortable with coding simple programs (e.g. calculators or small games), try to really understand what the Stack, the Heap, and the Garbage Collector are.

I would also like to mention Scratch as a fun and very gentle introduction to computational thinking.

Project ideas

Should be something that’s fun. Like maths & physics? Make a thing that calculates and plots orbits of planets around each other, or write an equation solver from scratch. Project euler is also a classic. Simple video games are also great, because they are fun and you get satisfying visual feedback on changes you make. You could start by getting this snake game to run, understanding how it works, and tweaking it (adding powerups, walls, more colours, a score, multiplayer, …). You could also do something more physical, and do a project on a Raspberry Pi or a BBC micro:bit, which are tiny computers specifically made for helping people to learn how to code.

Further studies

For writing ‘clean’ code that is readable and maintainable and has fewer bugs. Some of these books are a bit … what’s a polite synonym for fanatical?, but many ideas will save you insane amounts of time:

  • Refactoring – Martin Fowler. If you read one book on writing code, I’d tell you to pick this one.
  • Clean Code – Robert Martin. Nothing to add.
  • Design Patterns: Elements of Reusable Object-Oriented Software – Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. How to split your code into pieces that will allow you to hold on to your sanity if the project you are working on gets big.

Other books I’ve read and recommend:

  • Test-Driven Development by Example. – Kent Back. On the importance of testing the code you write. You don’t actually have to write your tests before your code, and you often won’t be able to. Try it out and see what works for you.
  • Programming Pearls – _John L. Bentley__. Fun algorithm problems to think about, and interesting anecdotes from the good ol’ times (long before I was born).
  • The New Turing Omnibus – _A. K. Dewdney__. An approachable collection of interesting things in computer science. Quite theoretical but, as I said, approachable.

Good lists of books (most of which I haven’t read):

  • OSDevWiki: Strong focus on operating system architecture & networking.
  • A list of hackernews posts featuring the word book: Hackernews is sort of a forum where a lot of tech people hang out. A lot of people there are very smart, which impacts the level of discussion. A lot of people there are just procrastinating their work, which impacts the level of discussion.

Other resources:

  • MIT’s Missing Semester: Things you’ll need as a software engineer that you won’t learn at university. You’ll learn a lot from going through this, and they’ve got a list of further resources on their landing page.
  • MIT Open Courseware: “hundreds of MIT courses and educational resources for free.” Not limited to CS, very good. Make sure you do the problem sets if you actually care about learning a thing ;)
  • How Big Tech Makes Their Billions Not directly related to software engineering, but very important to understand if you’re going to work in the industry.

A few notes to finish up.

  1. Many programming resources are presented / present themselves as almost religious texts. Don’t be afraid to ignore advice if it doesn’t work for you. This includes this post.
  2. You’ll need to enjoy some parts of software engineering in order to get good at it. If you learn a bit and hate it every step of the way, you might be better off doing something else. But also, you might just need a different introduction to the subject.
  3. LLMs will probably change how programming is done a lot. Make sure you learn how to use them, how to leverage them fore more learning, and how to programm with them. (Started writing this before shit got real, and I’m as clueless as the next person at this point, but I’m pretty sure I won’t go wrong by saying this is important.)
  1. “software, n.” OED Online. Oxford University Press, December 2022. Web. 6 February 2023. 

  2. Relevant XKCD

  3. There are also non user-facing computers out there. Servers, for example, are computers that mostly talk to other computers. They are what serves you webpages, or videos, or email, … Then there are embedded devices which are also often controlled through programming languages. These are things like the circuit board in a microwave oven, or thermostat, or car, or industrial machine. 

  4. I love rust, of course, but I suspect it’s hard to learn well without knowing C or C++, and without having developed some frustration tolerance on other languages. Happy to be proven wrong! 

  5. Think: a blacksmith making their own tools. This is common. Relevant XKCD

  6. Featuring such wonderful component names as the RequestProcessorFactoryFactory

  7. Not really on topic, but fun. Spectre is a software vulnerability that occured because of how the CPU internally optimizes the execution of operations. Row Hammer is another vulnerability that uses electromagnetic interference between cells of computer memory to change information in unauthorized ways. Relevant XKCD

  8. Personally, I prefer the lightweight variant, and I use vim in combination with various language servers and plugins, and make extensive use of makefiles and the shell. 

  9. I really should say mallicious actors or criminals or something like that, but where’s the fun in that? I live by Starship Iris rules: Never miss an opportunity to say pirate, never miss an opportunity to say hacker. 

  10. Read C sharp, which, apparently, is a pun on music. Because it’s been developed by this company called Microsoft, and they make cute music puns. That’s the only thing worth knowing about them, nothing to see here.