A Spartan did not march carrying every tool he owned.
He carried what he needed: shield, spear, sword, food, maybe a knife. The point was not minimalism for its own sake. The point was movement, readiness, and discipline. Extra weight was not neutral. It slowed the march, complicated the work, and exhausted the person carrying it.
A codebase should be treated the same way. A development organization should be treated the same way. Spartan simplicity is carrying the bare minimum required to get the work done right.
Not the bare minimum to hack it together. Not the bare minimum to look clever. Not the bare minimum to win an argument about elegance. The bare minimum to do the job correctly, reliably, and sustainably.
That distinction matters because software teams love tools. We love new frameworks, new languages, new runtimes, new patterns, new harnesses, new libraries, and new ways to make yesterday’s work feel old. That curiosity is not a defect. The industry runs on the belief that better tools are possible.
But novelty is easy to adopt and hard to carry.
Every technical choice becomes part of the team’s load. Someone has to debug it, secure it, deploy it, monitor it, document it, review it, onboard new developers into it, and explain it to the next AI agent that touches the codebase.
The question is not whether a tool is good. The question is whether the team should carry it.
Platform Choices Have Weight
At a financial services SaaS provider, the broader company had a mixture of platforms and UI stacks in use. There was .NET. There was Go. There was Angular. There was Blazor. There was React. Each choice may have made sense locally when it was introduced. Each may have solved a real problem for the person or team working in that area.
Together, they made the organization heavier.
Every platform adds cognitive load. It adds debugging load, deployment knowledge, security surface, testing patterns, hiring considerations, onboarding cost, and incident response complexity. It adds another set of conventions for humans to learn and another set of instructions for AI agents to follow.
Security and performance are the two hidden costs teams underestimate most. A new framework does not only bring new syntax and a new component model. It brings new default behaviors, new dependency trees, new authentication patterns, new rendering rules, new serialization risks, new patching needs, new performance traps, and new failure modes.
.NET and React are both powerful platforms. Used well, they can produce secure, high-performing applications. Used poorly, they can create security and performance problems that are not obvious to a team adopting the platform for the first time.
That does not make the platform bad. It makes the platform weighty.
I saw a very concrete version of this at that same company. A product I oversaw needed a dashboard application. The company stack was primarily .NET and SQL Server, and there was already a rudimentary dashboard written in C# MVC. One senior developer took a weekend with AI and built a much better dashboard in Go.
It looked great. It worked great. It was also written in a language only that developer had even started learning.
The product manager wanted to use it because it solved the immediate problem. I said it should be rewritten in C#. That was not because Go is bad. Go is a very good language. The issue was that adopting it for that product would have made one developer’s partial skill set a production dependency for the whole team.
That is the kind of trade Spartan simplicity forces into the open. A tool can be good and still be too expensive for the team to carry.
At a marketing services SaaS provider, the team had also experimented with Blazor before I arrived. They built a key internal application with it, and that application proved challenging to maintain. The problem was not that Blazor is bad. The problem was that the organization had to carry the operational, performance, maintenance, and security understanding required to support a platform the broader team did not use as its standard path.
That is the part early enthusiasm rarely prices in.
React Still Has To Earn Its Weight
I see the same question today with React.
At a marketing services SaaS provider, a number of developers have asked whether we are going to move to React. My answer, at least right now, is no.
Not because React is bad. React is excellent when the problem calls for it and the team is prepared to carry it. But our current UI standard is ASP.NET MVC with HTMX. It is understood by the team, performs well, fits our backend architecture, and gives us the interaction model we need without adopting a larger frontend platform.
React would not be free.
It would bring state management decisions, build tooling, component conventions, testing patterns, onboarding cost, AI instruction updates, and a new failure surface. It would require the team to carry a third UI paradigm because React might be useful someday or because it feels like the modern thing to do.
That is not enough. Not unless React solves a problem large enough to justify the weight of carrying it.
That is the standard every new platform should face. Does it solve a business problem we actually have? Does it fit the team’s current skill base? Can more than one person support it? Does it fit our deployment, monitoring, security, and testing model? Does it reduce total system load, or does it merely make one developer’s work more interesting?
And the hard question is whether we are willing to carry this for five years. If the answer is no, the tool has not earned its place.
Pattern Sprawl Is Weight Too
Platform sprawl is easy to see because frameworks, languages, and runtimes have names. Pattern sprawl is quieter.
Factories here. Orchestrators there. Rich domain models in one module. Anemic services in another. Singletons in the old code. DDD where one senior engineer was involved. A different shape where another developer had been reading different books that year.
I have seen this in multiple codebases. Similar problems get solved with radically different patterns depending on who wrote that part of the system and what architectural idea was popular at the time.
In one inherited codebase, some areas were standard ASPX pages. Other areas had a previous developer’s attempt at MVC. Other areas had custom ideas that were interesting, if I am being charitable.
Each decision may have been defensible locally. Together, they made the codebase heavier.
Pattern sprawl turns the codebase into a museum of past enthusiasms. Every area speaks its own dialect. The next developer has to learn not only the business behavior, but the local architectural language of that part of the system.
That load compounds. Small fixes and small tweaks become harder because you cannot assume how the feature is organized. The naming conventions may be different. The file layout may be different. The flow through the code may be different. Before you can make the change, you have to re-orient yourself to the local pattern.
Code review slows down because reviewers have to ask whether the pattern is intentional, accidental, outdated, or merely preferred. Onboarding slows down because new developers cannot trust the shape they learned in one module to apply in the next. AI agents get worse because they infer from nearby code, and nearby code may be a fossil from a previous architectural fashion.
Spartan simplicity does not mean a team uses one pattern for everything.
It means the team does not make the codebase carry five patterns where one or two would do the work. It also means introducing a pattern is a deliberate choice, not something that happens because one developer preferred it in one part of the system.
A Spartan did not randomly select a weapon or carry the one he liked most that day. He selected the weapon the situation required, then carried the cost of that choice.
Good Common Libraries Reduce Weight
There is a trap on the other side of simplicity.
Many codebases have a Utilities class or a common library that becomes the place everything homeless goes. One helper method lands there. Then another. Then a formatting function. Then a logging wrapper. Then a half-finished data helper. Then an authentication shortcut. Eventually the common library is not a shared capability. It is clutter with a namespace.
That looks like reuse. It is often shared cognitive load.
Good common libraries are different. They own specific, repeated capabilities behind stable boundaries. They reduce repeated decisions. They make the right thing easier to do.
At a marketing services SaaS provider, we have more than 20 common libraries. At first glance, that may not sound like simplicity. The important part is that they are small, focused, and independently packaged.
We have one data access library for each database so the DAL can evolve alongside that database. We have libraries for common AWS interactions, including simplifying secret usage and writing to S3 and queues. We have common libraries for handling authentication against approved platforms. We have other libraries for common application infrastructure concerns.
Each is its own NuGet package. The DALs follow standard patterns and include default behavior, like .AsNoTracking(), so developers do not have to remember the same performance-sensitive choice every time they write a query.
That is Spartan simplicity in practice: not fewer packages, fewer repeated decisions.
By breaking the libraries into small, focused packages, each application carries only the weight it needs. An app that needs one database uses that DAL. An app that writes to S3 uses the AWS library. An app that needs a specific authentication path uses the auth package that owns that concern.
That is very different from one giant common package every app references because one helper method happens to live there.
A catch-all library makes every application carry the whole junk drawer. Focused libraries let each application carry only the tools required for its job.
Repeatable Architecture Reduces Load
The same idea applies to application architecture.
At a marketing services SaaS provider, we have standardized our new architecture around ASP.NET MVC with HTMX for the UI, ECS containers for applications and APIs, and Lambdas for backend processing work.
That is not the only way to build software. It is not the trendiest way to build software. It is the way we have chosen to build because the team can understand it, repeat it, operate it, and support it.
The value is not that every application is identical. The value is that every application has a familiar shape.
Developers know where UI behavior belongs. They know where API behavior belongs. They know which hosting model applies. They know how common database access works. They know where AWS interactions should live. They know how authentication is supposed to be handled.
AI agents benefit from that too.
When the architecture is repeatable, an agent can load standards that actually apply. UI work can load UI standards. API work can load API standards. Database work can load the correct DAL expectations. The agent is not guessing from five competing local examples. It is following the shape the team has chosen to carry.
That is technical simplicity: not the absence of architecture, but the presence of repeatable architecture.
AI Has Weight Too
The AI era adds a new category of technical load.
Teams are now carrying multiple models, multiple agent harnesses, multiple instruction formats, multiple skill systems, and multiple evaluation approaches. That weight is usually lighter than adopting a new backend language or frontend framework because switching between AI tools is easier than migrating a production platform.
But it is still weight. Each harness has quirks. Each model behaves differently. Each instruction format needs maintenance. Each tool adds another place where standards can drift. Each new workflow has to be explained, taught, secured, and evaluated.
Spartan simplicity does not mean choosing one AI tool forever. That would be foolish in a market moving this fast. It means being honest about what the team is expected to carry.
That is part of why I invest in common AI instructions and an internal skills marketplace. The goal is not to pretend the variety does not exist. The goal is to reduce the cognitive weight of carrying it. Developers should not have to remember every convention, prompt pattern, model preference, and tool behavior from memory. The standards should be packaged, distributed, refreshed, and easy to load.
In practice, that means a version-controlled registry, an installer, and an update skill that refreshes each developer’s local toolkit. The marketplace turns “which skills should I use and are they current” into infrastructure instead of another thing every developer has to remember.
If two models serve different needs, carry both deliberately. If a second harness gives the team a real advantage, define where it should be used. If a skill system reduces repeated work, standardize it. If a tool mostly exists because someone wanted to try it, keep it out of the production workflow until it earns a place.
AI does not remove the carrying cost of technical variety. It gives teams more variety to carry.
The Carrying Test
Before adopting a new platform, pattern, library, harness, or tool, ask what it adds to the team’s load.
Can the team debug it?
Can the team secure it?
Can the team deploy and monitor it?
Can more than one person support it?
Can new developers learn it quickly?
Can AI agents follow the team’s standards inside it?
Does it reduce repeated work, or does it create another special case?
Are we willing to carry it for five years?
Those questions do not reject innovation. They discipline it. Some tools should be adopted. Some patterns should be introduced. Some libraries should be created. Some AI workflows should become standard practice. Spartan simplicity is not anti-technical. It is not nostalgia. It is not fear of change.
It is selective innovation. Carry what helps the team do the work right. Put down what only makes the system more interesting.
A simple stack is not a stack with nothing in it. It is a stack where everything has earned its place.
Receipts
- Financial services SaaS provider: The broader organization carried .NET, Go, Angular, Blazor, and React across different products and teams, which increased the cognitive and operational weight of normal development.
- Go dashboard field note: A senior developer built a strong dashboard prototype in Go for a .NET and SQL Server product, but the language choice would have made one developer’s partial skill set a production dependency.
- Marketing services SaaS provider: The team standardized new UI work on ASP.NET MVC with HTMX, ECS containers for applications and APIs, and Lambdas for backend processing work.
- Common libraries: The marketing services SaaS provider maintains more than 20 focused NuGet packages, including database-specific DALs, AWS helpers, authentication libraries, and common infrastructure packages.
- AI skills marketplace: The internal skills marketplace packages and refreshes shared AI skills so developers do not have to carry every convention, prompt pattern, model preference, and tool behavior in memory.