DEV Community

Mark
Mark

Posted on

The Mental Model I Use Before Touching Any Codebase

After 25+ years in the IT industry, I've developed a mental model that completely changed how I approach any codebase. This is the framework I wish someone had handed me early in my career.

They don't teach the real world in bootcamps. Get 25 years of production-grade experience on my YouTube: πŸ› οΈπŸ‘‰ https://www.youtube.com/@lessonsfromproduction


⚑ Typing First Is a Trap

The fastest way to get humbled as a developer? Open a new codebase and immediately start typing.

I've done it. You've probably done it. And if you haven't done it yet β€” you will, and you'll remember it for the rest of your career.

Because here's the thing nobody tells you early on: the instinct to just start coding feels completely rational. It feels like the right move. It feels productive.

And that's exactly what makes it dangerous.

Productive-looking is not the same as actually productive. What you're doing is optimising for the appearance of progress. And that confidence? It costs you later.


πŸƒ Speed Feels Like Progress (But It's a Lie)

Let's talk about why smart developers do this.

You get assigned a ticket. You open the repo. And instead of slowing down, something in your brain goes: "I'll figure it out as I go."

And honestly? That impulse makes sense. The industry rewards people who move fast. Standups reward people who "made progress." PRs reward people who shipped something. Nobody in a sprint review has ever said, "Wow, great job spending two days just reading."

So you skim. You find something that looks like where your code should go. You start typing. You feel productive.

That feeling is lying to you.

Because what you're actually doing is optimizing for the appearance of progress while quietly increasing the probability that you break something important.

The industry doesn't reward speed. It rewards not breaking important things. Those are not the same game.


🌱 Junior vs Senior: It Comes Down to One Question

Here's the real shift β€” and this is the thing I wish someone had told me earlier.

Less experienced developers ask: "Where do I add my code?"

They aim at a location. They skip the context. They optimise for speed and skim the system.

Senior engineers ask: "What is this system actually trying to do?"

That sounds like a small difference. It is not a small difference.

One question aims you at a location. The other aims you at understanding. And when you're working inside a system you don't fully understand, location without understanding is just a more confident way to make a mess.

Senior engineers read way more than they write. They spend time feeling unproductive on purpose β€” because they've learned that the pain of confusion up front is a lot cheaper than the pain of a production incident at 2am.


πŸ“‹ A Half-Day Ticket. Real Consequences.

Let me tell you about a time I learned this the hard way.

Early in my career, I was asked to add a small feature to a payments service. Nothing crazy β€” just a new field on an existing form, persisted to the database. I looked at the model, found where the other fields lived, added mine, wrote a migration, opened a PR. Done in half a day. Felt great.

What I did not do was trace where that data actually went after it was saved.

Turns out that model was being serialized and sent to a third-party payment processor. My new field showed up in the payload. The processor didn't know what to do with it. The new field silently corrupted the payment payload.

Transactions started silently failing for a small percentage of users. Not all users. Not in a way that threw an obvious error. Just... some people couldn't check out.

We caught it because someone noticed the revenue graph looked weird.

That was my field. That was my half-day ticket. That cost way more than half a day to fix.

A codebase is not a text file. It's a living, connected system. And systems have consequences that travel far from where you touched them.


🧠 The Mental Model: 6 Steps Before You Type

So now β€” before I touch anything β€” here's how I actually think about it.

πŸ“– Step 1 β€” Read Before You Write

Boring advice. Necessary advice.

I'm not looking to understand every line. I'm looking for the patterns. How do they name things? How do they structure modules? What does "normal" look like in this codebase?

If I write code that fights the existing conventions, I've already created a problem β€” even if it works.

πŸ—ΊοΈ Step 2 β€” Map the System

What talks to what? Where are the boundaries?

I'm not trying to memorize the architecture. I just need a rough map. You cannot make good local decisions without some understanding of the global structure you're operating inside.

πŸ”„ Step 3 β€” Follow the Data

This one is underrated.

Don't just read the code β€” trace what the data actually does. Where does it come in? How does it get transformed? Where does it go?

The logic only makes sense once you understand what it's operating on. Following data flow will tell you more about what a system is actually doing than reading a hundred function signatures.

🚨 Step 4 β€” Find the Entry Points and Risky Paths

Where does a request land? What are the high-traffic paths? What's the code that, if it breaks, someone gets paged immediately?

I want to know where the landmines are before I start walking.

βœ… Step 5 β€” Read the Tests

If they exist. Big if.

But when they do exist, they are the most honest documentation in the entire codebase. They show you what the code is supposed to do, not just what it does.

And if there are no tests? That's not a greenfield opportunity. That's a warning sign. Proceed accordingly.

πŸ” Step 6 β€” Ask Why Before How

If something looks weird β€” an unusual pattern, a strange condition, a function that seems way more complicated than it needs to be β€” do not touch it until you understand why it's there.

There's a 70% chance it exists for a real reason: a business rule, a past bug, an edge case from three years ago. And a 30% chance you're about to find out the hard way.


πŸ’‘ Three Shifts That Actually Matter

Upgrade #1 β€” Change the Question

Stop asking: "Where do I add my code?"

Start asking: "What breaks if I change this?"

That single reframe will save you from more production incidents than any linting rule ever will.

Upgrade #2 β€” Change the Time Horizon

Slow now versus broken at 2am β€” choose your pain wisely.

Short-term speed is always a trade against long-term consequences. Know which one you're optimizing for.

Upgrade #3 β€” Change the Incentive Lens

Before you merge anything β€” ask yourself: who gets paged if this goes wrong?

Is it you? Is it your team lead? Is it the on-call engineer who had nothing to do with this change?

That question will focus your attention faster than any code review checklist.


🎯 The Challenge

Next time you open a codebase β€” don't type anything for 30 minutes.

Just read. Map. Follow the data. Find the edges. Ask why.

It will feel unproductive. Do it anyway.

Because you've been trying to get better at writing code faster. That's the wrong target.

The actual upgrade β€” the one that separates senior engineers from everyone else β€” is getting better at understanding systems before you touch them.

The most dangerous developer in the room isn't the one who writes bad code. It's the one who writes confident code inside a system they don't understand.

Don't be that person. You're better than that. You just needed to aim at the right target.


I've been working in the IT industry for over 25 years. If this helped you think differently about how you approach code, drop a comment below β€” I'd love to hear what your biggest challenge is when jumping into a new codebase.

Follow me here on dev.to for more no-fluff advice straight from the trenches of a Senior Developer.

Top comments (13)

Collapse
 
itskondrat profile image
Mykola Kondratiuk

the productive-looking vs actually productive framing is the one. I fell into this so hard early on - open ticket, grep for the thing, start editing, wonder why tests break in 5 unrelated places. now I spend the first 20-30 minutes just reading. not even searching, just following the execution path from the entry point. feels slow but you catch the assumptions the previous dev made, which is usually where the real bug lives

Collapse
 
lessonsfromproduction profile image
Mark

Yep, catching the assumptions is the whole game. Half the time, the bug isn't even a bug; it's two devs who had different mental models of what a function was supposed to do, and nobody wrote it down πŸ˜„

Collapse
 
itskondrat profile image
Mykola Kondratiuk

the undocumented mental model mismatch is the hardest one to debug because there is no error message. just two people who thought they were talking about the same thing and weren't

Collapse
 
trinhcuong-ast profile image
Kai Alder

Step 3 (follow the data) is the one that took me longest to internalize. I used to treat code like a text adventure game - just navigating function to function. But once I started actually tracing what the data looks like at each step, everything clicked differently.

One thing I'd add: git blame is underrated for step 6. When you see something weird, checking who wrote it and when often leads you to a PR with context you'd never get from the code alone. Sometimes it's a bandaid from 3 years ago. Sometimes there's a whole Slack thread linked. Either way, you're not guessing anymore.

The payments example is painfully relatable. Nothing humbles you like silently breaking something that touches money.

Collapse
 
lessonsfromproduction profile image
Mark

"Sometimes it's a bandaid from 3 years ago" - yes, totally agree, how many times have you seen a //ToDo comment in some code from years ago πŸ˜…

Collapse
 
larsfaye profile image
Lars Faye | Confident Coding • Edited

Short-term speed is always a trade against long-term consequences. Know which one you're optimizing for.

YES. I'm currently watching my kid learn how to play the flute and they keep wanting to go faster. And I keep reiterating that speed is a natural byproduct of proficiency. Once you understand, and are proficient in something, you naturally will move faster. And so speed should never be the thing that is prioritized, lest you will sacrifice your understanding

Collapse
 
lessonsfromproduction profile image
Mark

"Speed is a natural byproduct of proficiency" -Totally agree, when I was learning to play the guitar and wanted to play fast. After I slowed things down and got muscle memory, I was able to start playing faster.

Collapse
 
kwun_ng_a66e33742de275cb7 profile image
Kwun Ng

Really solid advice here. The distinction between asking 'where do I add my code' vs 'what is this system trying to do' is something I had to learn the hard way early in my career. Taking 30 minutes to read before writing anything has saved me countless hours of rework on large codebases.

Collapse
 
lessonsfromproduction profile image
Mark

Thanks. Yes, I think we all made that mistake; I know I did!

Collapse
 
leob profile image
leob

Agreed 100 percent, but well:

"Next time you open a codebase β€” don't type anything for 30 minutes. Just read."

No-brainer - who in their right mind would not do this when starting to work on an entirely new codebase? For something substantially big and complex, change "30 minutes" to "at least a day" ...

Collapse
 
lessonsfromproduction profile image
Mark

Yes, it was born from observation of some of the juniors I have mentored. They were so eager to get started, they would literally start refactoring code as soon as they opened the IDE... πŸ€”

Collapse
 
sreno77 profile image
Scott Reno

Great tips Mark!

Collapse
 
lessonsfromproduction profile image
Mark

Thanks Scott, appreciated