Why Architecture Matters More in the AI Era (Not Less)
Many people think that since AI can write code, architecture becomes less important.
The opposite is true.
I witnessed this firsthand when I ran an experiment with AI building a complex networking project. The results changed how I think about architecture in the AI era.
The Experiment
I asked an AI to build an HTTP benchmarking tool—a C-based project with epoll event loops, TLS encryption, multi-threading, and QuickJS embedding. Not a toy project. Real complexity.
Day 1 results:
- ~2000 lines of working C code
- Code compiled and ran
- Achieved 140,000+ QPS (comparable to the industry-standard
wrktool) - All features functional
Everything worked. But when I examined the architecture, I found chaos:
What AI Produced:- Connection layer embedded HTTP parser directly- Each fetch() call created its own epoll instance (pseudo-async)- Three different timer implementations coexisted- Request types split into two unrelated hierarchiesThe code worked perfectly. But I couldn’t modify it safely.
The Cost Equation Has Flipped
Here’s the core insight: AI has driven the cost of writing code close to zero. But the cost of managing complexity hasn’t changed at all.
Traditional Development: Time spent: +-- Architecture: 20% +-- Coding: 60% +-- Review/Testing: 20%
AI-Assisted Development: Time spent: +-- Architecture: 60% <-- MORE important +-- Coding: 5% <-- AI handles this +-- Judgment/Review: 35% <-- NEW focusWithout architectural guidance, AI generates what I call efficient technical debt machines. They work today. They’ll collapse tomorrow when you need to add a feature.
Why This Happens
AI writes code like a bricklayer laying bricks fast and well. But architecture is the blueprint.
Without blueprints, you get walls everywhere and no livable house.
I saw this clearly when the AI generated a connection structure:
// AI's approach: Everything piled togethertypedef struct connection_s { int fd; int state; http_parser parser; // HTTP knowledge embedded char buffer[4096]; // Buffering mixed in rbtree_node_t timer; // Timer implementation coupled int request_type; // Request state scattered void *request_data;} connection_t;This works. But every concern is tangled with every other. When the HTTP parser changes, the connection struct changes. When timer implementation changes, the connection struct changes. When I need to reuse connections for a different protocol, I’m locked in.
I gave the AI an architectural constraint:
“Separate concerns into distinct concepts. The connection layer shouldn’t know about HTTP.”
From this one sentence, the AI derived the refactoring:
// Proper layering with clear abstractionstypedef struct connection_s { int fd; int state;} connection_t;
typedef struct http_peer_s { connection_t *conn; http_parser *parser; buffer_t *in; buffer_t *out;} http_peer_t;
typedef struct timer_s { rbtree_node_t node; void (*handler)(void *data); void *data;} timer_t;Now each concept is isolated. I can test each component independently. I can reuse the connection layer for WebSockets or custom protocols.
The Three Judgments AI Cannot Make
In my experiments, I identified three types of judgment that require human experience:
1. Judgment of Problems
The AI’s fetch implementation was pseudo-async—creating independent epoll instances per call. This isn’t a single-line bug. The entire I/O model is wrong.
AI doesn’t know this is a problem. I knew because I’ve done event-driven architecture at NGINX for years.
2. Judgment of Direction
When I said “global event loop + pending Promise,” this one sentence defined the entire async architecture direction. The AI correctly modified 9 files based on this constraint.
But that sentence itself requires experience. AI can execute direction. It cannot generate direction.
3. Judgment of When to Suspect
All tests were green. Functionality worked. At this point, most people would think “done.”
But I continued reviewing and found a subtle bug that would cause all 16,576 test cases to fail under specific conditions. Not because I’m smarter, but because experience tells me “when it looks too smooth, there’s often a problem.”
What Architecture Means in the AI Era
Here’s what confuses people about architecture:
# NOT architecture (AI can do this):def process_request(request): validate(request) transform(request) save(request)
# IS architecture (human must define):# - Which layer owns validation?# - How do layers communicate?# - Where is complexity isolated?# - What concepts deserve their own types?The first is implementation. The second is design. AI excels at the first. Only humans can do the second.
The Quality Gap I Measured
After scoring both the AI-only code and the human-guided architecture, I found:
| Category | AI-Only | After Architecture | Gap |
|---|---|---|---|
| Functionality | 8/10 | 8/10 | 0 |
| Readability | 8/10 | 8/10 | 0 |
| Async Design | 7/14 | 14/14 | +7 |
| Abstraction Quality | 5/9 | 9/9 | +4 |
| Maintainability | 4/7 | 7/7 | +3 |
| Code Organization | 5/8 | 8/8 | +3 |
| Total | 59/105 | 85/105 | +26 |
Notice: functionality and readability unchanged. The entire 26-point gap came from architectural dimensions.
Common Mistakes When Using AI for Development
I’ve made these mistakes. Learn from them:
Mistake 1: Trusting Tests Over Architecture
“All tests pass” proves nothing if the tests share AI’s blind spots. AI-generated tests for the HTTP tool checked that responses returned correctly. They didn’t check that the event loop could handle 10,000 concurrent connections without locking up.
Mistake 2: Reviewing Functionality, Ignoring Structure
Code reviews focus on “does this work?” and “is this readable?” They skip “does this fit our architecture?” and “will this scale?”
Mistake 3: Giving Solutions, Not Constraints
I’ve seen prompts like “add a connection pool.” AI adds one. But it’s the wrong abstraction for the problem.
Better: Say “we need to handle 10K concurrent connections with bounded memory” and let AI propose solutions. Then evaluate proposals against architectural principles.
The Shift in Developer Value
This isn’t about AI replacing developers. It’s about developers doing different work:
| Era | Developer Focus | Time Distribution |
|---|---|---|
| 1990s-2000s | Writing code | 70% coding, 30% thinking |
| 2010s-2020s | Writing + Reviewing | 50% coding, 50% reviewing |
| 2024+ | Architecture + Judgment | 10% coding, 90% judgment |
The future developer doesn’t write functions. They make architectural decisions. They set constraints. They judge trade-offs.
Related Concepts Worth Knowing
The “Two Pizza Team” Rule (Amazon): Small teams can build big things. But only with clear architectural boundaries. AI amplifies this—small teams with AI can produce enormous amounts of code. Architecture becomes the limiting factor, not velocity.
Conway’s Law Revisited: “Organizations design systems that mirror their communication structure.” With AI, the communication structure is: human to constraint to AI to code. The architecture must be explicitly stated, not implicitly discovered through team interaction.
The Sapir-Whorf Hypothesis for Code: The language and abstractions we use shape how we think. AI thinks in patterns it has seen. If you want different architectural thinking, you must provide different architectural vocabulary.
What I Do Now
After these experiments, I’ve changed my workflow:
-
Start with architecture diagrams before any code. Not detailed designs, but component relationships and data flow.
-
Define constraints first: “The authentication module never touches the database directly” or “All external API calls have timeouts and retries.”
-
Let AI implement within constraints: Give AI the boundaries and let it fill in the details.
-
Review for architecture drift: Does the generated code respect the constraints? Often AI will “helpfully” violate a constraint because it saw a pattern in training data.
-
Refactor before it grows: Don’t let AI add one more feature to a module that’s already doing too much.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments