A Tech Education
The tech industry is notorious for missing a ladder for beginners. The path from absolute beginner to having deep enough knowledge to make informed decisions when writing software is very unclear, especially if you are an outsider to technical culture. As a woman who has always been outside that culture and had to find my own path, I want to offer an overview of the path I've followed, in a way that others might be able to imitate.
I graduated from university over ten years with a degree in basically philology and the classics. It didn't help me to get a job, but it did give me mental skills that helped a lot with learning programming. If you don't have a similar background, tech will teach you a lot of those skills if you let it, but you would be well advised to be intentional about how you learn. Spend some time learning at least high-school mathematics, and reading a lot of difficult books. You will benefit from the thinking process they require. And that includes reading outside of technology. The best technologists are not narrowly focused on their own domain.
A lot of the advice in this article is frequently discounted as unnecessary for getting a tech job. I argue that this knowledge is still crucial to acquire a sufficiently deep understanding of the technology to advance beyond an entry level.
I will be writing this article in more of an imperative style, as a series of steps that you should take to reach these goals. It doesn't have to be strictly followed step-by-step, but if I were mentoring your learning, these are the steps I would have you follow.
Also note, I will not be going into detail about how to follow each of these steps. I will be describing the steps and their place, and then I will usually link to one or more external sources where you can learn more.
If you can start off working in Linux, or Mac at the very least, and writing your code in a minimal text editor so that an IDE doesn't rob you of the chance to analyse the language's syntax, that would be ideal. But if that's too overwhelming, it can wait until we get to a slightly later section of the learning process.
I have been heavily influenced by Teach Yourself CS and Build Your Own X. They are fantastic resources. Some other guides I have seen that seem to be worth recommending are Roadmap.sh and Starting Systems Programming. Iris Meredith also has a platform which teaches a lot of fundamentals called Arca.
In addition to following this guide, you should experiment as much as possible. You are generally not at risk of breaking anything too serious. Build things that interest you. Follow sections of this guide out of order and use the knowledge to further experiment. Play around in the REPL. Read widely. Tackle hard topics, move on when they're overwhelming, come back to them and try again. That's how I learned so far, and it's been pretty effective. I recommend a big dose of curiosity. A lot of my time on the web has been spent diving into languages like Lisp and Haskell because they fascinate me. Prioritise topics that give you insight into the history of the technology and fundamental concepts, rather than flashy topics like LLMs or blockchain or modern JavaScript frameworks.
This guide is a framework that I may use in future for in-person mentoring or workshops, though I haven't yet worked out the logistics for making that happen. For now, I hope it will help others looking for guidance on which steps to take.
Learn to Code
This sounds like a "draw the rest of the owl" type piece of advice, but it's not. Coding, i.e. the ability to write syntactically correct code in a given programming language, is the most elementary skill.
It's like learning how to write gramatically correct sentences in a spoken language. The ability to form letters by hand and string them together in words to form sentences that make sense is a complex skill. But the sentences you produce with that skill are not exactly interesting. After learning to write, you must learn how to write an informed essay about a topic you have an opinion on, or a novel about characters you've thought deeply about. Writing is the most basic skill. Writing code that compiles is the technical equivalent of that.
So you need to begin by learning to code. That means learning how to set variables, write functions that do what you want them to, have the most basic understanding of how to use data structures, possibly classes, and manipulate program flow. You can go into an infinite amount of depth here, but at this stage, it is sufficient to learn the very basics. You can start with a mainstream language like JavaScript. My personal preference to begin with is Python. Here's a good guide to learn the basics: Automate the Boring Stuff with Python.
Critical Thinking
Now that you've learned how to write some code that works, it's time to start thinking critically about how it works. This might seem like an odd next step. I assure you that without it you will be stumbling in the dark every time you try to write any code. If you take the time now to figure this out, you will learn everything else so much faster.
You need to start by reasoning about how basic standard library functions are implemented. Your implementations don't have to be perfect, secure, performant or bug-free, but the exercise of working out what they do will change how you analyse code.
I don't have a specific guide to link to here. I actually think the process of working this out yourself is invaluable, so I won't take away the exercise. As an example of what I mean, how would you figure out the length of a string if you didn't have access to the length attribute? You would take the string into a function, and, assuming this is Python, you would write a for loop where you increment a variable by one for every letter in the string. If it were C you would just keep going until you hit a NULL character.
This will sound very obvious and not that useful to any experienced programmers reading this. But as a beginning programmer I didn't understand that this was happening and no one explained it to me. When I figured it out, the opacity of the code I was working with went down.
Go on from here and implement functions that split a string, join multiple strings, find the count of an element in a string, return the index of the first occurrence of an element in a string, you get the idea. Keep doing this until it becomes instinctive to reason about how a method or function works when you see it. You don't always have to be perfectly correct when you think about it, and your implementation can be a horribly slow collection of for loops. The important thing is that you think about it. This will break the learner's habit of treating every function as a black box.
Get used to the REPL in Python or the console in JavaScript as well. Try out your solutions as you work iteratively. That's what a REPL is good for. It will teach you a lot.
Now Do It In C
Repeat the above exercise in C. You will first need to learn some basics of C if you haven't already. It's tough to recommend a single resource to learn C online. The famous book simply known as K&R is a good book, but I still haven't fully read it and I certainly didn't find it helpful as a beginner for learning the language. The first chapter asks you to check if a file has matching parentheses, which is the type of exercise needed to start making a language parser. It's a really hard problem to reason about if you don't have exposure to those types of problems, and it stopped me from progressing for a while, so I recommend to leave that book until later, unless you happen to read it and find it easy. If you are willing to spend some money, I have found the resources on Low Level Academy very instructive. It's a lifetime payment that gives you access to a bunch of valuable courses. I haven't tried all of them, but they seem very well structured.
Otherwise, I would suggest that you follow a specific process for learning exactly what you need of the language. First, write down your Python implementation. You should already have one available from the last exercise. Then you should write down what that program is achieving in plain English. Then look up how to perform each step in C. You will easily find guides online about how to print a specific string in C, how to add numbers together, how to return values from a function, etc. Those guides will show you how to include the header files you need in order to print or allocate memory.
In order to progress, you will specifically need to learn several topics. These include, what a pointer is and how to use it, including how to pass one to or return one from a function; the Stack and the Heap in C and how to use them in data structures safely; and how to compile your code for your operating system, including the correct use of header files and multiple source files. Learning to use makefiles will also make your life easier. By this time, learning some Linux will probably help. See the section of this guide on that if you want to use it. I would advise you to search for those concepts online. Give preferences to long answers on StackOverflow and Reddit which describe these concepts, as well as articles from websites with minimal decoration and lots of text. In general you should avoid websites with too much markup or too much of a focus on user-friendliness, especially for topics like C. I actually have W3Schools and TutorialsPoint blocked in my search engine for results relating to C, as they are full of misinformation and don't provide the background that would make sense of these topics. Those resources will keep you dependent by teaching you what to type in a specific case, rather than how to understand the topic as a whole.
Once you have learned enough C to understand how to pass in pointers and receive them back from functions, you will be able to implement these standard library functions in C. This will teach you how to handle memory, in addition to performing the operations with no assistance. It will give you a much deeper understanding of how to use code competently.
At this point you can build a few other tools in C if you feel like understanding more. I built the very basics of a text editor after learning some C, updating a character count, backspacing and moving the cursor. It taught me how to handle growing memory and how to turn off the terminal's input interception. Don't feel like you have to perfect these products, but thinking about how to solve some of these problems will help you understand a lot of the technology you work with in future.
Learn Assembly
At this point you are ready to learn some Assembly. I won't be answering objections here about how hard Assembly is or how irrelevant it is to modern programmers. It will teach you principles about programming that are useful no matter what language you are working with. In your career in software you will see bug reports about overflowing buffers and other vulnerabilities that will only really make sense if you understand the underlying software components. Understanding Assembly clarifies all of this.
The Low Level Academy courses mentioned above include a couple on Assembly. You can also just look up the compiler flags that will output the Assembly version of your C code. Learn the basic structure of an Assembly file for your operating system. Also learn why they are different on so many different platforms (which will also explain why installation downloads for software are different for different platforms).
Don't spend quite as long on Assembly as you have on C. You most likely won't be using it later on, and there are fewer new concepts to learn here if you have already learned about memory and pointers in C. Learn enough to write some loops, some conditions, how to print to the screen, and how to invoke and return from functions.
The really valuable insights you will gain from this are the operations that the computer performs in order to handle variables, functions, and program flow control in Assembly. Once you understand how the Stack changes size for functions, the callstack, how variables are allocated, how pointers are handled, and how program control works, you will understand how every higher level language handles these concepts at the lowest level. You will understand how buffer overflows work, how return addresses get exploited to take control of a system, how memory allocation works, and more. It's really well worth the time.
Linux
You may have chosen to learn some basics in Linux prior to this point. If you haven't already, now is a good time. Create a virtual machine or install Linux on your main machine. Ubuntu and Mint are easy operating systems to use. There's nothing to be particularly afraid of. They can do most of what you need a computer for these days, especially as we do so much over the web. And the experience is invaluable. You can dual boot if you really don't want to give up a more familiar OS. At the very least, create a VM and install Linux there.
I'm not going to link to a specific guide here. There are lots, and honestly, at this point you don't want to follow one single guide to learn Linux. Get used to a lot of online troubleshooting. Get creative. Try out more than one OS.
If you're feeling brave, you can nuke your main computer's hard drive and install Arch Linux, Gentoo, FreeBSD, even all three on the one hard drive. I've done it before. It's a bit terrifying, but the anxiety makes the whole experience very memorable. I highly recommend it.
Learn how to use the command line and get really comfortable in it. Learn a command line text editor like Vim or Emacs. Learn how to install packages and manage users that way.
Learn Web Programming
You don't have to wait until this point to learn web programming, but now is as good a time as any to learn it. You want to get familiar with databases, backend applications, HTML, CSS and JavaScript, frontend frameworks, and the HTTP protocol. You should be able to describe what happens when you send a request from a client browser, all the way through the API layer, backend business logic processing, database updating, through to frontend rendering of the results.
I recommend the book Computer Networking from the Teach Yourself CS guide mentioned above to understand how networking works.
Build a basic blog in Flask with Python or in PHP. Learn how to insert into a database without risking injection attacks. Learn enough JavaScript to create drop down menus, then never use JavaScript again on a website you build without really good justification. Play around with your website's aesthetics and behaviour as much as possible. You can prioritise frontend or backend more, but I wouldn't entirely neglect either of them. You will be weaker as a developer if you treat an entire section of infrastructure as off limits.
Similarly to the exercises you do in C, if you can learn to implement some web functionality yourself, it can be well worth the effort. When I started out, I spent some time learning enough Ajax and JQuery to automatically save the user's typed input on the server while they were typing. These days we would probably use web sockets and some fancy libraries, but learning it this way forced me to solve some interesting problems. Just because these libraries are embarrassingly outdated doesn't mean you shouldn't use them to learn. When everything runs on localhost, you don't run any risks by using them.
Another exercise I did was to create a web app that fetched weather forecast data from the local weather service and track over time how that compared to actual weather data to see the variance. I had to create a long-running service which fetched the API data and processed it locally. Then I had to gather the data and display it using Matplotlib in Python and render a responsive graph to the frontend. It taught me heaps. Find a project like that that interests you and build it.
Additional Projects
At this point we are getting into a series of topics you could learn. You probably don't have to learn all of them, but I have and I wouldn't want to do without any of them.
MicroComputers
Learn to use microcomputers including Raspberry Pis and other chips. You will have to learn some electronics, as well as how to flash programs to real-time operating systems. You will learn how to read and write to pins, which is similar to working with registers in a CPU. It also teaches you a type of debugging which will drive you crazy, and make debugging on the web feel easy by comparison.
I once built a program that would monitor the temperature of a fridge which contained some temperature-sensitive ingredients I was using in the kitchen. When the temperature rose above a certain threshold, the micro-computer would activate a relay which would turn the fridge on. When it dropped below a threshold, it would switch the fridge off again. It transmitted the temperature data to a remote server, which created a graph that I could view on my phone at any time.
The fridge was old and using a relay to switch it rapidly on and off burnt out the engine, but the project was fascinating and taught me so much. Find a project that matters to you and do something similar.
CPU Internals
Follow the Nand2Tetris book, at least for the first half. Learning how logic gates function will build nicely off the electronics from the last section. Learning how to address memory and perform CPU instructions will make sense of everything you learned from coding in Assembly. This will really prepare you to understand the fundamentals of what the computer is doing with compiled code.
Graphics
Learn how to use Pygame and make a simple game of Pong. This will teach you how program windows work, including the coordinate system, which will also make sense of how CSS and HTML work. You will also finally understand the side rulers in word processing programs. Learning the order of drawing will also make sense of graphical glitches such as cascading error windows.
From here you can also learn how to make the most basic digital art program, creating a cursor that draws a circle in different colours, changes size, erazes, and saves the results in a file.
Browsers
Having learned a bit about graphics, you can learn how to build your own browser. This guide is a very valuable resource for that. You don't have to do the whole thing, but once you learn how to draw HTML to the screen and modify it with CSS, frontend programming will make so much more sense. The sections on JavaScript will also help you understand what JavaScript really is, i.e. just a file full of code which gets interpreted by an interpreter in the browser. It will also help you understand why JavaScript can slow webpages down so much.
Compilers
You can learn this before browsers if you want to. It would probably help, as a lot of the work of a browser involves parsing and interpreting text, which is a big part of the work of a compiler too. This guide is excellent. Write a few other projects after that which parse text in your own custom format to really reinforce some of those lessons.
At this point you are probably ready to read SICP and K&R. They are classics for a reason. They are currently at the top of my reading list.
Other
Go to the Build Your Own X list linked above and find more topics that you want to better understand and follow them. Build an HTTP parser, a small server, a database engine, a regex parser, an OS, an emulator, a container. These are all possible now that you have learned these other topics. The rest is up to you and it's a journey without a fixed end.
Conclusion
If you follow these steps, you will reach the point where you can teach yourself the rest and become an advanced software engineer. You can go away and learn some discrete maths or develop your own engines, programming languages, etc. Or just try and specialise in a particular bit of tech that interests you.
Without this knowledge, it is very difficult to understand where to start. This guide isn't going to get you there all the way on your own, which is why I've linked to a number of other resources. My hope is that in combination they will orient you, and allow you to know what to do to get there.
Good luck!