Does AI Change How We Structure C# Projects?

I’ve been using AI assistants to write and change code. This has made me look more closely at how easy it is to find all the code involved in a single operation.

Take an order API. A new rule says that orders above a certain value need approval before they are sent to a supplier.

The request enters through a controller. The controller calls a service, which calls another service. Validation lives elsewhere. A handler is registered automatically at startup. There is also a background job that sends orders without going through the controller.

If I know the project well, I may remember all these paths. An AI assistant has to find them. It can add the approval check to the service used by the controller, run the tests, and report that the task is done. The background job will still send orders without approval.

A developer new to the project could make exactly the same mistake.

Keeping Related Code Together

I prefer to keep the code for a business operation reasonably close together. For an order request, that might include the request type, validation, handler, and tests in one feature area.

This does not mean putting everything in one file. It also does not remove shared services or database rules. But it gives someone changing the operation a better chance of finding the code they need.

AI assistants benefit from this because they work with a limited amount of context. Developers benefit because they have limited time and can also overlook a code path.

Making the Rules Visible

Some projects rely heavily on conventions. A class is discovered through assembly scanning. A name determines which handler is selected. The team knows which feature may call which service, but the compiler does not.

Those choices can work well. The trouble starts when you need to change something and cannot easily see what will be affected.

For important boundaries, I like to use the tools C# already gives us. A separate project can restrict dependencies. An internal type cannot be used from everywhere. An explicit interface shows what another part of the system is allowed to call.

I would not add a new project for every small feature. I would use these boundaries where breaking the rule could cause a real problem.

The same goes for dependency injection. Automatic registration saves code. Explicit registration makes the connection easier to find. Neither is always better. The useful question is whether someone can see how the feature is wired when they need to change it.

Structure Is Only Part of the Answer

Even if the order code is easy to find, we still have to understand the rule. What happens when an order’s value changes after approval? Does the background job check approval again? Can a cancelled order be sent?

Moving files into a feature folder will not answer those questions. Tests, examples, and a conversation with the people who know the process might.

I don’t think we need a new kind of architecture for AI. When an assistant misses part of a feature, I ask whether a developer unfamiliar with the project would have missed it too. If the answer is yes, making the code easier to follow is probably worthwhile, regardless of who writes the next change.

Leave a Comment