1. Pick a Project
First, I start with a project in mind. When I was first learning Ruby, my “learner” project was a miniature HTTP server. For iOS, it was a string figure catalog. For CoffeeScript, I wanted to write some interactive demonstrations of maze generation algorithms. The actual choice of project is unimportant; all that matters is that it be something that I find interesting, and which I don’t immediately know how to do.
It may often be the case that the choice of project is what initially spurred the desire to learn. Maybe you have a web app you want and so you figure you might use it as a chance to learn Rails. Or you wish you had an app on your iPhone, which spurs you to learn iOS development.
But whatever is spurring your desire to learn to program, don’t try to learn it academically. The project is what takes the musty, dusty facts and makes them real. Without the project, you aren’t learning, you’re simply giving yourself a passing acquaintance with some information.
2. Do What you Can
Second, I write as much of it as I can, using the resources available to me. If I’m learning a new programming language, the resources probably include an online syntax reference. If it’s a new framework (like Cocoa, or Rails), I’ll be looking at references for the framework. (Personally, I prefer online references, since they are easily searchable and bookmarkable, but if books are your thing, use what works.) The going is usually very slow at this phase, with lots of false starts and backtracking as I learn what works and what doesn’t. You’d think this would be a discouraging phase, but I actually find this to be the most exhilarating of the steps. It’s all about discovery and exploration.
During this second phase, I also make heavy use of resources like Stack Overflow. I don’t think I’ve ever asked a question on that site, but when I was learning iOS programming, I learned a bunch from the questions other people had asked there, and the answers they got. Similarly, looking at other (open-source) projects on GitHub and elsewhere can help me see how more experienced programmers solved similar problems. The key, though, is to make sure I understand those solutions before I adopt them myself; if I just blindly apply their code, I’m not learning, I’m copying. I’ll never do myself any favors by taking shortcuts I don’t understand.
Note what I intentionally did not mention: posting to mailing lists or forums orIRC and asking for help. I’ve found that these are not so useful to me. For one, unless my question is very specific, the forum or list will rarely have useful responses. For another, if I do have a specific question, I may still have to wait a day or two for a relevant response, and in my experience I’ve often solved the problem already by that time. Which again casts doubt on the usefulness of those forums. Remember that you are almost certainly not the first person in the world to have the particular problem you are encountering: the list or forum has almost certainly seen the question before. Instead of asking, take the time to look for the answer. Only when all else fails should you consider actively asking for help.
3. Divide and Conquer
Third, if the problem I’m tackling is large, I try to break it into small bits first. When I was writing the first version of Net::SSH for Ruby, I was overwhelmed by the complexity of the SSH specification. Instead of trying to write an entire client ex nihilo, I started with a bunch of much simpler scripts that helped me explore the domain and learn it in chunks. For instance, I had a script that just tested connecting to an SSH server, another that went further and negotiated the encryption algorithms to use, and another that went further yet and opened an SSH channel on the connection.
As others will no doubt mention, this is where TDD really shines. It forces you to take the problem apart and think of it in the most atomic pieces. When I was learning how to tessellate a plane using Wythoff constructions, I foundTDD invaluable. I wrote Kaleidoscope almost entirely test-first, and came out the other side with a good idea of how Wythoff constructions work.
When the problem you’re facing has you stumped, see if you can break it into smaller problems that can be solved separately. You may find that the larger problem solves itself in the process.
4. Ask for Feedback
Fourth, I try to post what I’ve learned somewhere, on a blog, a mailing list,IRC, a static web-page, somewhere visible, and ask for feedback. I’ve not done this as consistently as I should have, but when I have, I’ve learned a lot. Several months ago I was learning CoffeeScript and I asked Sam Stephenson to review my code (an implementation of a maze generator). He pointed out a lot of places where my code could be more idiomatic. That was invaluable.
The most important thing to keep in mind is that learning how to program (or how to do anything at all, really) is not going to be an overnight task. Do not be tricked into thinking it will be easy. But just because it isn’t easy doesn’t mean it can’t be enjoyable! Decide it’s worth it, and it will be. In the end, the more you learn, the more you are empowered to accomplish.