DEV Community

Cover image for AI Found the Architecture Problems Your Team Stopped Seeing
vladimir ivanov
vladimir ivanov

Posted on

AI Found the Architecture Problems Your Team Stopped Seeing

Six architectural structures colliding into a web of circular dependencies

Every codebase starts with the same intention:

"Let's structure this properly so it stays maintainable."

And then reality happens.

We don't pick one structure. We pick several. And that's where most architectural problems begin.


Why architecture advice only works in small systems

Most architecture discussions quietly assume something important: a small-to-medium codebase with clear ownership boundaries.

In that world, layers are easy to enforce, dependencies are visible, structure matches intent, and refactoring is local. So advice like "use feature-based structure" or "follow clean architecture" actually works.

But that's not the world most long-lived systems live in.

In a large monorepo, boundaries are softer, ownership is shared, changes are continuous, and multiple architectural styles inevitably coexist. Most importantly:

Structure is no longer enforced — it is negotiated.

Feature boundaries overlap domain boundaries. Layers leak across features. Shared utilities become dependency hubs. Events connect everything indirectly. The system is no longer structured in one way. It is structured in several competing ways at once.


The six structures — and where each one breaks

1. Layer-based (MVC)

/controllers  /services  /models
Enter fullscreen mode Exit fullscreen mode

Separate code by technical responsibility. It feels clean and familiar — most frameworks push this by default.

Where it breaks: Features get scattered across layers. Changes require touching multiple folders. Services become dependency hubs.

Hidden failure mode: everything depends on everything through the service layer.


2. Feature-based (vertical slicing)

/orders  /payments  /shipping
Enter fullscreen mode Exit fullscreen mode

Group everything needed for a feature together. Improves local reasoning and reduces navigation overhead.

Where it breaks: Shared logic gets duplicated or pushed into "common." Features slowly become mini-monoliths. Cross-feature dependencies emerge anyway.

Hidden failure mode: "shared" logic becomes the new service layer.


3. Domain-based (DDD)

/orders  /pricing  /shipping  /returns
Enter fullscreen mode Exit fullscreen mode

Model the real world — business concepts first. Aligns code with how the business thinks.

Where it breaks: Domains are harder to define than expected. Boundaries shift over time. Subdomains start depending on each other.

Hidden failure mode: "domain purity" collapses under real change pressure.


4. Layer + feature hybrid

/orders/ui  /orders/domain  /orders/infra
Enter fullscreen mode Exit fullscreen mode

Combine feature isolation with internal layering — the "best of both worlds."

Where it breaks: Complexity is duplicated per feature. Cross-feature duplication increases. Inconsistencies appear between features over time.

Hidden failure mode: you scale structure, not understanding.


5. Component-based (frontend)

/components/Button  /Modal  /Table
Enter fullscreen mode Exit fullscreen mode

Build reusable UI building blocks. Maximises reuse and design consistency.

Where it breaks: Business logic leaks into components. Components become over-generalised. State dependencies become tangled.

Hidden failure mode: reuse becomes coupling in disguise.


6. Event-driven / capability-based

/billing-events  /order-events  /shipping-events
Enter fullscreen mode Exit fullscreen mode

Structure around events or system capabilities. Decouples systems and enables scalability.

Where it breaks: Execution flow is hard to trace. Dependencies hide inside event subscriptions. Debugging requires system-wide reasoning.

Hidden failure mode: coupling disappears visually but remains logically.


What happens when you mix them

Most real codebases don't follow one structure. They follow all of them at once:

  • features contain layers
  • layers contain features
  • domains overlap features
  • components leak business logic
  • events connect everything

And then we wonder why every change touches something unexpected.


Why mixing produces cycles

Circular dependencies are not random. They appear when the feature boundary and the domain boundary disagree about who owns a piece of logic — so both reach for it.

  • Feature A needs logic from Feature B
  • B already depends on shared services from A
  • Domain boundaries don't match feature boundaries
  • Layer boundaries don't match runtime dependencies

So instead of a direction, you get a loop:

Cycle diagram: Feature A, Service B, and Domain C forming a circular dependency

This is not a bug in the code. It's a contradiction in the structure.


AI makes it impossible to ignore

AI coding tools don't introduce circular dependencies — they expose them.

In a well-structured codebase, AI feels almost invisible: it suggests changes within clear boundaries, works inside a single module, rarely needs to cross the system.

In a poorly structured monorepo, something different happens. A single change pulls in multiple unrelated modules. Refactoring suggestions span half the system. AI has to load far more context than expected.

AI does not assume architecture — it discovers it.

Circular dependencies used to be easy to live with: "it still builds," "we know why it happens," "it's just legacy glue." AI removes that tolerance. Every action becomes a dependency trace — what imports what, what impacts what, what breaks if changed. Circular dependencies stop being abstract warnings. They become visible symptoms of how far the system must travel to answer a simple question.


The conclusion

Every structure works — but only when it's consistent.

The moment you mix models, you stop having architecture and start having accidental connectivity. That's exactly where circular dependencies come from. Not from bad code. From conflicting ideas about how the code is supposed to be organised.

And AI is the first tool that makes that contradiction impossible to ignore.

Top comments (0)