← Home
23rd January, 2026·Andrew R. Louisingh

the shape of stuck

stuckness has geometry. the shape suggests what to try next.

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 struggling to solve a problem. it gets much easier if you describe it to someone who doesn't know any algorithm names.

here's the version i'd say out loud:

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 sophisticated machinery.

then i gave up and looked at the solution:

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

one line of logic.

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.

suddenly, 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.

working memorystart: empty slots
1234
livelock (cycling) cured by flush, then reload for traction

if you asked that same person, they would just look at the numbers and say:

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

they win because they are traveling light. i lose because i'm carrying too much luggage.

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.

ask a different question: what shape is this stuckness? the shape often suggests what to try next.


friction vs. incoherence

the feeling of "being stuck" is not a monolith. from the inside, it just feels like "hard." this essay makes one cut through that space: friction vs incoherence. most of the time, stuck means incoherence — effort that doesn't buy anything. friction is the exception: effort hurts, but it buys progress.

friction: you're climbing a steep hill. every step hurts, but you're higher than you were.

the geometry: your 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: you're 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: your direction flips. each attempt undoes the last. what tends to help: stop. effort here often accelerates the loop.

a lot of standard advice prescribes a single cure—"push through"—but effort behaves differently in these two cases. in friction it buys progress. in incoherence it mostly reloads the loop.

incoherence isn't always obvious. sometimes it screams (panic), and sometimes it whispers (it feels like flow). to stop doing damage, it helps to distinguish between the common shapes:

the geometry of work
truthlooping
cycling. high heat, zero displacement.

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 signature: high effort, near-zero net progress.

why it's hard to escape: working memory is tiny — maybe four slots. once it's full of "dp" and friends, the simple arithmetic can't get in. concepts prime each other, so "optimization" keeps summoning "memoization" back onto the stage.

put them together and you get a closed loop:

the metabolic trapreinforcing loop
trigger ("minimize")load "dp" schemafilter realityfail & retryR
the more you try, the less you can switch frames

the loop is self-reinforcing. 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.

drift (latent incoherence)

the geometry: slow incoherence. you are moving steadily, but in a direction the world didn't ask for. it can look like a perfect Callout component, a refactor, a new base class — and no new sentences.

the signature: output that doesn't cash out. the mechanism: a coherent story that isn't tethered to the actual constraint. what helps: collide with reality. a hard stop from outside.

drift is sneaky because it often feels good. you need a clock, a person, or a test that doesn't care about your story.

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. crossed-out hypotheses. a growing table of test cases. a diagram that keeps expanding. the search space is shrinking: Search_Spacet+1Search_SpacetSearch\_Space_{t+1} \subset Search\_Space_t.

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

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

the destruction of value

this matters because the wrong move makes things worse.

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 try to look for one thing: 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.

livelock loops in minutes. drift loops in weeks. seeing the shape matters before deciding what to do.


if you only read one thing:

seeing the shape

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

introspection is a compromised sensor for progress. it measures intensity (heat) and coherence (smoothness), but it's bad at measuring velocity (progress toward reality).

so i try to start with something concrete: write the problem naked. sometimes even that is hard for boring reasons: you're missing an input, you can't yet say what "done" means, or you're just tired. treat that as a constraint too.

e.g. "i don't even know the input limits" / "i can't say what done looks like" / "i'm running on fumes." the move is boring: fetch the missing fact, write the done sentence, or step away and come back.

because drift often feels good, you can't reliably wait for a "symptom." here are some lenses i've found useful.

looking at your scratchpad

artifacts are harder to rationalize than vibes.

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.

stripping the mechanism words

try stating the problem using only inputs, outputs, and constraints. no mechanism words — ban "optimize," "traverse," "recurse," "cache," "dp state," "hook," "middleware."

contaminated

algo: "minimize operations by finding optimal dp state transitions that redistribute values"

systems: "we need a microservice architecture with event sourcing and CQRS to handle user signups"

writing: "i need to find the right narrative vehicle, earn the turn with enough setup, and make sure the kicker recontextualizes the lede"

decision: "i need to evaluate whether this opportunity aligns with my long-term career goals given the risk profile and my current runway"

mechanism words have infected the description. you're describing your approach, not the problem.

naked

algo: "array of odd numbers. one operation moves value. make all equal."

systems: "user signs up. we store their info. they log in later."

writing: "i'm trying to explain one idea. the reader doesn't know it yet."

decision: "do i want to do this?"

four words. sometimes the analysis is avoidance.

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.

the judgy duck

you've probably heard of rubber duck debugging — explain your code to a rubber duck and you'll find the bug. but i find it more useful to imagine explaining to your most critical coworker. or a rubber duck that judges.

not the problem. the solution you are currently building. 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."

why it works: 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.

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.)

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.

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

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.

the watchdog timer

drift disables your internal alarm system. so i use a dumb external one: a watchdog timer.

if you rely on pain to stop you, drift can run for weeks. you have to rely on the clock.

reading the shape

these lenses often point in the same direction:

scratchpadmechanism wordsjudgy duckconstraintslikely shape
looping, same ideas repeatedcan't strip themlivelock
growing, expandingcan stripfeels boringall giventraction
elaborate but disconnectedcan stripdefensivesome inventeddrift

what the shape suggests

the taxonomy recommends different moves. if all three shapes got the same advice, the taxonomy wouldn't be doing any work.

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 not to think harder — it's to think with different furniture.

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.

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.


the word "stuck" erases the geometry. it makes a dp loop and a slow drift and a real climb feel like the same kind of hard — and it tempts you into the same move every time: push harder. try again.

but a tight loop needs an interrupt, not more force. a slow drift needs a collision, not more hours. and a real climb needs protection, not a reboot.

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


further reading: