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.
My assumption is that the person can do some basic coding in a procedural language like Ruby or Python or Java (possibly JavaScript), but does not yet have the fluency / muscle memory that you see with sophisticated programmers. The person I imagine has been around technology for some time, loves it, and has some hunger.
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.
In my experience, the first priority is to set aside 3-6 months in a personal crash course in one language and one framework, with a secondary interest in another language and a second framework for the purposes of comparison. Some people can do this on the job. But basically, one's brain should be completely preoccupied with the languages and the frameworks. (So . . . Stop reading the 5th book in that fantasy series; stop going out to dinner and eat with your books and computer open; etc.) So the primary might be Ruby/Rails, and the secondary might be JavaScript/React. I'm talking saturation. Obsession. "Programming all the time" should be your motto. I'm going to talk about books a lot here, but I'm thinking about the books being open while you try things out. Think up personal projects; check out some open source projects on Github and hack around. But keep coding. There are some easy ways to come up with personal projects: I could write about that but I'd have to be asked. I started off writing computer games. #workedforme
For languages/frameworks, these specific languages/frameworks -- Ruby/Rails, JavaScript/React would be my choice. The reason for Ruby as the primary is twofold: the Ruby ecosystem has some of the best tools, and the Ruby lineage has some fascinating links to SmallTalk and Lisp. (I grant that at the present moment Python is in ascendancy, but I still believe Ruby is a lovely language for learning.) But my main advice here is to scramble and, as much as possible, become a master in the primary language and framework. For this, you should obtain not only the foundational language texts like Programming Ruby (the Pickaxe) and The Ruby Programming Language but also books like David Black's The Well-Grounded Rubyist and Russ Olsen's Eloquent Ruby. I would very strongly recommend watching Dave Thomas's screencasts on "The Ruby Object Model and Metaprogramming." A gap I frequently see among Rubyists is an insufficient understanding of the standard library; therefore, it's worth it to actually read Part IV of the Pickaxe closely -- there's quite a bit of gold in the examples, some of which are clever. For Rails, you'd want Agile Web Development with Rails (Rails 5) along with The Ruby on Rails Tutorial for a second opinion (and a more interesting emphasis on testing). The Ruby on Rails Guides are also very helpful. I would then supplement this with some of the ecosystem resources like The RSpec Book (its latest version: Effective Testing with RSpec 3). I'm not sanguine about JavaScript being the primary language here, because JavaScript's history is so messy and in reality one is always dealing with cruft. It's possible; I just think that Ruby is more coherent. Ruby is not perfect, though, and part of the learning process here is to get a sharp understanding of Ruby's limits -- and cross-learning with another language can provide that vantage point. I recommend React strictly because of contemporary mindshare; I personally like Ember because its community has a lot in common with Ruby's.
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.)
Testing and Debugging. I already mentioned the RSpec Book. The bad news about getting more sophistication in testing is that testing in most professional settings tends to pick different tools, so you might find that a great book on testing such as Growing Object-Oriented Software, Guided by Tests is a bit hard because all of the examples are in Java. Same for Kent Beck's Test Driven Development. In any case, you'd want to read the chapters (11 and 23) on test doubles in xUnit Test Patterns. I also quite like the blog posts on testing from ThoughtBot at Giant Robots Smashing Into Other Giant Robots. For JavaScript testing in the browser, search YouTube. Testing is about practice. Reading a book will not create the neural pathways to get testing into your fingertips.
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.
Object-oriented programming. For a Rubyist, start with Sandi Metz's Practical Object-Oriented Design in Ruby (a second edition will be out soon). By way of comparison, it is worth making a big effort to learn JavaScript's prototypical inheritance and study the new(er) class model in ES6. There are a lot of resources for this on the web, but it is hard for me to imagine getting smart with JavaScript without reading Crocker's JavaScript: The Good Parts and some of Kyle Simpson's various books.
Functional programming. I'd start by leveraging your already-existing knowledge of JavaScript through a book such as Functional Programming in JavaScript. But, here, we begin to get into territory where you might want to go to your local university and take a course.
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):