Right now it is impossible to scroll through your LinkedIn feed without being overwhelmed by posts about how great AI is and how it is going to solve all our problems and even make a lot of jobs obsolete. The opposite messaging is also there, ranging from AI is the devils work to real world experiences that dampen the hype quite a bit. I assume that as usual the truth lies somewhere in the middle. There are great use cases for AI, like everything associated with software development, but also a lot of caveats. Successful AI implementation depends on a lot of different factors. A recent Stanford Study involving 120,000 developers had some sobering findings:
- The average productivity gain for AI usage was only about 10%
- Many projects had even negative productivity gains
- Using more tokens had a very low correlation with better results
- The best success predictor was a clean code base to work with. The cleaner the code base the AI worked on the better the productivity gains. The messier the code base, the messier the results.
That of course is very bad news for many companies, because clean code bases are quite rare. Many software development organizations are drowning in technical debt. It seems like the lack of will or ability to enforce code quality, architecture and coding standards is again catching up with us.
We could say that AI repeats the patterns it finds in a code base. Good patterns lead to more good patterns generated by AI, bad patterns lead to more bad patterns. AI simply amplifies what it finds. Before AI the argument to invest in clean code and clean architecture was always that code is read much more often than it is written. Adding or changing code requires the developer to understand the context of the code he or she is working with. The messier the code base, the harder that becomes. And it turns out (surprise, surprise) that AI needs to read and “understand” code too. So we could argue, that clean code and clean architecture is now even more important than before.
Now some readers may think that this argument will become obsolete in the very near future. “Just let the AI do all the work including fixing of problems.” But anybody who worked on a real project with AI knows, that when push comes to shove, the human owns the problem and has to fix it when the AI fails to do so. Sometimes you have to interrupt the coding agent when it runs into a seemingly endless loop burning lots of tokens trying to fix an error without visible progress. At the end, while coding agents seem to be quite smart, they are just glorified and complex pattern matching engines that rely more on probability than on logic. At the end one thing will always stay true: you can only fix what you can understand.
AI and Software Architecture
In the context of this article I will define software architecture as the division of a software system into a set of clearly defined components with explicitly defined allowed dependencies between them. Each component can then again be divided in sub components – and so on. There are many more aspects of software architecture which are not relevant in the scope of this article. So here we talk about system composition and dependency structure. Actually those are things the AI does not understand out of he box, especially in a messy code base. AI coding agents always optimize locally without looking at the larger scope of a system. Therefore they tend to duplicate code where it is not needed and just look at the local context of the problem they try to solve. That leads to code bases described by an architect as “like 10 developers worked on it without ever talking with each other”.
You can partially mitigate that problem by providing architecture context information in the CLAUDE.md or AGENTS.md project files. But that is more like a suggestion than a law. What is needed is a way to guide the coding agent in the context of an architectural model. And it just so happened that we developed the perfect solution for this problem more than 10 years ago: a domain specific language to describe and enforce architectural models – the Sonargraph architecture DSL. This language can best be described as UML component diagrams in text form. And after I showed it to Claude he was quite enthusiastic about it (does he have feelings?).
This is an example of the DSL describing the layering for our new product ArcTree:
relaxed artifact View
{
include "**/com/hello2morrow/arctree/**/view/**"
include "*/icons/**"
}
relaxed artifact Controller
{
include "**/com/hello2morrow/arctree/**/controller/**"
}
relaxed artifact Model
{
include "**/com/hello2morrow/arctree/**/model/**"
}
artifact Foundation
{
include "**/com/hello2morrow/arctree/**/foundation/**"
}
The relaxed keyword (as in relaxed layering) allows downward going dependencies, so View can access Controller, Model and Foundation.
The magic about this language is that it works on a white list approach – in other words everything that is not explicitly allowed is forbidden. This stays in contrast to black list approaches implemented by tools like ArchUnit, where you need to anticipate possible violations and write rules that would catch them. White list approaches work much better with coding agents, because they can guide the AI to create the right dependencies. Once you know where you are within the architectural model it is easy to deduct what can be accessed from there.
Claude was able to guess about 80% of the semantics of the language in the first try. After some more explanations he had a good picture and was able to use it as a guide. But subtle details were harder to get right, so he proposed to develop an MCP server that would completely understand the model and could be queried about the architectural model. And that is exactly what I did with him over the next couple days. That effort resulted in a new product called “Sonargraph MCP” which can be used to guide coding agents to respect your architectural model while generating code. So instead of doing multiple iterations every time the coding agent generates code that violates architectural rules it will generate correct code on the first try. That saves tokens (=money) and time and leads to much better outcomes.
Sonargraph MCP
“Sonargraph MCP” is an add-on product for Sonargraph-Architect. All existing Sonargraph customers will get one free MCP server license per Sonargraph-Architect license. If you are a customer and did not receive the free license yet, please contact us.
Here is, how the process works:
- Use Sonargraph (26.2.0 or higher) to create any number of architecture definitions using a subset of the architecture DSL. Currently we only support Java and physical (file based) architecture models. Also only use standard patterns (no attribute retrievers like “JavaHasAnnotation”) and no artifact templates.
- Make sure the architectural models you want to use are activated in Sonargraph.
- Use “File / Export MCP Server Data…” to create an MCP server configuration file in the project root directory. This will also export all existing architecture violations in a format readable by the MCP server.
- Add the MCP server to the
.mcp.jsonfile (example below). The MCP server is shipped as a jar file that is started viajava -jar <mcp-jar-file> <license-activation-code> <directory-of architecture-mcp.json>. It requires Java 21 or higher. - Start your coding agent
- Ask “do you have a MCP server running”. If all is well it will answer yes and you can start asking questions about the architecture. While the MCP server is quite self explanatory to your agent it is always a good idea to explicitly add a rule to your
AGENTS.mdfile to consult this MCP server before adding new dependencies to the code. - If there are architecture violations you can even ask your agent to fix them. If you want them to be fixed in a very specific way, add more details to your prompt. You can also tell the agent to only fix violations originating from a specific artifact or between two specific artifacts.
- Once the agent did some changes go back to Sonargraph, refresh the system and re-export the MCP server data. This will also update the list of violations.
- After a re-export ask your agent to execute the
reload_alltool so that the MCP server model is updated.
This creates a pretty powerful development loop. If you are struggling with a messy legacy code base it is a good idea to start with a very simple model first, e.g. just define some technical layers. Then you can delegate the fixing of violations to your agent. Once he is done, you can create more specific rules until you transformed your system into a much more maintainable state. This might actually be the silver bullet that can help with fixing big balls of mud.
Here is an example .mcp.json file:
"mcpServers": {
"architecture": {
"command": "java",
"args": [
"-jar",
"<absolute path to SonargraphMcp-version.jar>",
"<license-activation-code>",
"<project root directory>"
]
}
}
Next Steps
Our next goal is to make the MCP server available for all languages supported by Sonargraph – currently C#, Java/Kotlin, C/C++, Python, Go and TypeScript. In the beginning that support will be limited to physical (file based) models.