In the Peak book, the authors describe the following learning challenge in a section called “Getting Past Plateaus”:
When you first start learning something new, it is normal to see rapid — or at least steady — improvement, and when that improvement stops, it is natural to believe you’ve hit some sort of implacable [immovable] limit. So you stop trying to move forward, and you settle down to life on that plateau. This is the major reason that people in every area stop improving.
The concept of the learning plateau is one way to describe how people approach learning, work, and self-improvement. With a new skill, there’s an initial period of excitement driven by how easy it is to make progress. Then a plateau arrives, and you have to decide whether to push through it or stick with your current skill level. And even if you push through it, you can look forward to another plateau where you’ll get to make the same decision again.
For most skills in life, there’s no need to push through plateau after plateau. It’s not worth the effort to become an expert in driving a car unless that’s your hobby or profession. But for the field that you specialize in, you probably do want to keep getting better. So what’s the secret to avoiding or conquering a learning plateau? The authors of Peak have something to say about that as well:
Any reasonably complex skill will involve a variety of components, some of which you will be better at than others. Thus, when you reach a point at which you are having difficulty getting better, it will be just one or two of the components of that skill, not all of them, that are holding you back.
According to this approach, the way to resist the plateau effect is to break down your target skill into its constituent parts, and be prepared to target those parts individually. In the book, the authors use typing speed as an example. Everyone who learns to type eventually reaches a speed plateau. Physical constraints mean you can’t keep increasing your typing speed forever. But you may plateau at a speed that is below your physical limits, or at least is slower than you want.
One idea for increasing your typing speed is just to push yourself to type faster whenever you get the chance. But according to the authors, there’s a more effective way. Rather than trying to type faster 100% of the time, try typing faster for just 15-20 minutes per day. During that time, document the mistakes you make. It’s likely that some letters or letter combinations will trip you up more than others. Once you identify them, you can more efficiently target those components, rather than trying to get better at the skill all at once.
Typing happens to be one component of the skill known as competitive programming. If your typing skills are slower than average, or if you’re competing at a high level in timed contests, working on your typing speed might be worthwhile. But for most competitive programming enthusiasts, working on other skills is more likely to produce results. What are those other skills?
Competitive Programming Sub-Skills
Last month, in a post called Competitive Programming Training Tips, I suggested breaking competitive programming into sub-skills as a way to practice it more effectively. One way to identify the best sub-skills to practice is to consider the steps that you use when solving a competitive programming problem, and what skills you use to complete each of the steps. Here’s how that could work.
Skill: reading and understanding a problem statement, and separating important information from filler
Competitive programming problem setters like to invent scenarios for their problems, rather than just posing problems in bare mathematical terms. This may make the problems more interesting, but it also makes them harder to solve quickly. To ensure that you’re solving the right problem and not getting bogged down in extraneous details, you need to be able to read and understand the sometimes quirky writing in competitive programming problem statements. This is our first sub-skill.
Once you isolate a sub-skill, you have to design a training method to get better at it. In the Training Tips post, I passed along some suggestions for getting better at the first three skills on this list. The idea is to take advantage of someone else’s solution to the problem you’re working on. Depending on the sub-skill you’re targeting, you’ll use different parts of the solution. For example, for getting better at reading comprehension, you can use this approach:
- Read the problem statement and summarize it in your own words.
- Without trying to solve the problem, find an editorial and verify that your summary is accurate.
Using these two steps, you can make your way through many more problems than if you followed the entire problem-solving process. You won’t get any better at the other sub-skills, but you’ll get a lot of targeted practice in reading comprehension. If that’s the sub-skill that’s holding you back, then it’s worth practicing.
Skill: algorithmic problem-solving
Once you’re clear on what problem you’re being asked to solve, you need to come up with a solution approach. This step requires creativity and flexibility, but the type of creativity it requires is not completely open-ended. For example, if you’re living in an old house and a fancy bathtub faucet starts leaking, it might require mechanical creativity to take it apart and diagnose the problem. You won’t be asked to do that in a programming contest. However, you could be asked to calculate how to fill the bathtub as fast as possible while keeping the water at a particular temperature. So you’ll have to practice that type of creative problem-solving.
To specifically target algorithmic problem-solving, you can again get help from a problem editorial. In this case, you will read the version of the problem description in the editorial. It should be free of the extraneous details from the original problem statement. Then before you get to the solution, stop reading and formulate your own solution to see if it matches what the editorial writer came up with.
Skill: algorithm design and analysis of algorithm efficiency
At this point, you have to design an algorithm to implement the approach that you came up with. This step requires the ability to turn a general solution into a step-by-step process. You’ll be dealing with programming concepts like loops and conditionals, but you can gloss over implementation details like syntax and precise data types. Pseudocode is a useful tool for recording your results.
Before you go any farther with your solution, you’ll also want to estimate the runtime of your algorithm, given the numerical constraints from the problem statement. There’s no point in spending time on implementation if your approach is going to take 10 seconds to execute. If that’s the situation you’re in, you’ll have to re-work your design.
To target the algorithm design sub-skill, read the parts of an editorial that contain the problem description and general solution, but stop before you get to any code or pseudocode. Then write your own pseudocode and see how it measures up compared to the editorial. You can also evaluate the quality of your pseudocode by looking through the logic used by a real code solution. If it matches, you’re in good shape. If not, figure out why yours is different.
Skill: programming language fluency
You now have a detailed algorithm, so you’re ready to implement your solution in a programming language. In this step, you have to deal with all of the language details that you avoided in the previous step. The skill you’re building in this step is language fluency, which like natural language fluency, allows you to implement your algorithm without consciously thinking about syntax and vocabulary.
There are a number of ways to work on programming language fluency in isolation. Educational websites like CodingBat feature problems that are much easier than competitive programming problems. So in the early stages of getting fluent in a language, you can focus more on syntax and speed than problem details. Another way to work on fluency is to read the non-code parts of an editorial, and then write your own code.
Skill: testing and debugging
Running your program on the problem’s sample input provides only the most rudimentary test of correctness. To ensure that your solution will pass the more rigorous secret test cases used by an online judge, you have to cultivate a testing mindset. Coming up with challenging test cases requires different skills than developing a solution, but the two areas are related. If you think about what test data could trip up your algorithm as you’re designing it, you’ll be likely to write more robust code in the first place.
The Training Tips post provides an unorthodox suggestion for working on your testing and debugging skills. The idea is to find an online judge like CodeForces that lets you see everyone’s submissions. Find a submission that didn’t pass all of the test cases. Without looking at the judge’s test cases, see if you can come up with your own test data that breaks the implementation. Then see if you can fix it.
Skill: reading code and technical explanations
Whether or not your solution to a problem is eventually accepted by the online judge, it’s a good idea to review code and editorials for the problem before you move on to the next one. Having invested the time to understand and at least try to solve the problem, you’re in a good position to see how others have approached it. The goal of solving a programming puzzle is to prepare yourself to tackle similar problems in the future, so it makes sense to study a few other solutions while you’re at it, rather than stopping with your own solution.
Many of the previous skill-building suggestions make use of editorials and code solutions, so it’s hard to avoid getting practice in the reading code and technical explanations sub-skill. Even reading an algorithms textbook (or a more specialized book like CP3) qualifies. But regardless of whether you target this skill specifically, it’s worth remembering that your work isn’t done just because you submitted an accepted solution.
Getting past a learning plateau has a lot in common with deliberate practice. One of the fundamentals of DP is to treat a skill as a collection of sub-skills to be mastered, rather than as a monolithic technique that you either get or don’t. Think of the common examples: The serious musician who repeatedly plays the difficult parts of a piece vs. the casual student who practices by playing an entire song. Or the serious golfer who analyzes each part of their swing and finds a training technique to improve it vs. the golfer who just plays for relaxation. To end up in the first category, you have to find the pieces your target skill is made of.
(Image credit: robert)