I think there is a bias towards the learning-by-doing approach in Computer Science, often to the point of lazy teaching. I belive learning-by-doing is important, but also that the tutorial/hacking-at-projects culture could use some additional structure, and that beginners would benefit from this the most. By emphasising other approaches and equally important, often-used but rarely mentioned skills, we can make programming more accessible to a wider range of people with different learning styles. This post is inherently subjective and based entirely on my experience, mainly from learning to program and also some experience teaching, so I will readily admit bias :-)
I've often heard, particularly from older programmers, something along the lines of "the saddest thing is a programmer [student] who hasn't done anything outside of their course". I can definitely see the intention behind this sort of phrasing - to encourage people to put their skills into use, tinker, build, explore, learn and master by themselves. It will teach a person how to learn, persevere and ultimately be quite rewarding. Above all, it will give them something to talk about during interviews for internships (or jobs) so that they can recruit someone, who is like themselves in this way.
I think there are, however, a few assumptions underlying this approach which make it infeasible in many situations, especially when starting to learn programming:
- It is unstructured and as a result, slow and frustrating.
- It assumes the project can be built and understood entirely by one person.
- It gives the impression that creating from scratch is the only valued skill in a programmer.
Style of Teaching
For me, learning to program was one of the hardest things I have ever done. There were many factors that made it difficult (choice of language, academic support and coding environment). I will focus here, only on style of teaching.
I often (but thankfully, not always) see tutorials on how to code as a 'monkey-see, monkey-do' sort of endeavour. Some short examples of code are given, usually ending with an open-ended exercise/idea/bold statement to 'go explore'. From these few examples, a beginner has to infer both syntax, semantics, a model of whatever they're manipulating (command-line output, webpage, GUI) and generalisable rules for combining all of them.
God forbid, they have to simultaneously solve a challenging, intellectual problem at the same time - this comes with a whole slew of issues such as (1) "knowing" the answer but not being able to/becoming stuck on how to express it, (2) having to juggle exploring the solution and the environment at the same time or (3) understanding the examples just fine, but not being able to generalise and see how they relate in any way to the problem at hand.
On top of that, a typical student learning this will be time-constrained. Courses can already be packed with other things to learn and it simply does not make sense for a student to spend hours learning a few things through exploration when there are more things to learn in other, more structured subjects in a more structured manner. Anecdotally, this was a complaint I heard often.
I do not have a cohesive solution to this problem, because it is a rather challenging one and others have done a much more extensive job of analysing and proposing solutions (see Chapter 7 of Kinnunen's Challenges of Teaching and Studying Programming at a University examining why a high percentage of students drop out of their introductory Computer Science courses, or simply search for it).
Maybe we can look to how young children learn actual/natural languages: small and simple words and sentences building (slowly) towards longer essays and books? An advantage of this approach would be its emphasis on reading, a very important skill, although without a progressive series of well-written literate programs, a beginner would effectively need someone to read the programs to them in the beginning. More on reading code, later.
I have come to adopt a strategy that seem to work well for me: I prefer books (or longer form, structured tutorial videos or blog-posts) preferably with solutions for many (if not all) exercises. Unlike many tutorial (or a blog-post), books are well structured, edited and usually self-contained/complete and not rushed. They often offer a clear path with well explained examples along the way.
I think a reasonable goal to aim towards here is the same level of structure and clarity in programming courses as you would find in Mathematics, Science or Engineering courses. Each of these fields encourage students to explore for themselves - alternate proofs/theories, experiments or ideas - but only after building a solid foundation of basics first.
One-person projects are not useful
Encouraging novices to write something from scratch all the time doesn't introduce them to the world of style, form, reading, editing, debugging, maintaining or understanding code (unless it's their own code from a few months/years ago...). As is done in a language class, exercises like "rewrite the following in a clearer and more concise manner" or "find the mistake in the following" or simply "what is the author trying to convey here" should become more commonplace - hopefully in equal or greater amounts to exercises asking learners to write code.
Learning that programming is often collaborative and involves good form or style is an equally valuable but often overlooked lesson. Once a student has learned how to express themselves, they should how to express themselves well. Often students learn the basics, but are rarely given comments on their overall form, marked through an automated tester for correctness as opposed to read by an experienced teacher and critiqued and iteratively improved like an essay. Yes, this would be time-consuming but wouldn't it be really cool? Imagine, even teachers could learn inventive ways of structuring code at a larger-scale! Crista Lopes gives a fantastic talk on Exercises in Programming Style at Curry On 2016 here.
While we're being imaginative, students often spend a term or a year learning different novels, poems or plays, analysing literary themes, structure and techniques. Imagine spending a term studying some non-trivial project (a text-editor) and analysing the structure, algorithms, exploring different choices and approaches (for example, a library written conventionally/operationally contrasted with one writen denotationally). You wouldn't expect to produce a good writer by simply telling them to write a lot and do nothing else - no, they must read other's works, be receptive to criticism and even be able to work collaboratively with others. Teach students how to approach bigger projects and they will become more adept at contributing to real-world (open-source 😉) software.
Judging Programming Ability
Not everyone is cut-out for the 'learn-by-doing' independent, rough-it-out yourself approach. It may have been the only way to learn in the days of 8-bit microcontrollers and no internet, but things have changed drastically and both teachers and employers need to understand that they cannot assume the next generation will learn (effectively) the same way they did. That approach has its merits, but like Hackathons, Capture-the-Flags and their ilk, unless a person is already good enough to learn by watching and doing from those around them, they are, at best useless and at worst, demoralising way of exposing people to programming . There are several, equally valid ways of becoming a programmer, and the one you chose is not necessarily the one the person you're hiring or teaching prefers. To assume one is a "better" or a "purer" way of learning than another, can help to reinforce the myth that programming ability is bimodally distributed, by devaluing those who don't learn by writing cool little games, attending hackathons or competing in programming competitions (like me 😊).