Five Observations Working with Claude Code

2025, so far, has been the year of Vibe Coding after Andrej Karpathy coined the term in February. Aside from vibe coding, which carries a negative connotation for many, AI-assisted coding has become a standard, also in professional software development.

While I would not consider myself a professional software engineer by any stretch of the imagination, I do write a lot of code, and AI code assistants have become a part of my workflow. While I do not develop and/or design software on a day-to-day basis, I have a good understanding of what good software and good software design are supposed to look like – this certainly also influences how I’m using coding assistants and what I expect from them.

It began with GitHub Copilot, then I used quite a bit of Cursor, and being a proponent of open source AI/LLMs, I’m recently playing around with Crush a lot. That said, when I need to get work done, Claude Code – despite the price – is still my go-to solution.

Being on the Max plan and having used Claude Code quite extensively over the last couple of months, I wanted to share a few observations as well as some early insights. Some of these observations certainly also are valid for other assistants, but my focus is Claude Code – currently using both Opus 4.1 and Sonnet 4.5.

Five Observations

So, let’s get going! Here’s my – definitely not exhaustive – list of observations from working with Claude Code almost daily. Following these observations, I will also share some of my best practices that help address some of the problems I will highlight.

It Enables Me to Do More but Makes Me Lazy and Less Confident

I fully understand the issues that many take with actual vibe coding. At least for now, I’m relatively sure that in the hands of people without any software development experience, tools like Claude Code will do more harm than good. They produce functional products, but these products, more often than not, are unmaintainable, and we don’t even have to talk about the security implications.

That said, Claude Code enables me to develop software faster and it enables me to push my own boundaries. Having Claude by my side not only makes me faster but also enables me to build things that I couldn’t create without extensive research and learning. In my experience, when working with Claude Code well, it’s worth its price and its worth the wait between sessions. Although I regularly get angry about waiting for a tool that costs me 100€+/month.

Interestingly, however, I’m more and more dependent on the tool. I now regularly see myself questions whether I could do it (or should do it) myself or if Claude would do a better job than myself. Having this tool by my side also carries the risk of making myself more lazy – there are instances in which I’d rather wait for two hours (session reset) than implement a simple change by myself.

That being said, I’m well aware that my time could be better spent on other tasks and I’m still able to make my own decisions. Nevertheless, it is interesting to observe how this tool is, despite me being very aware of it, changing my thought processes and behavior.

It Learns From Examples and Its Great at Reverse Engineering

Claude Code is great at learning from examples and it is also great at reverse engineering. I regularly show it examples, including the output of other tools or even “unknown” format, and let it build from there.

While this workflow doesn’t come without risks, it works very well. Of course, this also works great for understand code bases, file formats, protocols etc. So whether I want to understand something (even my own codebase) or implement something new, I start by showing Claude examples and let it reverse engineer from there.

It Finds Hacky Ways to Solve Complex Problems

In my experience, code (and documentation) reviews are crucial when working with Claude Code. While, at least in my opinion, it rarely fails to create a working solution, it very often finds extremely overengineered and hacky solutions to relatively simple problems.

Hence, “it works as intended” is most definitely not a good metric for AI generated code. Instead, I’m constantly reviewing the changes Claude Code introduces and “solve the underlying issue and don’t create a hacky solution” has become a staple of sorts.

This also leads to a situation in which keeping the project maintainable becomes an even more constant task than it already is. The moment I start using Claude Code, especially for larger features, I’m likely introducing new maintainability issues. Of course, this is a trade-off and through good prompting and reviews, these issues can be reduced quite well.

It Makes Things About the Project Up

Even when following best practices – for example, those outlined by Anthropic – Claude Code seems to love to make new things up. Whether it is features, new ideas for documentation, or best practices, Claude Code loves to “improve” beyond what I told it to do.

A simple example: I asked it to streamline a series of documentation files I had for a project. Generally speaking, it did a great job, but it also introduced several new “ideas,” including a Discord group, a new support e-mail, and a series of best practices for new developers. Of course, all of these were added, with the utmost confidence, through the documentation.

Put differently: Despite using CLAUDE.md, spec files, etc., I am having a really hard time keeping Claude Code within the scope of what I want it to do.

It Gets Stuck in the Current Context and Ignore the Rest

Generally speaking, it’s a good idea to keep Claude Code’s context as focused as possible. I usually reset the context after each completed task or feature. If done consistently, many common issues are gone!

However, a related, and significantly trickier, challenge is the fact that Claude Code often only selectively looks at files and parts of the project. For instance, when I request a refactor of existing code based on a recent change (e.g., a change in data structures), there’s a good chance it will only refactor about 1/3 of the affected files, all while claiming it has reviewed the entire project with utmost confidence.

Although this issue can be mitigated through the use of tools, I simply don’t trust Claude Code to consider the whole project, even with a relatively small codebase.

Some of My Best Practices

There are many best practices when working with AI coding assistants such as Claude Code, including the ones by Anthropic themselves. Therefore, I am not even attempting to create an exhaustive list of best practices. Instead, I want to share five things that have helped me significantly with some of the issues outlined above:

  1. I keep and maintain a solid CLAUDE.md for each project and I ask Claude Code to update this file regularly. I also work with subagents and also let Claude Code update these for me.
  2. I work with specification files – i.e., simple markdown files outlining the features, changes, etc. I am envisioning. I also let Claude Code modify these files, make notes, etc.
  3. I am relying on Git to track and review all changes that Claude Code is making. I also use more advanced features such as Worktrees to keep track of changes.
  4. I am relying on linters (and similar tools), Git hooks, as well as unit tests to help me ensure maintainable and working code. While these are not catching everything, they really help with keeping the code maintainable and prevent, at least sometimes, regression.
  5. I work with custom slash-commands to regularly let Claude Code check and optimize its own work. This also work great for regularly updating CLAUDE.md as well as agent defintions etc.

Conclusion

I strongly believe that AI-assisted coding is one of the best use cases for LLMs. Generative AI, in the form of increasingly powerful LLMs, has rightfully become an integral part of software engineering, and I am happy that it has. Learning how to program many, many years ago, I would have wished for a co-intelligence that could help me solve tricky problems and that would help me get unstuck!

That said, state-of-the-art coding assistants make coding look trivial. It has, and this is exciting, become incredibly easy to create functioning software that does what it’s supposed to do. However, good software and good software engineering are more than just creating something that works. It is also creating something that is maintainable, efficient, safe, trustworthy, etc. And these, for now, are precisely some of the areas that require design and engineering competencies, even if it looks as if developing software has been “solved.”