What this note is really about

When people first encounter terms like:

  • MVC
  • MVP
  • MVVM
  • layered architecture
  • clean architecture
  • hexagonal architecture
  • onion architecture

it can feel like software design is full of competing acronyms invented to sound clever.

That is not the right way to look at it.

These patterns exist because software becomes hard to manage when:

  • UI logic, business logic, and data access all get mixed together
  • responsibilities are unclear
  • dependencies point everywhere
  • testing becomes painful
  • change in one part breaks unrelated parts

So this note is not mainly about memorizing acronyms.

It is about understanding:

  • what problem these patterns are trying to solve
  • why so many variants exist
  • what the major patterns are
  • how they compare
  • where each one fits well

The point is to become fundamentally clear-headed about why structured software patterns exist at all.


The first principle: these patterns exist to manage complexity

The broad problem is simple:

As software grows, one big pile of code becomes hard to:

  • understand
  • change
  • test
  • reuse
  • reason about

So developers try to separate concerns such as:

  • presentation
  • user interaction
  • business rules
  • data access
  • external system integration

These patterns are all, in one way or another, attempts to answer questions like:

  • where should UI logic go?
  • where should business logic go?
  • who talks to the database?
  • how should dependencies flow?
  • how can we make code easier to test?

So the right mindset is:

these patterns are organizational responses to recurring software problems

They are not laws of nature.


The second principle: no pattern is universally best

A common beginner mistake is to ask:

  • which pattern is the best one?

That question is usually too vague.

A better question is:

  • what problem am I solving, in what kind of software, with what complexity?

For example:

  • a desktop UI app has different pressures from a backend API
  • a CRUD admin tool has different pressures from a long-lived domain-heavy system
  • a small internal tool does not need the same architecture as a platform product

So patterns are tools, not medals.


The underlying recurring concerns

Before naming patterns, it helps to identify the recurring concerns they are trying to separate.

These usually include:

  • presentation: what the user sees
  • input handling: what happens when the user interacts
  • application flow: coordinating use cases
  • domain logic: business rules and core concepts
  • persistence: databases and storage
  • infrastructure: external services, files, messaging, frameworks

Different patterns separate these concerns in different ways and at different levels of strictness.


A useful distinction: UI patterns vs architectural patterns

Not all of these patterns live at the same level.

UI or presentation patterns

These mainly organize interaction between:

  • screen
  • user actions
  • state
  • presentation logic

Examples:

  • MVC
  • MVP
  • MVVM

Application or system architecture patterns

These mainly organize larger-scale dependencies and boundaries across the whole application.

Examples:

  • layered architecture
  • clean architecture
  • hexagonal architecture
  • onion architecture

This distinction matters because people often compare patterns that are not really at the same layer.

For example:

  • MVC and hexagonal architecture are not direct substitutes in the strictest sense

One often describes presentation structure, while the other describes larger dependency boundaries.


Start from the oldest broad problem

Early software often became tangled because code for:

  • screen rendering
  • event handling
  • business rules
  • and storage

all lived together.

That made every change risky.

For example:

  • changing the UI could break domain rules
  • changing database code could affect view rendering
  • testing business logic required spinning up screens

Patterns like MVC emerged to reduce this entanglement.


MVC: Model-View-Controller

MVC is one of the most famous software structuring patterns.

At a broad conceptual level:

Model

Represents the application’s data and often domain-related state or rules.

View

Represents what is shown to the user.

Controller

Handles input and coordinates what should happen next.

The controller receives user actions, interacts with the model, and decides what view or response should be produced.

This was a major improvement over dumping everything into one place.


Why MVC existed

MVC existed to separate:

  • user interface rendering
  • user interaction handling
  • application data/state

The key benefit was not the acronym itself.

The key benefit was that it reduced direct coupling between visual representation and core logic.

This improved:

  • maintainability
  • reuse
  • testing
  • conceptual clarity

That is the core reason MVC became influential.


MVC in practice

In real systems, MVC has been interpreted differently across frameworks.

Examples:

  • Ruby on Rails
  • ASP.NET MVC
  • Spring MVC
  • Django’s structure, though not always described exactly the same way

In many web frameworks, “controller” became:

  • the class or function receiving HTTP requests

“View” became:

  • HTML templates or rendered responses

“Model” often became:

  • a mixture of domain objects, validation, and database-backed entities

This is important because “MVC” in framework marketing and “MVC” as a clean conceptual pattern are not always identical.


Common weakness of naive MVC

MVC can become weak when the “model” or “controller” absorbs too much.

Common problems:

  • fat controllers
  • anemic models
  • database entities treated as the whole domain
  • business logic scattered between controllers and services

So simply saying “we use MVC” does not guarantee good design.

MVC helps, but it does not replace disciplined responsibility assignment.


MVP: Model-View-Presenter

MVP evolved as another way to separate UI and behavior, especially in environments where UI event handling became awkward.

At a broad level:

Model

Represents data and domain or application state.

View

Represents the UI surface, often kept relatively passive.

Presenter

Contains presentation logic and coordinates between model and view.

The presenter often becomes the main testable unit for UI behavior.


Why MVP existed

MVP became attractive because people wanted:

  • thinner UI code
  • more explicit presentation logic
  • easier unit testing of UI-related behavior

Especially in older desktop or event-heavy UI frameworks, keeping the view passive and pushing logic into a presenter could be much cleaner than putting behavior directly into the UI layer.

So MVP is often a stronger “passive view” answer than naive MVC.


MVP in practice

In MVP:

  • the view usually exposes an interface
  • the presenter talks to the view through that interface
  • user actions are translated into presenter logic

This can work very well when:

  • UI logic is non-trivial
  • testability matters
  • the framework otherwise encourages code-behind chaos

But MVP can also become verbose if the app is simple.

You may end up writing a lot of glue code for small benefit.


MVVM: Model-View-ViewModel

MVVM became especially popular in UI frameworks that support:

  • data binding
  • observable state
  • declarative UI updates

At a broad level:

Model

Represents domain data or application state.

View

Represents the UI.

ViewModel

Represents the state and behavior the view needs in a UI-friendly form.

The ViewModel is often not the domain model itself.

It is a presentation model shaped for the view.


Why MVVM existed

MVVM became useful because some UI platforms made it practical for views to bind directly to state exposed by a ViewModel.

That allowed developers to avoid:

  • large amounts of manual UI update code
  • tangled event wiring
  • direct business logic inside the UI layer

MVVM is strongly associated with technologies such as:

  • WPF
  • Silverlight historically
  • Xamarin
  • .NET MAUI in some styles
  • Android architecture patterns
  • some JavaScript frontend frameworks in spirit, though not always formally labeled MVVM

The key advantage is that UI state and behavior can be exposed in a testable and bindable way.


ViewModel is not just “model but renamed”

This is a frequent confusion.

A ViewModel is usually:

  • tailored to a screen or view
  • shaped for display and interaction
  • often includes derived display state
  • often exposes commands or bindable properties

For example, a domain Order object and an OrderDetailsViewModel are not the same thing.

The ViewModel may include:

  • formatted strings
  • UI-specific flags
  • loading state
  • selection state
  • validation messages

That is why MVVM can be very powerful for rich UIs.


Common weakness of MVVM

MVVM can become weak when:

  • ViewModels become giant dumping grounds
  • too much domain logic leaks into ViewModels
  • bidirectional binding becomes hard to reason about
  • hidden coupling through binding magic makes flow unclear

So while MVVM can be elegant, it can also become opaque if not kept disciplined.


PAC, HMVC, and other presentation variants

There are other UI-structuring patterns too, such as:

  • PAC: Presentation-Abstraction-Control
  • HMVC: Hierarchical Model-View-Controller

You do not need to memorize all of them deeply at first.

The important takeaway is that many UI patterns are variations on the same broad attempt:

  • separate display
  • separate interaction coordination
  • separate state or domain concerns

The names differ because different frameworks and eras emphasized different pain points.


Layered architecture

Now move from UI patterns to broader application structure.

One of the most common system-level patterns is layered architecture.

A typical layered structure may include:

  • presentation layer
  • application or service layer
  • domain or business layer
  • data access or persistence layer

Each layer has a broad responsibility, and higher layers depend on lower ones.

This is one of the most widespread software patterns because it is easy to understand and teach.


Why layered architecture existed

Layered architecture exists because applications often need clear separation between:

  • what handles requests or UI
  • what coordinates use cases
  • what enforces business rules
  • what talks to storage or external systems

It helps teams answer:

  • where should this code go?
  • what should depend on what?

That clarity is very valuable in medium-sized systems.


Strengths and weaknesses of layered architecture

Strengths

  • simple mental model
  • clear separation
  • familiar to many developers
  • works well for many business applications

Weaknesses

  • can encourage over-layering and boilerplate
  • business logic may still leak into service or controller layers
  • domain layer may become weak if everything depends on persistence models
  • dependency direction is sometimes not strict enough for highly complex systems

Layered architecture is often a solid default, but not automatically a perfect one.


Three-tier architecture

A closely related term is three-tier architecture.

This usually refers to broad deployment or logical separation such as:

  • presentation tier
  • application tier
  • data tier

This term is often more infrastructural or system-level than MVC or MVVM.

It is important historically, but in practice many modern systems use more flexible service boundaries and do not always fit the clean classic three-tier picture.

Still, the core idea is the same:

separate concerns so each area can evolve more cleanly.


Clean architecture

Clean architecture is a broader architectural style emphasizing:

  • clear dependency direction
  • strong domain focus
  • independence from frameworks
  • separation between business rules and infrastructure

At a high level, the idea is:

  • the core business logic should not depend on outer technical details
  • frameworks, databases, and UI should depend inward on the core, not the other way around

This is a powerful idea because it protects the most important rules of the system from incidental technology choices.


Why clean architecture existed

It existed because many systems became too dependent on:

  • frameworks
  • ORMs
  • UI tooling
  • databases

When business rules become entangled with those outer layers, changing anything becomes painful.

Clean architecture tries to preserve the core by making dependencies point inward.

This often leads to concepts like:

  • entities
  • use cases
  • interface adapters
  • infrastructure implementations

Even if you do not adopt the full terminology, the dependency-direction idea is extremely valuable.


Onion architecture and hexagonal architecture

These are closely related to clean architecture.

Onion architecture

Emphasizes concentric layers with the domain at the center and infrastructure outside.

Hexagonal architecture

Also called ports and adapters.

It emphasizes that the application’s core should talk through abstract ports, while concrete adapters handle:

  • databases
  • web frameworks
  • messaging
  • file systems

These patterns are all trying to solve a similar problem:

keep the core application logic independent from external mechanisms

The vocabulary differs, but the philosophical direction is similar.


Ports and adapters: the key idea

In hexagonal architecture, the application core defines what it needs through abstract interfaces or ports.

Examples:

  • OrderRepository
  • PaymentGateway
  • NotificationSender

Concrete infrastructure then implements those interfaces:

  • SQL repository
  • Stripe adapter
  • email provider adapter

This is attractive because:

  • business logic can be tested in isolation
  • infrastructure details stay replaceable
  • external systems are clearly treated as dependencies, not as the core

This pattern is especially useful in systems with rich domain logic and multiple integration points.


Clean/hexagonal/onion are not UI patterns

This is worth stating explicitly.

MVC, MVP, and MVVM mainly organize interaction around the presentation layer.

Clean, onion, and hexagonal mainly organize dependencies and boundaries for the application as a whole.

You can combine them.

For example:

  • a desktop app may use MVVM for UI and a clean-architecture style for domain/infrastructure separation
  • a web app may use MVC at the HTTP layer and hexagonal ideas internally

So do not treat these pattern families as if only one may exist in a codebase.


Repository and service layers

While not always treated as whole-application architecture patterns on their own, these are very common structuring patterns.

Repository

Abstracts persistence access in domain-friendly terms.

Service layer

Coordinates use cases or business operations that do not belong directly in one entity.

These often appear inside:

  • layered systems
  • clean architecture
  • hexagonal designs

They help answer:

  • where do workflows go?
  • where do storage concerns go?

But they can also be overused if turned into generic dumping grounds.

For example:

  • UserService, OrderService, DataService, EverythingService

without clear responsibility boundaries is not good architecture.


How many such patterns are there?

There are many named patterns, but you do not need to treat them as an endless list to memorize.

At a practical level, the major ones worth understanding early are:

  • MVC
  • MVP
  • MVVM
  • layered architecture
  • three-tier architecture
  • clean architecture
  • onion architecture
  • hexagonal architecture
  • ports and adapters

You should also understand common companion ideas such as:

  • repository
  • service layer
  • dependency injection
  • domain model
  • presentation model

There are more patterns beyond these, but these form a strong conceptual foundation.


Why so many patterns exist

Because software contexts differ.

Different patterns became popular in response to:

  • desktop UIs
  • web request-response systems
  • enterprise backend systems
  • domain-heavy business applications
  • systems requiring testability and framework independence

Also, some patterns are really:

  • refinements of older ones
  • renamings of similar principles
  • framework-era adaptations

So the sheer number of patterns should not make you think software design is arbitrary.

It means recurring problems were attacked from slightly different angles.


Framework examples, briefly

It helps to attach names without going deep.

MVC-associated ecosystems

  • Ruby on Rails
  • ASP.NET MVC / ASP.NET Core MVC
  • Spring MVC
  • Laravel in broad structure

MVVM-associated ecosystems

  • WPF
  • Xamarin
  • .NET MAUI
  • Android architecture patterns
  • some reactive frontend patterns conceptually

MVP-associated ecosystems

  • older WinForms practices
  • older Android patterns in some teams
  • various desktop UI systems where passive view testing mattered

Clean / hexagonal / onion usage

These appear more as architectural styles than as one framework feature.

You will see them discussed in:

  • ASP.NET backend systems
  • Java/Spring backends
  • domain-driven design oriented codebases
  • microservice and service-platform codebases

The key point is that frameworks may encourage patterns, but the patterns are conceptually larger than the frameworks.


Comparison: what each pattern optimizes for

MVC

Optimizes for:

  • separating input handling, view, and model
  • straightforward request/response or UI organization

Good when:

  • you want a familiar structure
  • the app is not unusually complex
  • the framework already supports it naturally

MVP

Optimizes for:

  • explicit presentation logic
  • passive views
  • testable UI behavior

Good when:

  • the UI framework tends to create messy event code
  • you want stronger testability of presenter logic

MVVM

Optimizes for:

  • bindable UI state
  • declarative UI updates
  • rich desktop or app-style interfaces

Good when:

  • the framework supports binding well
  • screen state is substantial
  • UI responsiveness and state synchronization matter

Layered architecture

Optimizes for:

  • simple broad separation of concerns
  • team clarity
  • maintainable medium-scale systems

Good when:

  • the system is business-oriented
  • domain complexity is moderate
  • you want a practical general structure

Clean / onion / hexagonal

Optimizes for:

  • strong core-domain protection
  • dependency discipline
  • testability
  • framework and infrastructure independence

Good when:

  • the system has important business logic
  • the system will live a long time
  • infrastructure should not dominate the domain
  • you integrate with many external systems

Common misuses

Patterns often fail not because the pattern is bad, but because it is misunderstood.

Common misuses include:

1. Cargo cult adoption

Using a pattern because it sounds professional, without understanding its purpose.

2. Excessive layering

Creating many layers with no meaningful responsibility separation.

3. Anemic domain models everywhere

Pushing all real logic into services and leaving models as data bags.

4. Framework worship

Letting the framework’s default file structure become the architecture without deeper thought.

5. Pattern mixing without clarity

Combining patterns in a way that obscures who owns what.

6. Overengineering small systems

Applying heavyweight architecture to tiny tools where it adds more ceremony than value.

This is why pattern knowledge must be paired with judgment.


How to choose a pattern

The right way to choose is not:

  • which acronym is fashionable?

It is:

  • what kind of software is this?
  • where is the complexity?
  • what kind of change do I expect over time?
  • what kind of testing matters?
  • how much UI state exists?
  • how rich is the domain logic?
  • how coupled do I want to be to the framework?

These questions guide better choices than pattern branding.


Practical advice by context

Small internal CRUD web app

Usually:

  • simple MVC or layered architecture is enough

Do not force elaborate clean-architecture ceremony unless the complexity truly demands it.

Rich desktop or mobile UI app

Usually:

  • MVVM is often attractive if the UI technology supports binding
  • MVP may also work if you want explicit presentation logic

Large business backend with meaningful domain logic

Usually:

  • layered architecture at minimum
  • clean, onion, or hexagonal ideas become more valuable

Integration-heavy service or platform

Usually:

  • ports and adapters or hexagonal thinking is very helpful

Why?

Because many external dependencies should remain outside the application core.

Short-lived prototype

Usually:

  • prefer simplicity
  • structure enough to avoid chaos, but do not overbuild

The architecture should fit the expected lifespan and complexity of the software.


Testing and these patterns

One major reason many of these patterns became popular is testability.

Examples:

  • MVP allows presenter logic to be tested without real UI
  • MVVM allows ViewModel behavior to be tested without full screens
  • clean architecture allows use cases to be tested without database or web framework
  • hexagonal architecture allows adapters to be swapped with mocks or fakes

So if you ask:

“Why are engineers willing to accept more structure and abstraction?”

one real answer is:

because isolated testing becomes much easier.

That matters a lot in systems that must evolve safely.


Dependency direction is one of the deepest ideas here

Many patterns differ in surface structure, but a very deep recurring question is:

what depends on what?

That question matters because dependencies shape:

  • coupling
  • replaceability
  • testing
  • change cost

Shallow design often lets everything depend on everything.

Stronger design usually tries to ensure that:

  • UI depends on core logic, not vice versa
  • infrastructure depends on abstractions, not the core depending directly on vendor details
  • business rules are not trapped inside framework code

If you understand dependency direction, you understand one of the most important reasons these patterns exist at all.


These patterns are not substitutes for good thinking

A codebase can say:

  • MVC
  • clean architecture
  • MVVM

and still be poorly designed.

Why?

Because naming a pattern does not automatically solve:

  • unclear responsibilities
  • bad naming
  • overgrown classes
  • weak domain understanding
  • poor boundaries

Patterns are organizing tools.

They help good thinking scale.

They do not replace good thinking.


The most important conceptual thread

If you want one flow that ties the whole topic together, it is this:

Software patterns such as MVC, MVP, MVVM, layered architecture, clean architecture, onion architecture, and hexagonal architecture exist because growing software needs clear separation of concerns and disciplined dependency structure. UI-oriented patterns mainly separate what is shown, how user interaction is handled, and how presentation state is represented. Larger architectural patterns mainly separate business rules from infrastructure, frameworks, persistence, and external systems. The many named variants exist because different eras, frameworks, and kinds of software exposed different pain points, but the underlying goals are very consistent: reduce coupling, increase clarity, improve testability, and make change less painful over time.


What you should come away knowing

You should leave this topic with these ideas clearly separated:

  1. These patterns exist to manage complexity, not to create ceremony.
  2. MVC, MVP, and MVVM are mainly presentation-structuring patterns.
  3. Layered, clean, onion, and hexagonal are broader architectural patterns.
  4. A ViewModel is not just a renamed model; it is usually a presentation-shaped state object.
  5. Ports and adapters are about protecting the application core from infrastructure details.
  6. No one pattern is universally best.
  7. The right choice depends on software type, complexity, and expected evolution.
  8. Testability and dependency direction are major reasons these patterns matter.
  9. Frameworks may encourage patterns, but frameworks are not the same thing as architecture.
  10. The deepest recurring question is always: which responsibilities belong where, and what should depend on what?

Bottom line

Patterns like MVC, MVP, MVVM, layered architecture, clean architecture, onion architecture, and hexagonal architecture are different answers to recurring software design problems. They exist because software becomes difficult when presentation, behavior, domain rules, persistence, and infrastructure are tangled together. If you understand what concern each pattern is trying to separate, what level of the system it applies to, and how it shapes dependency direction, then the acronyms stop feeling arbitrary and become practical tools for designing clearer systems.