For six months, I wrote every SQL query like this:

SELECT * FROM users WHERE id = 123;

SELECT star. Get all the columns. Always.

My reasoning: “I might need all the data. Better to have it than query again.”

This worked fine for my bootcamp projects. Tables had 5 columns. Performance didn’t matter.

Then I joined a company with real production data.

My first code review:

Senior Engineer: “Why are you selecting all columns?”

Me: “In case I need them later?”

Him: “Do you need them now?”

Me: “Well, no, just the email and username.”

Him: “Then select those. This table has 47 columns. You’re transferring megabytes of data you don’t need.”

He was right.

But here’s the problem:

I didn’t just need to learn “SELECT only what you need.”

I needed to unlearn “SELECT star is fine.”

And unlearning is way harder than learning.

Why Unlearning is Harder Than Learning

When you learn something new, you’re filling an empty space.

When you unlearn something, you’re demolishing a structure you’ve already built.

And your brain doesn’t want to do that.

graph TD A[Learning
Adding new knowledge] --> B[Empty space → Filled space
Easy, feels like progress] C[Unlearning
Removing old knowledge] --> D[Filled space → Demolished → Rebuilt
Hard, feels like regression] style B fill:#6bcf7f style D fill:#ff6b6b

The psychological resistance to unlearning:

  1. Sunk cost fallacy: “I spent so much time learning this. It can’t be wrong.”
  2. Identity attachment: “This is how I do things. It’s part of who I am.”
  3. Status threat: “If I was wrong about this, what else am I wrong about?”
  4. Comfort: “I’m good at the old way. The new way makes me feel like a beginner again.”

All of these forces conspire to keep you doing what you’ve always done.

Even when it no longer works.

Story: The Engineer Who Couldn’t Let Go

Meet Tom.

Tom had 15 years of experience writing jQuery.

He was great at it. Fast, efficient, productive.

Then his company decided to migrate to React.

Tom’s reaction: “React is overengineered. jQuery is simpler. This is a mistake.”

He wasn’t wrong that jQuery was simpler.

But he was wrong that it was the right tool for what the company was building.

What happened:

Year 1: Tom kept suggesting jQuery solutions to React problems. His advice was ignored.

Year 2: Tom begrudgingly learned React, but kept writing it like jQuery. Manipulating the DOM directly. Not using component lifecycle properly.

Year 3: Tom was the bottleneck. Everyone else had moved on. He was still fighting the framework.

Year 4: Tom left the company. “React is just a fad.”

The tragedy: Tom was talented.

But he couldn’t unlearn jQuery-style thinking.

So when the world moved on, he got left behind.

The Unlearning Process

Unlearning isn’t instantaneous. It’s a process.

graph LR A[Stage 1:
Unconscious Competence
You're good at the old way] --> B[Stage 2:
Conscious Awareness
You realize it's outdated] B --> C[Stage 3:
Active Unlearning
You force yourself to stop] C --> D[Stage 4:
Relearning
You build new habits] D --> E[Stage 5:
New Unconscious Competence
The new way becomes automatic] style A fill:#4d96ff style B fill:#ffd93d style C fill:#ff6b6b style D fill:#ff9999 style E fill:#6bcf7f

Stage 1: Unconscious Competence

You’re good at the old way. It’s automatic. You don’t even think about it.

Stage 2: Conscious Awareness

Something happens (feedback, observation, failure) that makes you realize the old way isn’t optimal.

This is the critical moment.

Most people skip to denial. “No, my way is fine.”

The ones who grow: “Hmm, maybe I need to reconsider.”

Stage 3: Active Unlearning

You consciously catch yourself doing the old thing and force yourself to stop.

This stage is painful. You’re slower. You make mistakes. You feel like you’re regressing.

Most people quit here and revert to the old way.

Stage 4: Relearning

You practice the new way until it starts to feel natural.

Still effortful, but no longer fighting your instincts.

Stage 5: New Unconscious Competence

The new way becomes automatic. You don’t have to think about it.

Now you’re better than you were before.

My Unlearning Journey: From Cowboy Coding to TDD

For my first year as a developer, I wrote code like this:

  1. Write a bunch of code
  2. Run it
  3. Fix bugs
  4. Repeat until it seems to work
  5. Ship it
  6. Hope for the best

This worked okay for small projects.

Then I joined a team that practiced Test-Driven Development (TDD).

Their process:

  1. Write a failing test
  2. Write minimal code to make it pass
  3. Refactor
  4. Repeat

My reaction: “This is so slow. Why would anyone do this?”

My manager: “Try it for two weeks. Then we’ll talk.”

Week 1 of TDD:

I was miserable. Everything took twice as long.

I kept forgetting to write tests first. I’d write code, then realize I was supposed to test first, then delete it and start over.

Week 2:

Still slow. But something strange happened.

I shipped a feature. No bugs in production.

This had never happened before.

Week 4:

I was still slower than my old approach. But bugs were way down.

Week 8:

I was back to my old speed. But with tests. And way fewer bugs.

Week 12:

I was faster than before because I wasn’t debugging production issues.

The unlearning:

I had to unlearn “write code first, think about correctness later.”

And learn “think about correctness first, write code second.”

My brain fought this for weeks.

But once I pushed through the active unlearning phase, I became a better developer.

Identifying What Needs to Be Unlearned

Here’s the problem: You don’t know what you don’t know needs unlearning.

The old knowledge is invisible to you.

How to surface it:

Signal 1: Repeated Failures

Pattern: You keep making the same type of mistake.

Example: Your PRs keep getting flagged for the same issues.

What to ask: “What belief or habit is causing this pattern?”

Example from my life:

I kept getting PRs rejected for “not handling edge cases.”

The belief I needed to unlearn: “If it works for the happy path, it’s done.”

The new belief: “A feature isn’t done until it handles errors gracefully.”

Signal 2: Obsolete Advice

Pattern: Advice that was true 5 years ago but isn’t anymore.

Examples:

Web development:

  • “Don’t use frameworks, they’re overkill” (maybe true in 2010, not in 2024)
  • “jQuery is essential” (was true, isn’t anymore)
  • “Optimize for IE6” (please no)

Career:

  • “Stay at one company for 20 years” (outdated)
  • “Get a degree, you’re set for life” (outdated)

How to catch this: Regularly ask “Is this still true?”

Signal 3: Frustration with New Tools

Pattern: New tools/approaches feel “wrong” or “overengineered.”

This might mean: You’re locked into an old mental model.

Example:

When I first saw TypeScript, I thought “This is JavaScript with extra steps. Why?”

The mental model I needed to unlearn: “Types are bureaucracy.”

The new model: “Types are documentation + error prevention.”

Signal 4: “This is How We’ve Always Done It”

If you catch yourself saying this, alarm bells should ring.

This is the sound of unexamined beliefs.

Better question: “Is this still the best way to do it?”

Signal 5: Generational Gaps

Pattern: Newer developers do things differently than you.

Your reaction options:

Option A: “They don’t know what they’re doing. My way is better.” (Probably wrong)

Option B: “Interesting. Why are they doing it that way?” (Probably right)

Example:

Junior developers use GitHub Copilot heavily. I initially dismissed it.

The belief I needed to unlearn: “Real programmers write every line themselves.”

The new belief: “Real programmers use tools to be more productive.”

The Unlearning Techniques

Technique 1: The Beginner’s Mind Exercise

Once per quarter, approach your domain as a beginner.

Ask: “If I were learning this today, with no prior knowledge, how would I do it?”

Example:

I took a React course as if I’d never used React before.

What I discovered:

  • Newer patterns (hooks) that I hadn’t fully adopted
  • Better ways to structure components
  • Abstractions I was overusing

I’d been doing React the 2018 way in 2023.

The course forced me to unlearn old patterns and relearn modern ones.

Technique 2: The Inversion Exercise

Pick a strong opinion you hold.

Then argue the opposite side as convincingly as you can.

Example:

My belief: “Microservices are better than monoliths.”

The exercise: Argue why monoliths are better.

What I learned:

  • Monoliths are simpler for small teams
  • Microservices have massive operational overhead
  • Most apps don’t need that scale

The result: I still prefer microservices for certain cases, but I unlearned “microservices are always better.”

Now I can recommend the right tool for the context.

Technique 3: The “Convince Me Otherwise” Challenge

State your belief publicly and invite people to change your mind.

Example tweet I posted:

“I think Redux is overkill for most React apps. Convince me otherwise.”

What happened:

  • 20 responses
  • Half agreed with me
  • Half showed me use cases where Redux is essential

The result: I unlearned “Redux is always overkill” and learned “Redux is overkill unless you have X, Y, Z requirements.”

Technique 4: The Constraint Exercise

Force yourself to NOT use your usual approach.

Example:

I always used loops for data transformation.

The constraint: “Use only map/filter/reduce for one week. No loops.”

What I learned:

  • Functional approaches are often clearer
  • My loop-based intuitions didn’t always translate
  • I was overcomplicating things

After the week: I had unlearned “loops are the default” and learned “declarative transformations are often better.”

Technique 5: The Fresh Start

Build something new using only the newest best practices.

Don’t port old code. Start from scratch.

Example:

Instead of migrating my old Express API to modern patterns, I built a new API from scratch.

What this forced:

  • No old patterns to carry forward
  • Fresh architectural decisions
  • Learning modern approaches without baggage

The result: I unlearned a dozen outdated Express patterns and learned current best practices.

Story: How Airbnb Unlearned Their Codebase

In 2017, Airbnb had a problem.

Their codebase was huge. Full of legacy patterns. Inconsistent.

They’d accumulated years of “this is how we do it here.”

The solution: They didn’t try to fix it all at once.

Instead, they created a principle:

“Don’t use old patterns for new code.”

The rule:

  • Existing code could stay (for now)
  • New code had to follow new patterns
  • When you touch old code, update it to new patterns

Over 2 years, the codebase gradually modernized.

Not through a big rewrite (which fails).

But through continuous, incremental unlearning and relearning.

The lesson:

You don’t unlearn everything at once.

You unlearn gradually, as you build new things.

Common Unlearning Failures

Failure Mode 1: The Pendulum Swing

Pattern: You swing from one extreme to another.

Example:

  • Old belief: “Never use any dependencies, write everything yourself.”
  • You get burned by this
  • New belief: “Always use dependencies, never write anything yourself.”

Both are wrong.

Better: “Use dependencies for complex, well-maintained tools. Write your own for simple, specific needs.”

The fix: Seek nuance, not opposite extremes.

Failure Mode 2: The Identity Crisis

Pattern: Your skill becomes part of your identity.

Example:

“I’m a jQuery developer.” → Company moves to React → “I don’t know who I am anymore.”

The fix: Identify as a learner, not a practitioner of one tool.

Instead of: “I’m a React developer.”

Try: “I’m a frontend developer. Currently using React.”

This makes unlearning less threatening.

Failure Mode 3: The Sunk Cost Trap

Pattern: “I spent years mastering this. I can’t abandon it now.”

Example:

Developers who spent years mastering jQuery feel like switching to React means their expertise was wasted.

The truth: The problem-solving skills transfer. The syntax doesn’t.

The fix: Focus on what transfers, not what doesn’t.

Failure Mode 4: The Defensive Expert

Pattern: You get defensive when challenged.

Example:

Junior dev: “Why don’t we use hooks instead of class components?”

You: “Class components are fine. We’ve always used them.”

What’s really happening: You’re protecting your ego, not evaluating the idea.

The fix: Separate your identity from your methods.

Instead of: “I use class components” (identity)

Try: “I currently use class components, but I’m open to hooks if they’re better” (method)

The Meta-Skill: Learning to Unlearn

The best learners aren’t the ones who learn fastest.

They’re the ones who unlearn fastest.

Because the world changes.

Today’s best practice is tomorrow’s anti-pattern.

The developers who thrive are the ones who can:

  1. Notice when something is outdated
  2. Let go of it without ego
  3. Learn the new thing
  4. Repeat

This is a meta-skill that compounds.

Each time you unlearn and relearn, you get better at the process itself.

Your first unlearning (jQuery → React): Takes 6 months, feels terrible.

Your tenth unlearning (Next.js v12 → v13): Takes 2 weeks, feels normal.

You’ve learned how to unlearn.

Practical Exercise: Your Unlearning Audit

Set a timer for 30 minutes.

Answer these questions:

1. What did I learn 5+ years ago that I still use exactly the same way?

List everything. Tech, processes, beliefs, habits.

2. For each item, ask: “Is this still the best way?”

Research. Ask experts. Look at what modern practitioners do.

3. Pick one thing that’s outdated.

Commit to unlearning it this month.

4. Define what “new way” looks like.

Be specific. “Use TypeScript instead of JavaScript” is good. “Be better” is not.

5. Set up accountability.

Tell someone. Post about it. Track it daily.

My example:

1. Old habit: Using var instead of const/let in JavaScript.

2. Still best? No. const/let are superior (block scope, clearer intent).

3. Commit: This month, I will unlearn var.

4. New way: Use const by default. Use let only when reassignment is needed. Never use var.

5. Accountability: ESLint rule that errors on var. Posted commitment on Twitter.

Result: After 2 weeks, const/let became automatic.

When to Unlearn vs. When to Keep

Not everything old is bad.

Some principles are timeless.

How to tell the difference:

graph TD A{Is this principle or implementation?} -->|Principle| B[Probably keep it
Principles transcend tools] A -->|Implementation| C{Is the context the same?} C -->|Yes| D[Keep it] C -->|No| E[Consider unlearning] B --> F[Examples:
- Write readable code
- Test your code
- Solve the right problem] E --> G[Examples:
- Specific syntax
- Deprecated tools
- Patterns tied to old constraints] style B fill:#6bcf7f style D fill:#6bcf7f style E fill:#ff9999

Keep principles. Unlearn implementations.

Keep: “Write testable code.”

Unlearn: “Always use class-based tests.”

Keep: “Optimize for readability.”

Unlearn: “Avoid arrow functions because they’re confusing.” (They’re not anymore)

Keep: “Consider performance.”

Unlearn: “Premature optimization is the root of all evil.” (Sometimes early optimization prevents rewrites)

Final Thoughts

I wasted months clinging to SELECT *.

Not because I didn’t know better.

But because I couldn’t admit that what I’d learned was wrong.

Unlearning is an ego check.

It requires admitting:

  • I was wrong
  • The way I’ve been doing this is suboptimal
  • I need to feel like a beginner again

Most people can’t handle that.

So they stagnate.

The developers who keep growing?

They treat unlearning as a badge of honor.

“I used to do X. I was wrong. Now I do Y.”

No shame. Just adaptation.

The world is changing faster than ever.

The half-life of technical knowledge is shrinking.

The only way to stay relevant:

Learn to unlearn.

And unlearn to learn.


What’s one thing you learned years ago that might be outdated now? Are you willing to unlearn it?