← writing
january 23, 2026

the shape of stuck

Andrew R. Louis

an attempt to deconstruct the feeling of being stuck working a problem

1.1

the paradox of expertise

there is a specific kind of dumb move i only seem to make once i know a domain well.

i recently spent forty-five minutes on a problem that should have taken five.

start with [1, 3, 5, ..., 2n-1]. in one operation, pick two indices and move 1 from one pile to the other. what's the minimum number of operations to make all elements equal?

i threw everything at it. i sketched state transitions. i built a dynamic programming table. i implemented a greedy recursion with memoization. i spent forty-five minutes debugging my own machinery.

each pass felt like progress. the dp table wasn't confused; it was doing exactly what dp tables do. the memoization wasn't misapplied; it was correctly optimizing the recursion i'd built. the machinery was sound. i had just assembled it around the wrong problem.

then i gave up and looked at the solution:

def min_operations(n):
    return n * n // 4

one line of logic.

forty-five minutes.

intuition: the array is symmetric around its average (n). each operation can move 1 unit from an above-average pile to a below-average one, so the work is the total deficit of the lower half, which sums to n * n // 4.

the mistake happened the second i read the word "minimize."

my brain saw that word and immediately retrieved the "dynamic programming" folder. it loaded all the heavy machinery: state transitions, memoization, recursion.

the retrieval is fast, automatic, heuristic; the machinery behind it is what kahneman called system 1. usually it saves time. here, it blinded me. the pattern-match ("minimize" = "dp") happened before i even understood the problem, and it came with no flag, no asterisk, no felt difference from the times it's right, which is most of the time, which is why you trust it.

in a 1942 monograph, a psychologist named luchins reported what happened when he sat people down with water jug puzzles and watched this happen under controlled conditions. once they learned a complex method, they couldn't see the simple one, even when it was obvious to newcomers. borrowing an old german word for "set," he called it einstellung: the mechanization of thought. once you pick up the hammer, you physically cannot see the screws. the wrong tool captures your attention so completely that the right one never even loads.

my guess at the mechanics: my working memory was full. there was no room left for simple arithmetic. i wasn't solving the problem in front of me. i was solving the problem i expected to see; it felt exactly like the real one.

which is the thing that's hard to keep straight afterward. not that the error happened (errors are obvious in retrospect). but that there is no felt difference, from inside the skull, between solving the right problem and solving a plausible substitute. the sensation of engagement is identical. the experience of progress is identical.

if you described it to a friend who'd never heard of dynamic programming, they'd just look at the numbers and say:

"wait, you're just moving piles around. the total amount of stuff implies the answer, right?"

they see it because they are carrying nothing. i missed it because i was carrying too much.

and that mistake has a particular flavor: hot, obvious, humiliating.

but i get stuck in quieter ways too. sometimes i'm "writing" for three days and the doc still doesn't have the next paragraph. sometimes i don't even notice it's happening.

this essay is for the person who is stuck because they're already carrying a lot.

what luchins caught in the jars is one shape of stuck. there are others. each has its own geometry, and the geometry decides what helps.


1.2

friction vs. incoherence

from the inside, it just feels like "hard." but that single coordinate hides the geometry.

give the space three axes. heat: how intense the effort feels. smoothness: how coherent it feels, whether each step seems to follow from the last. velocity: whether any of it is actually moving you toward reality. the shapes this essay names are regions of that space. livelock runs hot and jagged and goes nowhere. drift runs cool and smooth and goes nowhere. traction is jagged too, sometimes hot, sometimes pleasant, but it moves.

the catch, and it's the catch the whole essay keeps running into: you can feel heat. you can feel smoothness. you cannot feel velocity.

one cut through that space: friction vs incoherence.

friction

climbing a steep hill.

every step hurts, but you are higher than you were.

the geometry: direction is stable. each attempt refines the last.

what tends to help: grind. this is one of the few times "try harder" is the right move.

incoherence

orbiting a contradiction.

you fix A, which breaks B. you fix B, which breaks A. you feel busy, but you're drawing circles.

the geometry: direction flips. each attempt undoes the last.

what tends to help: stop. effort here often accelerates the loop.

we are trained to expect friction. in school, sports, and early work, effort reliably correlates with progress. if you aren't moving forward, the answer is almost always to push harder.

but usually, when you are truly stuck, the problem is incoherence.

incoherence is dangerous because it triggers the same "try harder" reflex, but the geometry is different. pushing harder in a loop just spins you faster. and you cannot distinguish the two from the inside by feel alone, which is the whole problem, because the thing you'd need to tell them apart (an honest map of where you are) is precisely the thing being compromised.

1.3

the common shapes

the geometry of work
realitylooping
high heat, low smoothness, zero velocity.
1.3.1

livelock (fast incoherence)

the geometry: a tight loop. you are cycling through the same three ideas in working memory. your approach flips every few minutes. "maybe it's the cache? no, the logic. maybe the cache?"

the ideas don't feel recycled. each pass feels like the first time. there is no signal from inside the loop that you've been here before.

the signature: high effort, near-zero net progress. on the axes: high heat, low smoothness, zero velocity. the flavor is loud and arrives fast: frustration, panic, heat.

why it's hard to escape:

your working memory is a scratchpad that holds about four chunks: cowan made the case in 2001, and the number is stubbornly small. for an expert, "dynamic programming" is a single chunk, which sounds like efficiency until you watch what the chunk does. it arrives with a retinue: state transitions, base cases, memoization, all loaded behind the label. and the deeper problem is attentional. the folder doesn't fill the slots so much as decide what gets loaded into them. eye-tracking studies of chess players caught in einstellung show their gaze returning to the squares of the familiar solution even while they report searching for a new one. the simple solution stays invisible because nothing ever loads it.

working memory
1234
1. filling memory
timeline
start: empty slots

your inner monologue runs on a buffer that holds about two seconds of speech; baddeley called it the phonological loop. if you are muttering "maybe cache... no logic... maybe cache," you are actively maintaining that state in your head. you can't have a new thought because you are too busy repeating the old one to keep it from fading. which means (and this took me a while to really absorb) you are actively maintaining the constraint. the loop doesn't sustain itself. you are the one refreshing it, every two seconds, to keep it from decaying.

worse, concepts prime each other: collins and loftus called it spreading activation. when you say "optimization," your brain involuntarily lights up related nodes like "memoization" and "caching." the wrong tools keep reloading themselves. even noticing that you're stuck on "optimization" re-activates the node, which re-primes its neighbors.

put them together and you get a closed loop:

reinforcing loop
trigger ("minimize")load "dp" schemafilter realityfail & retryR
trigger, load, filter, fail. repeat.

when you ask "what am i missing?", the answer comes from the same biased circuit that missed it.

what helps: interrupt. break the loop before trying to move.

1.3.2

drift (latent incoherence)

the geometry: slow incoherence. you are moving steadily, but in a direction the world didn't ask for. it looks like work. you are optimizing the query planner for a database with ten rows. you are refactoring the auth system for a userbase of one.

the signature: output that doesn't cash out. on the axes: low heat, high smoothness, zero velocity. the flavor, such as it is: satisfaction, "flow", cool. don't lean on it; traction can feel exactly the same.

the mechanism: local optimization masking global incoherence. doing the sub-task feels good, so you keep doing it, even though it doesn't move the main metric.

what helps: collide with reality. a hard stop from outside.

drift is the most dangerous shape because it feels like work. you are producing high-quality artifacts. the code compiles. the diagrams are beautiful. and the artifacts are genuinely good, which is what keeps the alarm from sounding: good code solving a problem nobody has. a gyroscope spinning in a vacuum: stable, precise, and touching nothing.

drift is still incoherence, still a loop. it's just slower. livelock loops in minutes. drift loops in weeks.

1.3.3

traction (the baseline)

traction is what friction feels like when you're pointed the right way. you are running through mud toward the goal: messy, but each attempt builds on the last. on the axes: low smoothness, real velocity. the mood won't tell you much (drift can feel just like this). the desk will: ugly, messy, real. crossed-out hypotheses. a growing table of test cases. a diagram that keeps expanding. the search space is shrinking: each attempt rules something out for good.

the risk with traction is premature flush. your working memory holds an expensive, fragile map of dead ends. if you context-switch or start over, you lose it.

a note on those flavors, because i've just contradicted myself. i said you can't tell the shapes apart by feel, then i tagged each shape with a feeling. both are true, and the scoping is the point. the flavors are real but they lag, and what they report is valence: how the work feels to do. livelock's flavor is loud, fast, and fairly trustworthy, which is why it's the easiest shape to catch from inside. drift and traction share a valence. both can feel absorbing, even great. feel gives you heat and smoothness, and it has nothing to say about velocity, which is the axis that separates them. so the diagnostics, when we get to them, stop consulting your feelings and start going through your stuff.

traction is where you want to be. livelock and drift are the two ways you miss it.

1.4

misreading the shape

mistaking one shape for another destroys value.

traction and drift can feel identical from the inside. in traction, the search space shrinks. in drift, you generate output that doesn't constrain anything.

i force a check: did the last hour reduce the branching factor? fewer plausible moves, sharper test cases, a clearer statement of what i'm trying to do. if yes, traction. if no, stop and look. this sounds simple, but the hard part is answering honestly, because what you're really asking is "was the last hour of my life wasted?" and nobody volunteers for that verdict.

what makes it harder: the question is recursive. you're using your judgment to audit your judgment. the instrument and the error may be the same instrument.

1.5

seeing the shape

livelock screams (frustration). drift whispers (satisfaction).

introspection is a compromised sensor: back on the axes, it reads heat and smoothness in high resolution and velocity not at all. and because drift feels good, you can't wait for a symptom to send you looking. you have to go check. so the diagnostics below stop trusting ambient mood. they either go through what the work leaves behind, or they provoke a response the work can't counterfeit.

1.5.1

looking at your scratchpad

artifacts are harder to rationalize than vibes.

paper has no working memory limit. it doesn't forget the bottom of the list when you add to the top. more importantly, by dumping state to the page, you break the phonological loop (risko and gilbert call this cognitive offloading). you don't have to keep chanting the problem to hold it, which frees up your brain to actually solve it. the implication is mildly humiliating: the voice you identify as you thinking, or at least its rehearsal track, is less a reasoning engine than a tape loop with a two-second buffer. the reasoning happens when you get it out of the way.

livelock: the same diagram drawn three times. code that circles back to where it started. you've written "dp" in three different places with arrows between them.

traction: crossed-out hypotheses. a growing table of test cases. a diagram that has expanded since you started.

drift: artifacts exist, but they're orthogonal. a polished component. a refactor. a new base class. none of it touches the problem statement.

1.5.2

stripping the mechanism words

mechanism words are assumption-preservers. the procedure for breaking them is old.

in 1619, a twenty-three-year-old soldier locked himself in a stove-heated room in germany and tried to take apart everything he knew. descartes had been filling notebooks with geometry and the mechanics of falling bodies, and could no longer tell which parts of what he knew were real and which were just familiar. so he cut. senses, memory, the external world: removable until proven otherwise. he kept going until he hit the atom that wouldn't split: the bare act of thinking itself.

for the stuck engineer, the move is the same. choose to forget your tools, the sound ones included, because you can no longer tell which parts are solving the problem and which are just solving themselves.

the naked problem is that foundation for engineers. we layer mechanism words (cache, optimization, microservice) on top of the actual requirement until we can't see the floor. strip the mechanism until you hit what you can't remove: inputs, outputs, constraints.

domaincontaminated (mechanism words)naked (physics only)
algo"minimize operations by finding optimal dp state transitions that redistribute values""array of odd numbers. one operation moves value. make all equal."
systems"we need a microservice architecture with event sourcing and CQRS to handle user signups""user signs up. we store their info. they log in later."
writing"i need to find the right narrative vehicle, earn the turn with enough setup, and make sure the kicker recontextualizes the lede""i'm trying to explain one idea. the reader doesn't know it yet."
decision"i need to evaluate whether this opportunity aligns with my long-term career goals given the risk profile and my current runway""do i want to do this?"

(four words. sometimes the analysis is avoidance.)

you're describing your approach, not the problem.

if you cannot strip the mechanism words, that's a strong signal: livelock. "dp" is the loop itself: saying it reloads the whole folder back into working memory.

if you can state it naked, you might have traction or drift. the next question is whether the story cashes out in reality.

sometimes the stripping fails for duller reasons. you don't actually know the input limits, or you can't yet say what done means. that's a constraint too, and the move is equally dull: go get the missing fact, or write the one-sentence definition of done. and if you're just tired, no diagnostic survives that. go to bed.

1.5.3

the judgy duck

explain your current solution (not the problem, the solution you're building) to your most critical coworker. or a rubber duck that judges.

does the thought make you wince?

drift: you feel a flash of shame or defensiveness. "well, i have to get this component right first because..." traction: you feel boring. "i'm just writing the test cases."

you can convince yourself of anything: you share all your own assumptions. the judgy duck doesn't. when you imagine their questions ("why this? why now?"), you're forced to justify premises you'd normally skip over. if you wince, dig there.

1.5.4

shrinking to n=1

run the smallest possible version of the problem. one array element. one request. one user.

scale hides complexity. you can theorize about n=1000 using vague terms, but at n=1, the "dp state" evaporates and you're left with raw arithmetic. if the problem is still hard at n=1, that's signal. if it becomes trivial, your complexity was probably invented.

(trap: if n=1 works but n=1000 fails, the bug may live in interactions, timing, or gaps between units.)

1.5.5

putting the readings together

set the instruments side by side and they turn back into the axes, read from evidence and provocation instead of mood. the scratchpad is a velocity gauge: a shrinking search space leaves a paper trail. the mechanism-word test reads capture: a frame you can't strip is a frame that has claimed the machine, whatever the temperature. the duck reads smoothness, specifically whether the smoothness survives an audience.

scratchpad (velocity)mechanism words (capture)judgy duck (smoothness)likely shape
looping, same ideas repeatedcan't strip themn/alivelock
growing, expandingcan stripfeels boringtraction
elaborate but disconnectedcan stripdefensivedrift

one reading can lie. three that agree are hard to argue with. (the n=1 collapse from above is the scratchpad's accomplice: it forces a velocity reading the full-size problem can hide.)

one more instrument remains: an audit of the wall itself.

1.6

is the constraint real?

sometimes you're not stuck on the problem. you're stuck on a constraint you invented.

i once spent hours on a packing problem, fitting circular covers onto a surface, before realizing the hole was square. the user said "cover the opening." somewhere between hearing that and starting work, i decided "circle." i don't know when. it felt like part of the problem, not a choice i'd made. the constraint enters as a decision and immediately disguises itself as a fact. by the time you notice it, it's load-bearing.

when i finally asked "wait, why circular?" the problem evaporated. a square packs at 100%. there was no packing problem. there never was.

same thing with algorithms. i had a graph problem once. shortest path. each directed edge has weight w: going with the arrow costs w, going against it costs 2w. and my brain quietly added a word the prompt never said: one. as if the task were: you get one reversal; pick the best edge.

so i started optimizing around that. dijkstra from start, dijkstra from end on the reversed graph, score each candidate reversal: dist(start, b) + 2w + dist(a, end). scan edges once, take the minimum. it felt clean.

then i reread the statement: there is no "pick one edge" step. the backwards edges just exist. you add them and run dijkstra once. the extra complexity was mine.

the move is always the same: list your constraints. for each one, ask: is this given (the user needs it, or physics requires it), or did i assume it? if you can't remember where a constraint came from, it's probably invented.

one trap: some constraints are invented at n=1 but real at n=1000. thread safety is optional for a script, mandatory for a server. the move is: delete the constraint to find the solution, re-introduce it to ship. if the solution breaks when you add it back, you've found where the real difficulty lives.

1.7

what the shape suggests

each shape calls for a different move.

livelock → interrupt. when your working memory is captured by a bad frame, "try harder" mostly just reloads it. what helps me: stop, physically walk away, let the cache cool, then come back and restate the problem without mechanism words. the goal is to return with different furniture loaded.

drift → collide. flushing doesn't fix wrong direction. it usually takes external contact. write the desired outcome in one sentence (no mechanism words). build the cheapest artifact that tests it. put it in front of the source of truth. for a blog post, that can be as small as sending the rough paragraph to one reader and asking what they think you're claiming. you need your story to hit something real, before you've invested months in it.

and because drift doesn't hurt, you can't rely on pain to schedule the collision. i use a watchdog timer: roughly every three hours of deep work, it goes off, and i have to answer one question. did the last three hours touch the actual problem, or did i build something adjacent? the timer knows nothing about my work, which is exactly what qualifies it. drift disables every alarm that does.

traction → protect. when you are solving the right problem and the space is shrinking, the fragile thing is context. it helps to externalize what you've ruled out, block interruptions, and not context-switch. traction is the only shape where "push through" is the right answer. so push.


descartes locked himself in a stove-heated room and stripped until he hit the atom that wouldn't split. for the engineer, that atom is the naked problem.

next time you're stuck, don't push. name the shape first. check whether the constraint is real. then move.


if you only read one thing:

  • write the problem naked (inputs/outputs/constraints; no mechanism words).
  • if incoherence:
    • livelock (tight loop) → interrupt
    • drift (slow, feels smooth) → collide
  • else: traction → protect
  • ask: is the constraint real?

further reading:

  • descartes, rené. discourse on the method (1637). the original.
  • kahneman, daniel. thinking, fast and slow (2011). why system 1 hijacks the wheel.
  • cowan, nelson. "the magical number 4 in short-term memory" (2001). the hardware constraint.
  • collins, allan m. and loftus, elizabeth f. "a spreading-activation theory of semantic processing" (1975). why concepts prime each other.
  • baddeley, alan. "working memory" (1992). the review of the model he and graham hitch proposed in 1974, phonological loop included.
  • risko, evan f. and gilbert, sam j. "cognitive offloading" (2016). why writing things down frees working memory.
  • luchins, abraham. "mechanization in problem solving" (1942). the einstellung experiments.
  • bilalić, merim, peter mcleod, and fernand gobet. "why good thoughts block better ones" (2008). the eye-tracking proof that attention stays captured by the familiar solution.