The course was difficult by design. That did not mean the design was working.

Students could follow an advanced solution in class and still fail to begin a new problem. Some knew the right algorithm after seeing the topic label but could not select it in a mixed set. Others spent hours on problems whose first useful observation remained out of reach.

It was tempting to interpret the struggle as evidence of rigor. Across fourteen Columbia course offerings, including terms that went well and terms that did not, I learned to ask a stricter question: what decision can the student make now that the course has taught them?

Difficulty needs a job

A hard problem is useful when its difficulty exposes a specific boundary.

One problem may test whether a student can choose the state in a dynamic program. Another may test whether they can reject a plausible greedy rule. A third may require implementation discipline after the main idea is known. If I cannot name the job, I cannot tell whether the struggle is producing the intended practice.

The same problem can be productive for one student and inert for another. A student who is one observation away can test and revise a model. A student missing three prerequisites may only wait for a hint. Time spent is not enough to distinguish them.

I now assign difficulty at the level of the decision, not the reputation of the problem.

Watch the first ten minutes

The beginning of a solve reveals more than the final accepted submission.

Can the student restate the target? Do they use the constraints to rule out impossible approaches? Can they generate a small example that separates two ideas? Do they know which claim would make progress possible?

When students repeatedly cannot find a first move, the course may have skipped the process that precedes the technique. Showing another complete solution often makes this worse. The instructor becomes better at solving in front of the room while the students remain dependent on the performance.

I began spending more class time at the point where several approaches still looked reasonable. We would identify the missing claim, design a counterexample, or choose what information a state must preserve before writing a recurrence. The finished algorithm received less stage time. The choice that produced it received more.

Distinguish struggle from abandonment

Useful struggle has feedback. The student tries something, obtains evidence, and changes the next attempt.

Unproductive struggle repeats the same state. The student rereads the statement, writes disconnected observations, or waits for a hint large enough to restart the problem. More time in that state does not create independence.

I use three observations to decide whether to intervene:

  • Is the student testing a claim or merely searching for one?
  • Did the last attempt produce information?
  • Can the student name the current obstacle?

If the answer to all three is no, I restore one missing decision. I may ask for the smallest failing example or point to the constraint that should control the model. I try not to reveal the path beyond that boundary.

The purpose of the hint is to make the next independent move possible. It is not to preserve the schedule of the lesson.

Use the weaker terms as evidence

Course evaluations are incomplete measurements. Response rates vary. Students enter with different preparation and goals. A single average cannot identify the cause of a weak term.

It can still force a review.

When a course receives weaker feedback, I compare it with the work students could perform. Which assignments produced learning after feedback? Where did office-hour questions cluster? Could students solve an unlabeled transfer problem? Did the grading system reward persistence, understanding, speed, or some confused mixture of them?

I do not want to explain away a weak result before asking what it revealed. The course belongs to the students who actually took it, not the ideal student I had in mind while writing the syllabus.

Several changes followed from that review. I made the first reachable step more visible without announcing the solution. I separated development activities from selection for contest teams. I used mixed sets so the topic was not given away. I added delayed checks because success during the lesson overstated what remained a week later.

These changes did not make the subject easy. They made the difficulty easier to interpret.

Set an operating bar for a lesson

I now consider a lesson useful when students can do more than reproduce its example.

For a technique, I look for evidence that a student can:

  1. state the condition that makes the technique relevant;
  2. find a reachable first step without the topic label;
  3. test a tempting alternative;
  4. reconstruct the decisive argument;
  5. reject the technique when an assumption fails;
  6. use the idea again after the explanation is no longer fresh.

The list changes what I teach and what I assign. A polished lecture can support the fourth item while leaving the other five untouched.

Keep rigor attached to transfer

Competitive programming rewards speed under pressure, but speed is a late outcome. The course first has to build a method that survives an unfamiliar statement.

That method includes reading constraints, forming a model, testing a claim, implementing carefully, and reviewing the first decision that failed. Hard problems can train every part of it. They can also become a wall that strong students learn to climb and everyone else learns to avoid.

I still assign problems that many students will not solve immediately. I want each one to reveal what the student should practice next. Difficulty earns its place when it produces that information and the course knows what to do with it.