Alberto van Oldenbarneveld

Six Months in Real Software

Notes from my first six months in a real codebase: messy frontend work, product pressure, AI, and the gap between seeing a problem and fixing it.

Laptop with code on screen

It’s been six months since I started working as a developer. I have tried to write about it a few times, but most drafts sounded more certain than I actually feel. Too much like I had already turned the whole thing into a lesson. I don’t think I have.

Clean code and real codebases

The main thing I keep noticing is the gap between learning to code in a clean environment and working inside a codebase that has been dragged through actual product decisions.

When you are learning, the world is kind of clinical: the examples are small ,the problems usually have a shape. Even when a personal project becomes messy, it is still your mess. You know where the bad decisions came from because, most of the time, you made them.

The frontend I walked into has a lot of history in it. Components that are much bigger than they should be. CSS that makes you nervous before you touch it. A lot of debt, basically. Which is kinda normal. A startup needed to ship things, and the product keeps growing, and architecture does not always get to be the first concern.

Seeing the problem is not solving it

Pretty early on I looked at the UI and thought we needed a proper design system. Tokens, consistency, shared decisions, all of that. I pushed for it at a periodical meeting, and people loved it. Made absolute sense, go for it, they said.

But then you have sit down and think about how you should it. And that’s the question: How do you introduce that into the repo without stopping everything else? Where do you start? Which pieces do you migrate first? What do you do with the weird old stuff that is half reusable and half extremely specific? How do you avoid turning a good idea into another layer of unfinished work? That was probably the first time the job felt very different from the version of programming I had in my head. That’s when I learned that seeing the problem was the easy part. Implementing the solution without breaking half the house was the work.

Most of the work is understanding

There are days where adding the actual code for a feature is not the part that takes the most energy. The harder bit is understanding where the change belongs, or refactoring the component enough that the new work does not make it worse, or touching the CSS and then checking that you have not quietly ruined some responsive layout three screens away.

I spend so much more time reading than I expected. Not even just reading code line by line. I mean reading around it. Trying to understand why something is shaped the way it is before deciding that it is wrong.

More often than not the question is: why the hell is this here?

Sometimes, after enough digging, the answer is less stupid than it looked at first. A feature started as one thing and became another. Someone reused something because there was no time. A flow that looks strange now solved a different problem six months ago. A bad abstraction exists because the alternative was worse. Other times it really is just a mess.

My taste in code has changed

My taste in code has changed because of that. I am much less impressed by clever code, because clever code is just annoying to deal with.

I like neat solutions and good abstractions. But I care a lot more about whether the code is easy to understand when you are tired, trying to trace a bug or making a small change without wanting to load the entire system into your head.

I have also become more relaxed about duplication. If removing duplication means creating a shared abstraction that everyone has to decode before making a tiny change, I am not sure that is always a win. Sometimes repeated code is ugly but understandable. Sometimes the abstraction is cleaner on paper and worse in the day to day. I’m not sure the tradeoff is always worth it.

The job is more social than I expected

That’s another thing, the job is a lot more social than I expected.

I had the headphones-on version of development in my head. Long focus sessions. You disappear into the editor and come back with code. A lot of the actual job is talking to people. Aligning with Design the intent behind the visuals. Asking why something works like this. Negotiating time lines and explaining blockers. Checking whether a change makes sense for the product. Explaining why a quick fix might create trouble later. Realizing that sometimes the blocker is not technical, but timing, priority, or the fact that the team cannot afford to open that whole area right now.

AI changes the learning curve

The AI part has probably made the whole thing feel even less stable. Some days you read someone saying that if you use AI too much, you will never really understand the code. Then you read someone else saying that writing everything by hand is already obsolete, and that the only sensible thing is to move up a level of abstraction as fast as possible. I have been stuck between those two arguments more for quite a while.

AI is very useful. Pretending otherwise feels ridiculous. It can speed you up, help you compare approaches, explain unfamiliar code, generate boring pieces, and get you unstuck when you are circling the same problem for too long. But it can also let you move faster than your understanding. There is a difference between using a tool and outsourcing the exact bit of thinking you needed to develop. The hard question for me is where that line is. What do I need to understand deeply? What can I safely delegate? When am I saving time, and when am I just postponing the moment where I have to learn how the thing works?

My guess is that the level of abstraction keeps moving up, whether I like it on any given day or not. More of the value will probably sit in architecture, data flow, product judgment, trade-offs, and knowing which problems are worth solving in the first place. But you will always need somebody still has to understand the ugly details. Somebody still has to trace the weird bug, read the old component, notice the regression, and know when a generated answer is confidently wrong.

I do not know exactly where I land yet. It is just one of the main tensions of learning this job right now.

Code is in service of the product

The other thing I keep thinking about is product.

I like the engineering side, cleaning things up, understanding flows. Taking a piece of code that feels unreadable, slowly building a mental map and turning it into something logical. But software first and foremost has to do something for someone. That may sound obvious, but you would be surprised about how very easy to forget when you are deep in the code. You can spend a lot of energy making something technically nicer and still not move the product much. And the flipside is also true, you can also ship something valuable with code that makes you wince a bit.

In the kind of environment I am in, code quality matters because it protects your ability to hold everything together. It should reduce the chances that every new feature leaves more mess behind, but it is still in service of the product. That is probably the most frustrating part so far. Sometimes it’s easier to see what good code should look like than knowing if the service it enables actually provides value.

Where I am after six months

Six months is not a lot of time. I am still very early in this and the work already looks different from what I imagined. Without talking about how fast the job seems to be changing. I’m happy though. I love solving problems. I love the feeling of taking something that seemed impossible to understand and slowly grasping it. That feedback loop keeps me going. There is always so much to do too. I’m continually turning ideas around in my head, from repo maintenance to reducing friction to new features. It’s an infinte pool to dive in, and I love it.

Very excited to see where the next six months will take me.