Learning to Learn I: the Ready Position
This post is about a learning Ready Position: a state of mind required for the adoption of new practices. A Ready Position is indispensable, especially when learning new behaviours that are either opposed to current behaviour, or refinements of existing behaviours. Best practice in learning programming mirrors best practice in learning musical instruments, where the utility of the 'ready position' is well-established.
i: The role of reinforcement loop practice
To talk about 'ready position' learning, let's start by talking about another kind of learning. 'Reinforcement Loop' learning is the most commonly-used form of learning. Essentially: a learner repeatedly attempts an activity or use of a particular skill in the (sometimes incorrect) belief that they will 'hone' their ability by doing so. This kind of learning has a good place in any learner's repertoire: but it is dangerous, and frequently overused. Why?
Doing is an addictive activity. This is especially true of learning programming: you code something, you see if it works, you modify it, you fix a bug, you get some green tests, you repeat. We program in tight reinforcement loops. This is just like how we play video games: we play a level, we fail a couple of times, we improve through practice, we complete the level, we get some points, or coins, and we repeat. The most 'addictive' of video games are optimised to use this process; that's what makes them addictive.
We can get better at programming by repeating this loop ad infinitum. In particular, we'll learn how to expend less effort when performing common tasks: things that initially require a great degree of cognitive effort (such as setting up a new project) eventually become second nature, and they are done without thought.
In musical instrument training, this is why we decompose complex music into scales, arpeggios, chords, and exercises. We aim to 'free up mental space' for the harder parts: performance, structure, and narrative. So, there is space for this kind of programming practice: especially when the aim is to 'free up mental space' for harder programming problems. These 'harder problems' include design, naming, optimisation, and so on.
Effective reinforcement practice has the following features:
- It iterates around a single focal point (optionally adding increasing complexity without losing focus).
- It typically has a very high standard for 'success' (say, 90% on an assessment, or being able to write a complete program without referencing documentation).
However, ineffective reinforcement loop practice usually fails to decompose the problem accurately, or winds up training a skill in an ineffective or counterproductive way. As we will see, it is better to adopt a 'ready position' before starting the loop, and to keep that loop tight.
ii: The role of ready position practice
Even a technically brilliant pianist couldn't do a complex piece justice if all they practiced were scales. Worse still; if they practice a complex piece repeatedly, they will only develop particular poor habits: ways of making the complex parts easier. Many of these may be detrimental to the performance of that piece, and most will be detrimental to the performance of other pieces at some point or other. At some point, the instrumentalist must develop a practice strategy of stepping away from the piece, of decomposing its parts, of reading about historical performances, of understanding the performance context, and of informing their practice using this information.
This rings true for learning programmers, too. The number one mistake I see our Makers Academy students make is failing to step back from the keyboard. This is understandable: it is hard to break the reinforcement loop. But, as with instrumental practice, it is absolutely necessary if they want to develop the - sometimes counterintuitive - skills necessary to become an effective programmer.
OK, back to the 'Ready Position'. Here's what I propose you practice to become a better programmer, a better instrumentalist, or a better learner in general. Develop the instinct to 'step back' from your activity, and to adopt a state of readiness for self-examination. When you have a better measure of yourself, actively choose the appropriate way to practice the given activity.
A simple way to do this is as follows: write an activity you want to get better at on a post-it, and put it on your screen. For instance, 'debugging'. Every time you start doing that activity (for instance, when you hit a bug), force yourself to sit back from the computer - it's hard! - close your eyes, and notice your thoughts about what you're already doing. Your mind will want to continue the activity - it's a problem-solving machine, and it has a problem to solve. Breathe, and watch those thoughts quieten down. It will take a while, the first time. It gets much faster, and more natural, with practice.
Once your mind is a little quieter, use a rubric, or notes from other programmers, or some other method, to analyse your current activity. For instance; a bullet-point list for self-examination when debugging could look something like this:
- Have I identified the single place from which the bug is arising?
- Have I identified the line number on which the bug occurs?
- Have I identified the exact structure which is causing the problem?
- What modifications could be required to eliminate this bug?
- What modifications could I make to ensure this bug is unlikely to happen again?
- What modifications to the way I write code could I make to ensure I don't make bugs like this in future?
Tick off the rubric as you go. It will initially be slow and painstaking – as I said, the formation of useful habits is often counterintuitive (like starting to eat healthy, or getting regular exercise after being sedentary for a while, or learning to control anger). But, with practice, you will get faster. And you will build positive instincts, not bad habits. Trust me - when you're debugging in an interview situation, it feels good to have cultivated these positive instincts.
We give these sorts of rubrics to students, and our most successful students use them religiously. They even set timers to remind them to stop, adopt a 'ready position', and use the rubric to analyse and modify their process. Even students who have struggled immensely have made significant gains by changing this one approach (despite the fear driving them to 'keep on programming' relentlessly).
There are many effective training methods. Here we've looked at two: reinforcement loop learning, and 'ready position' learning. Most students (by an overwhelming margin) overtrain unthinkingly in reinforcement loops (and often poorly, at least initially - there is such thing as negative reinforcement training!). Develop the practice of adopting a regular 'ready position' until it becomes instinctive when faced with a new challenge, and it will pay off.
The main benefit of the 'ready position' is simple: initially, it helps to avoid entraining bad habits, and focusses cognitive effort on retraining a different approach to a problem. With practice, an instinctive 'ready position' helps to get clarity in even the most complex of situations, and to develop continual awareness of how to select the correct process for a given situation. Executive control over your thinking tools and processes – in cognitive theory, called 'metacognition' – is the most important skill you can develop as a programmer, and as a learner.