Skip to main content
Back to Blog
Building software for future me
Development

Building software for future me

Daniel Wohlfarth
Daniel WohlfarthJul 1, 20267 min read
#software-engineering
#ai
#architecture
#developer-experience
#maintainability
Building software today with future developers in mind — lessons on architecture, decisions, and maintainable systems.

A few years ago I opened an old project again that I had not touched in a long long time.

It was a strange feeling because I still remembered building it. I remembered the ideas behind it, some of the features, the problems I was trying to solve. Looking at the repository felt a little bit like opening an old notebook. At first I thought:

“This is actually pretty good.”

And then, a few minutes later:

“Why did I do it like this?”

The funny thing was that the code was not bad. It was running. The application was still alive. Some of the decisions were actually still decisions I would probably make today. But there were other parts where I had no idea what I was thinking. Not because the code was impossible to understand. I could read it. I could follow what happened. I just did not remember why.

Why this abstraction? Why this structure? Why this database decision? Why not the simpler solution?

And that is probably one of the most interesting things about software that lives for a long time. The code stays, but the moment in which the code was created disappears.

When you build something, you always have a lot of invisible context. Conversations with teammates. Things you tried before. Limitations you knew about. Problems that happened in another part of the system. None of that is visible when someone opens the code later. Sometimes that someone is another developer.

Sometimes it is you.


Building for a future that does not exist yet

When I started programming, I thought becoming better meant simply writing better code.

I spent a lot of time thinking about structure. Clean code. SOLID. Design patterns. Making things reusable. Avoiding duplication. Creating the right abstractions. And all of these things are important. But over time I realized that I sometimes optimized for the wrong thing. I optimized for a future that did not exist yet.

I wanted everything to be flexible because maybe one day we would need it. A simple feature became a generic system. A small change became another abstraction layer. A thing that should have been easy to understand required knowing several other concepts first. The problem was never that abstractions are bad. They are incredibly useful when they solve a real problem.

The problem is that every abstraction has a cost. Someone has to understand it. Someone has to maintain it. Someone has to make a change later. And that someone might be me.


The software that outlives the original idea

I have tons of projects that are many many years old. Projects that were supposed to be temporary. Small tools. Experiments. Things that grew. Small apps and big sites. Somehow, they are still alive.

And that changed how I think about building software.

You are not only building something for the user today. You are building something for the person who has to work on it later. And sometimes that person is not someone else. Sometimes it is just you, a few years from now, looking at code you once wrote and trying to understand what you were thinking.

That changed how I think about comments and naming.

I used to think comments were there to explain code. But if I need a comment to explain what a function called addRecipe() does, the problem is probably not the missing comment.

The problem is the name.

A function name is not just a label. It is part of the context you leave behind. A few years later, future me might look at addRecipe() and ask:

“Add where?”

To the database? To a menu? To a shopping list? To a user’s collection?

The code might still work. The function might still be understandable. But the original intention is gone.

A better name removes that question.

Comments should explain the things the code cannot explain:

Why did we choose this approach? Why is this thing intentionally different? Why does this weird-looking code exist?

Those are the things future me cannot recover from reading the code alone..


Documentation as external memory

Documentation is similar. Nobody really wakes up and thinks:

“Today I want to write beautiful documentation.”

But good documentation is one of those things you appreciate when you need it. The difficult part is not writing more documentation. The difficult part is writing the right documentation.

Nobody wants a huge document that explains everything and nobody reads. What I care about more today are the decisions.

Why did we build it this way? What alternatives did we consider? What should someone know before changing this?

ADRs, RFCs, decision logs, README files, architecture notes. They are basically external memory. Because human memory is terrible. Especially when the software outlives the person who created the decision.


AI changed the way we think about context

Interestingly, AI made this topic even more relevant.

For a long time we wrote documentation mainly for other developers. Now there is another reader.

AI.

AI can understand code extremely well. It can explain functions, suggest improvements, and help you navigate a codebase. But it has the same problem a new developer has. It only knows what exists. It was not part of the discussion. It does not know why the team rejected another solution. It does not know that this strange workaround exists because something broke in production two years ago.

If that information only exists in someone’s head, AI cannot access it.

And then it has to guess.

Sometimes it guesses correctly.

Sometimes it creates a very convincing explanation that is completely wrong.

This is why I think good documentation will become even more important. Not because AI replaces developers, but because understanding software becomes even more valuable.


Names, commits, and the story of a codebase

The same applies to naming and commits.

I spend much more time naming things today than I used to.

Because names are not just labels. They create a shared understanding.

Sometimes the best refactor is not adding another layer. It is renaming something.

A service. A module. A concept.

The code stays the same, but suddenly everyone understands what it represents.

Commits are similar. A codebase has a history. A commit like:

fix stuff

might contain a good change, but future me will have no idea what happened.

A commit like:

feat(recipe): add recipe ownership checks before allowing updates

already tells a small part of the story. The history of a system matters.


Tests are what allow change

I also changed the way I think about tests.

I love tests. I also hate writing tests sometimes.

Because writing tests is easy. Writing good tests is hard.

A good test is not there to prove that your code works today. A good test gives you confidence when you change it tomorrow. Because the biggest advantage of tests is not preventing bugs. It is making change safer.

And software is basically change.


Building software today

Today, when I start building something bigger, I spend more time thinking before writing code.

Sometimes that means writing things down. Usually on paper.

I tried using whiteboards, but honestly, paper works better for me. There is something about physically writing things down that helps me understand the problem.

Sometimes I talk with teammates. Sometimes I build a small proof of concept. Sometimes I ask AI questions. Not because I want AI to make decisions for me. But because it is a great way to challenge my thinking.

  • “Did you consider this?”
  • “What happens if this changes?”
  • “Is this complexity actually necessary?”

The best tools do not replace thinking. They improve it.


Future me will read this again

Maybe in a few years I will open this article again. Maybe I will disagree with some of it. Maybe I will think some of these ideas were good but incomplete.

That is probably going to happen.

And honestly, I hope it does.

Because it means I learned something. I do not expect future me to look back and think everything was perfect.

I only hope future me understands why.

Because the best thing you can leave behind in software is not perfect code. It is enough context for someone—even yourself—to continue the story.