Skip to content

Development

First (and Last?) Steps With OpenSpec

OpenSpec brings spec-driven development (SDD) to AI coding assistants. The idea is that we move away from vibe coding and use well-established practices for software development inside our AI coding tools. While I love the idea, my first experience was not that promising. Let us see what happened.

Why Requirements Matter So Much for AI Coding Agents

AI coding agents are impressive. Give them a prompt, and they can scaffold apps, write tests, refactor code, and even debug tricky issues. That speed makes them feel almost magical. But anyone who has used them on a real project learns the same lesson quickly: the quality of the output depends heavily on the quality of the requirements.

Requirements are not bureaucratic overhead. They are the map for what to build. A human developer can often fill in missing context through experience, conversation, and judgment. An AI coding agent cannot do that reliably. Combine that limitation with the agent’s speed, and you get a recipe for disaster. High-speed development does not help when you move in the wrong direction.

So how do teams find the right direction? With requirements. But as with all important things, it is not as easy as it looks.

The Prototype Trap

When we use AI coding tools we have to be careful that we do not fall into the prototype trap. Then just because we can prompt a prototype in a few hours does not mean we can take a few additional sessions and turn it into an application. Let us see what I mean by that.

Claude Code Basics: Improve Your Workflow and Save Tokens

Last week we jumped right into the command line interface of Claude Code and vibe coded a tiny application. While this works with larger applications, it is not the best use of our tokens. If we do not want to explain everything every time we come back to Claude, we need a bit more structure. That will help us with fixing wrong technology choices as well. Let us see how easy it is to get more out of Claude Code.

Getting Started With Claude Code

AI tools for code generation are currently the hot topic. Wherever you look, there are tons of articles and videos that show you how easy it is to start and how you can turn your idea into an application. Between you and your dreams is just a 20$ a month subscription and then everything will be great.

If you are a bit more realistic, you know that there is a hook and that the advertised benefits are too good to be true. On the other hand, the tools are much better than what many sceptics say that claim the AI coding tools can only produce slop and are useless. As so often, these tools are multipliers and the better you know how to use them and what their limitations are, the better the results you get.

Over the next weeks I like to take a closer look at various parts of the development process using AI coding tools. I will use Claude Code, because I find it currently the most useful one.

Create Sortable GUIDs With UUID Version 7 in .NET

GUIDs are great for generating unique identifiers across distributed systems, since they need no centralised coordination and are globally unique. But their randomness comes with a price tag when we use them in relational databases: fragmented indexes, slower inserts, and no sense of order.

Since .NET 9 we get an out of the box solution that fixes this problem: UUID version 7. We can keep the upsides of a GUID while we can get rid of the downsides - by just using a different method to create our identifiers. Let us explore how that works.

A Shorter Way for Null Guard Clauses in C

When we want to make sure that our method only accepts values that are not null, we can write guard clauses like these on top of the method:

string Combine(string address, string city, string zipCode)
{
    if(address == null)
    {
        throw new ArgumentNullException(nameof(address));
    }
    if(String.IsNullOrEmpty(city))
    {
        throw new ArgumentNullException(nameof(city));
    }
    if(String.IsNullOrWhiteSpace(zipCode))
    {
        throw new ArgumentNullException(nameof(zipCode));
    }

    // Do the work
    return $"{address} - {zipCode} {city}";
}

That works, but as you can see in this little example, this uses many more lines to check the data than it uses to do the work itself. Is there a better way to get this functionality?