So I was talking to a young person (younger than me, at least) about programming. This person is moving from one technology field to being a developer / engineer / builder. Courage! For this role, I like the word "programmer" myself, because it is pretty narrow and doesn't require the word "software" to be tacked on (as in "software developer" or "software engineer") and it doesn't make too many assumptions about being embedded in a craft or an art, which might be suggested by builder or engineer. (But avoid "web developer" -- there's no discipline.) What might this person do to becoming someone who can program with facility in a professional setting? Here are some ideas. What follows is based on experience (what worked for me): I'm not a big one for "advice" but most of these are also patterns I've observed in others.
Before I proceed, I want to note that if you want to be a computer scientist, it's a whole different game. Attempting to become a computer scientist means that you have to do the work that will enable you to be recognized as a computer scientist. If you want to teach, get that PhD. If you want to work in industry as a computer scientist, I think it is possible to "roll your own" program, but you will want to understand the state of the art in terms of what computer scientists think you should know. For that, study carefully the curricula designed by the Association for Computing Machinery.
I'm proofing this piece, and I'm realizing that there's a message I need to convey explicitly: I love programming. I love the immediate feedback; I love the conversations with other people who also love programming; I love to read beautiful code. I also love software engineering and computer science, but . . . at the end of the day (I am not fond of that expression!) I enjoy working towards code, and working code.
#bias! I don't get to do enough of it these days.
But the key is mastery. Another word for mastery might be fluency. What I mean by that is that one should have at least one general purpose language baked into one's muscle memory. The idea is that when there comes a need to bang something out just to get a feel for an algorithm or technique, there's a language available where your deep knowledge of syntax and the library is never inhibiting the flow of your ideas around the programming topic. Mastery/fluency is about knowing the language all the way down. You might spend some time with Pat Shaughnessy's Ruby Under a Microscope. You want to be able to use
pry and other debuggers. With regard to the ecosystem, you should be able to build a gem and a C extension. Beyond just knowing Ruby, after this focussed cramming, you should become . . . A Rubyist. Ruby should be a tattoo on your cerebrum. Set yourself assignments. Learn what "Ruby One-Liners" and Ruby Koans are, and practice them as finger exercises. Take a look at Rubinius, which is Ruby written in Ruby.
During this phase, I'd also recommend working at a desk, and use a bookstand to keep references open. It can be helpful to have a printed book and a digital version of another resource open on a bookreader or iPad.
The next timeframe is from half-way through the 3-6 month cram course to a longer period going into two years. First read The Pragmatic Programmer and get back to me.
Wow, that was quick. Interesting, eh? That book should make you very hungry for more power. That's what happens now: You can get stuff done but you will probably hit some things where you're just skating on the lake and have little insight into the depths. Don't fall through the ice! These topics might well be pursued through more formal courses. I'd pick a couple of the following topics. I would delay going for mastery in other languages besides your primary and secondary at this point: You want some other flavors to broaden your palate but at this point try and discover the limitations of your languages with regard to these topics.
You probably have a job programming now. In Phase I, you were doing a lot of solo work; but in a professional setting nowadays, programming is a social activity. You'll be pair programming and you'll be writing for others -- so your code must be legible. I've never seen a book that really emphasizes this point, but your ability to be a great programmer will be at least partially conditioned by your skills at working with others, accepting feedback, and correcting your recently-developed bad habits.
By the way, I hereby give you permission to not read whole books. Read chapters and leverage indices. You will also want to build up a personal wiki of definitions, examples, and cross-references to these books. (A great way to make a personal wiki is with Gollum.)
In my experience, great human debuggers are born, not made, but maybe it's simply experience and getting to your 10,000 hours with your language. (I have noticed that there are a lot of articles saying that the 10,000 hours observation is wrong; I wonder how many such people have acquired their 10,000 hours.) Anyway, you need to know your tools. Nowadays, it can help to learn all about the debugging features in an IDE such as IntelliJ's IDEA. However, a person with what I would call "debugger brain" can get a lot done with print statements inserted into code. This tends to break down with code that uses threads; here, your best bet to gain expertise at debugging threaded code is to learn from Java world and Google for "java debugging threads".
The machine. You need to write some code where you get a feel for the fact that there is a machine there: CPU and memory. This could mean writing a lot of C code with The C Programming Language at your side; or it could be about writing some code for a Raspberry Pi. But somewhere along the way you need to get some experience with memory-mapped IO, the use of bitwise operators, and the call stack. If you have the energy for it, you should learn assembly. Here we're thinking about primitives: Without an operating system, how can we control access to memory? How can we simulate doing two things at once? This is a good time to learn tail recursion and some of the other things that come naturally when you exploit the machine's call stack. You might learn how to write C extensions for Ruby.
Data structures and algorithms. Good programmers have at some point or another implemented linked lists, doubly-linked lists, hash tables, binary trees, n-ary trees, and have written some sorting algorithms. Personally, I think doing this in C is the way to go, though having said that, I learned algorithms from Niklaus Wirth's Algorithms + Data Structures = Programs where the examples are in Pascal. The reason to use C for learning algorithms is that in my experience not having classes is a plus and you'll benefit from learning about pointers. At some point, browse at your library Knuth's The Art of Computer Programming. There are two tiers in courses and books on algorithms: There are the ones that define particular data structures and algorithms and challenge you to implement them; you should learn some of the qualities of good algorithm design, and get a feel for computability and get some of the lingo (Big O notation, for instance). A higher tier is proving algorithms. At this stage in your learning, focus on the first tier.
Networking and HTTP. Try Computer Networking: A Top-Down Approach (expensive; might be on the shelf at your library - the 6th edition is probably good enough). It's a textbook, but in this case, I think reading something that is "correct" is a great help. I have found that beginning developers rarely know much about HTTP, and I mean the basics: That requests and responses have headers, how HTTPS works, and so forth. Wikipedia can be very useful with these details.
Distributed computing. For a programmer (as opposed to a computer scientist), it is hard to beat Mikito Takada's Distributed Systems For Fun and Profit. The "Further Reading" section of this book has a nice list of seminal papers that are worth perusing. If you talk to some old-timers, you will find that a lot of their agony is tied up with distributed objects: There's a lot to learn from your older colleagues who are experts at CORBA and RMI.
Unix. My favorite book on Unix/Linux is Bruce Molay's Understanding UNIX/LINUX Programming: A Guide to Theory and Practice. He has a couple of great courses at Harvard Extension. You will also need to become very solid in shell programming. A classic is Unix Power Tools, Third Edition. I keep this book near my desk. A book that deserves a lot of credit is Mark Bates's Conquering the Command Line. Once one starts learning Unix, it's time to learn gdb, ptrace, strace, etc. Another person might recommend a book on operating system design, but I'd leave that for Phase III.
DevOps. Here you need some high-level guidance that is almost philosophical. For that, The DevOps Handbook is great but actually a little dry. Then you need to start building automation for personal projects. You must experience online products like Heroku, but you must also practice building your own cloud-based Linux systems with a tool such as Ansible. Finally, you are going to have to start taking notice of the cloud-based offerings from Amazon, Microsoft, and Google. At this point, it almost makes sense to read a certification book for AWS: There is so much detail that you need to be force-marched through the tools. Another dimension of DevOps is understanding what it means for a system to be in production and be able to scale: The key book is Nygard's Release It! (get the second edition).
And now we reach the rest of your life. You are now well-positioned to take up any book on programming and build it into this mental map. Here are some of my favorites (and I'm stretching the idea of programming here):