Always take a peek beneath the abstraction.

Every layer saves you time, until it hides the reason something broke. So for your own peace of mind, understand how each layer works.

7 days ago
Always take a peek beneath the abstraction.

Until a while ago, monorepos were one of those things I knew I needed to learn, but somehow never really did.

Not because I never tried. I tried. Quite a bit, actually. The issue was that my approach was garbage.

What I would usually do was initialize a Turborepo project, look around for a bit, then jump straight into the code and start changing things. In my head, that counted as learning by doing. But looking back, I was basically just wandering around a structure I did not understand and hoping the understanding would just... happen.

It did not happen.

I would move things around, rename a few files, poke at configs, run commands I only half understood, and end up even more confused than I was at the start. There was no actual learning there.

Eventually, I accepted that I needed to do the thing most people hate doing: go through the documentation properly. Page by page. No skipping around, no “I’ll just figure it out as I go”, none of that.

So I did. And somehow, that accomplished in two days what months of stumbling around had failed to do. The difference between the two approaches was pretty simple.

In the first one, I took the abstraction as-is and immediately tried to build on top of it.

In the second one, I took time to understand how it worked beneath the surface, and that made it way less of a black box.

That is a pattern I keep running into.

Software is built in layers, right? Languages hide machine details. Frameworks hide repeated language-level work. CLIs hide framework setup. Libraries hide implementation details. AI tools hide chunks of actual thinking and implementation. And to be clear, that is fine. That is how progress works. If we all had to start from scratch every single time, software development would be quite annoying.

Abstractions are useful. Very useful. They save time. They save effort. They spare you from rewriting the same boring stuff over and over again. They let you build bigger things faster, which is great, because I do not think any of us got into this because we enjoy hand-rolling boilerplate for fun.

But here is the catch. Every abstraction leaks.

Sooner or later, something weird happens. Auth stops working as expected. Your data no longer matches what you thought your schema said. A page becomes weirdly slow. A tool spits out code that looks fine until you actually rely on it. Stuff works, but only in the very fragile sense of the word “works”.

And when that happens, it is no longer enough to know the surface. You need to be willing to go one layer down.

Not all the way down, by the way. I am not doing that thing where people start sounding like the only morally pure form of programming is writing assembly in vim with no internet. Relax. The point is not to reject abstractions. The point is to not become completely helpless inside them.

That was my problem with monorepos.

The issue was not that Turborepo was impossibly complex. The issue was that I had no real mental model for what it was organizing, why it was structured the way it was, or what problem it was trying to solve in the first place. So every folder felt arbitrary. Every config felt magical. Every command felt like some little weird thing I was expected to respect without understanding.

That is a very frustrating place to be. Because when you do not understand the shape of the thing, every change feels random. You are not really making decisions at that point. You are just doing stuff and seeing what explodes.

Reading the documentation changed that, because it gave me a map. It made the structure make sense. I could finally see what belonged where, why packages were split the way they were, how tasks flowed, what the tooling was actually trying to optimize for.

Once that clicked, the whole thing became far less intimidating. Not easy, necessarily. Just legible.

And that matters a lot. Because once something becomes legible, you can reason about it. You can make changes with intent. You can tell when something is off. You stop treating the tool like magic and start treating it like, you know, a tool.

That is the bit I think matters.

You do not need to constantly live beneath the abstraction. That would be exhausting, and also kind of dumb. The whole point of abstractions is that they save you from having to think about everything at once.

But you should be willing to peek beneath them. That little habit goes a long way.

If something feels off, go one layer down. If a tool is being weird, go one layer down. If some generated output looks correct but feels suspicious, go one layer down. Read the docs. Inspect the structure. Check what the thing is actually doing for you instead of just what it appears to be doing.

A lot of the time, that is where the answer is.

And yes, AI fits into this too, but only because it is just another layer in the stack. A very useful one, obviously. But still a layer. It can speed things up, sure. It can also produce nonsense with a level of confidence that would be impressive if it were not so annoying. So the same rule applies there too: use it, absolutely, but do not stay at the surface.

That is really what I learned from the monorepo thing.

I did not get comfortable with it by trying harder on the surface. I got comfortable with it by making it less mysterious. And that's the balance I am trying to keep now.

Use abstractions. Use them aggressively, even. They are there to save you time.

Just do not trust them so blindly that they turn into a blindfold.

Because the moment one of them cracks, and one eventually will, you want to be the person who knows how to look underneath.