Blog

coding

How to stay a good software engineer despite AI

Preserving the art of sustainable software craftsmanship: building robust, lasting systems rather than succumbing to the cycle of throwaway code

August 21, 2026 9 min read Marvin Drude
C#.NET

Preamble

To kick off this article, I want to make one thing clear: I actually find AI to be a very useful tool in my day-to-day work as a software engineer. But not in the way that is often promised across the web, where people tell you to generate as much code as possible, wire up agent loops, or obsess over prompts. My approach to AI is far more pragmatic, and that's what I want to share here.

Why write about this? To answer that, I have a confession to make: I did try out the workflow of generating a lot of code, acting purely as a reviewer, and nudging things here and there. It was only three weeks on and off, but that was more than enough time to realize that this cannot be a sustainable path forward for any software meant to be maintained or loved by its creators.

At first, I found myself heavily adjusting the output and iterating relentlessly to reach the shape I envisioned. But over time, that discipline eroded into accepting more and more compromises, code that was functional, but nowhere near the quality standard I hold myself to when writing by hand. Don't get me wrong: the code worked, and overall you could still look at it and say, "Yeah, it's good enough." But that is the exact mindset I've spent my entire career avoiding. I love crafting creative, elegant, and high-performance solutions. None of that could be said about my generated code after a while.

Not only did my quality standards slip, but I also found it harder to come up with original, creative solutions on my own (a skill I had spent years cultivating). There was always that "easy button" in the back of my mind: "If I just do this problem with AI, I can be done immediately in a mediocre way and move on to the next problem faster."

I kept promising myself: The next problem, I'll solve cleanly and creatively on my own again. But I was lying to myself; it rarely ever happened. Going to bed felt unfulfilling, and I wasn't proud of my code anymore, there were just too many mediocre compromises.

Fast-forward to today: I completely reversed this depressing three-week phase. I am back to loving writing code by hand, coming up with my own creative solutions, and staying plenty productive, both at work and on my personal projects.


My take aways on 3-week agentic


1. The "Reviewer's Illusion" or I like to call it the fatigue of shallow reading.

Reviewing AI code feels fast, but it is actually more mentally draining than writing it. When you write code, you construct a mental model in your working memory. When you read AI Code, your brain engages in passive pattern-matching. You will miss subtle edge cases, architectural drift, and problems in another module only loosely dependent on your new code or vice versa.

Because the code looks syntactically professional and correct, and even smart. But AI after all, does not understand your code. It will never do so. And therefore there is a new type of bug that is even harder to spot than most others.

2. The "Good enough" ratchet.

As I described above in my 3-week adventure into agentic coding, your standards erode over time and your code will be moving more and more to the statistically average code the AI was trained on. And let me tell you, you typically do not want the statistically average code to be inside your project.

A ratchet only turns one way. When you start generating code, you promise yourself that you will rigorously refactor every AI output to match your pristine personal standards.

  • On Day 1, you ruthlessly rewrite half the snippet to eliminate heap allocations and enforce strict invariants.
  • By Day 7, you let a few unnecessary allocations slide: "It's not the hot path, and the tests pass."
  • By Day 14, you stop checking whether the abstraction makes sense: "It works, let's ship it and move on."

I personally hate this mindset.

3. The Loss of the "Mental Map".

If you go into a project that you built and maintained for a long time by hand. You have a very clear mental model and map about what code does what and where a potential problem at 2 AM in the morning in production could originate from. If everything is generated by AI mostly, you will lose this ability and solely rely on AI.

You put yourself into the role of a tourist in your own code base.

When you spend hours wrestling with a complex problem by hand, the friction is not wasted time. That friction is the process of etching a high-resolution map of the architecture into your brain. You know every load-bearing wall, every quirk of the protocol, and exactly why that weird guard clause exists on line 87.

4. The local optimum trap.

AI writes code that solves the immediate 20 lines (local optimum) while completely disregarding system-wide idioms, allocation patterns, or lifetime management (global optimum).

A scenario as example: You spent some thoughtful time carefully designing a zero-allocation pipeline using ReadOnlySpan<char>, ArrayPool<> and custom enumerators.

You or a coworker ask AI to format a token or extract a substring. It gives you a clean, elegant one-liner using .Split(), string.Join() or a LINQ chain.

The Impact: It solves the requirement perfectly, to someone who is not currently much into performance or does not know this is a hotpath, it will still look great, all tests pass. But quietly blows up the GC allocation budget of your entire hot path.

5. The "10:1 Debugging Ratio" (Keystrokes are cheap)

The Trap: Generating 500 lines of code in 5 seconds feels like 10x productivity. But in reality writing the code takes 1x effort, debugging clean code takes 2x effort. Debugging 500 lines of subtly flawed, non-deterministic AI code where you don't possess the mental model takes 10x effort.

6. The "Deliberate Delinking" Workout

If you always use AI autocomplete / copilot, your brain slowly loses its ability to hold complex algorithmic state in working memory (cognitive offloading). If you cannot completely restrain from using AI in your Job, I at least highly advise AI-Free sessions to always stay in the groove.

My rules moving forward

Preserving the art of sustainable software craftsmanship: building robust, lasting systems rather than succumbing to the cycle of throwaway code

I created a ruleset for myself on how and for what I use AI in my days as a programmer:

  1. Generating code (what people call agentic)
    • As production code: Never do this, not even for small fixes (only for repetitive tasks after coding the original one by hand)
    • Spinning up a fast POC for something you wanna test: Go ahead, it's also fun to explore the crappy code sometimes
    • Creating Benchmarks quickly: Go ahead, create throwaway benchmarks like foreach vs Linq
    • Tests: Previously I rarely did take the effort to write them, so having this automated is wonderful since AI's usually doing an okay job at them. Better having some of these tests than none.
  2. Finding and understanding Repositories
    • This is honestly a huge win. Being able to quickly pinpoint how other people did something in their code
    • Clone yourself a big repository and ask the AI, so how did they solve X. Great for learning
  3. Very rare and obscure errors
    • Something that we as developers had spent a lot of time on in the past, which we can now shortcut. But it is really important to actually learn about what the error meant and why it happened.
  4. Code-Reviews
    • I still think it is very important to have real people code review your PR's BUT having AI do a base line scan and find off-by-one errors etc. is still really helpful and I wouldn't want to miss that anymore. (There are of course a lot of false-positives)
    • Paste your hand-written code into the chat and prompt it to be an adversarial reviewer:
      • "What concurrency race conditions or deadlocks could happen here?"
      • "What boundary inputs or Unicode edge cases will break this parser?"
      • "If the remote socket disconnects mid-frame, how does this state machine leak resources?"
  5. Spec reading
    • Reading 100-page RFC specifications can take hours or days. Use AI as an interactive Index to speed up the process of reading

You might have caught on a theme here: I am trying my best to optimize everything around the actual coding, because coding by hand, is what I truly enjoy and care about when it comes to quality. Therefore, my way of boosting some of my productivity is by simplifying the processes around that, not the coding itself.

The Long-Term Compounding Effect

When we look at software development through the lens of pure typing speed or lines committed per hour, AI wins every time. But software engineering was never about typing speed; it is about managing complexity and designing systems that survive change.

When you write code by hand, you pay the cost upfront during creation. When you generate code, you defer the cost to the maintenance and debugging phase with high interest. The friction you experience while designing clean abstractions, zero-allocation loops, or robust lifetime boundaries is not lost productivity; it is the compound interest of understanding your own system.

The Friction is the Teacher

There is an uncomfortable catch-22 emerging in our industry: To effectively review AI code, you must already be an expert. But if you rely on AI from the start, you will never develop the intuition required to review it.

Intuition is not born from watching syntax appear in an editor; it is forged by spending three hours chasing a subtle race condition or debugging an unexpected memory leak under load. If we remove all friction from our craft, we also remove the very process that turns junior developers into seasoned architects.

AI as a Sparring Partner, Not the Driver

The trap lies in treating AI as an author and yourself as an editor. The dynamic should be the exact opposite: You are the author, architect, and craftsman; AI is your research assistant and adversarial sparring partner.

Let it do the grunt work of indexing large RFCs, summarizing third-party API quirks, or poking holes in your hand-written concurrency logic. But the architecture, the mental map, and the actual implementation of core domain logic must remain yours. That is where both quality and engineering joy live.

Closing words

There is still so many topics I could dive into deeper when it comes to Software-Engineering and AI Usage. But I really wanna get back to coding right now, so I better stop rambling here :)

Thank you for reading until here and always remember:

You cannot become a great writer by only reading books.

You cannot become a pro chess player by only watching games.

You cannot become a great programmer by only reviewing AI code.

An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.