When I first started learning software architecture, I thought it was mostly about remembering names:
MVC.
MVP.
MVVM.
Clean Architecture.
Repository.
Use Case.
Domain.
Data.
But after working with real applications, I realized that architecture is not really about memorizing these names.
The more important question is:
When an application grows, where should each piece of logic actually live?
That question is what helped me understand MVVM and Clean Architecture more clearly.
This article is my attempt to explain both concepts in a practical way, without treating them as complicated rules or a collection of folders.
When a Simple Application Starts Becoming Complicated
Imagine we start with a simple expense-tracking application.
At first, the application might only need:
- A screen to enter an expense
- A button to save it
- A list showing expenses
Everything feels simple.
But then the application grows.
Now we need:
- Input validation
- Different expense categories
- API communication
- Local database storage
- Loading and error states
- Authentication
- Business rules
- Offline support
- Data synchronization
- Reporting
- Notifications
- Analytics
Suddenly, the screen that originally handled a few things is now responsible for many completely different concerns.
The UI knows about the API.
The API logic knows about the UI.
Business rules are mixed with button-click logic.
Database code appears inside presentation code.
Changing one thing starts affecting several unrelated parts of the application.
This is where architecture becomes important.
Architecture Is About Responsibility
One of the biggest things I learned is that architecture is not primarily about creating folders.
You can create folders called:
components
services
models
repositories
utils
screens
and still have a badly structured application.
Architecture is really about responsibilities and boundaries.
Every part of the application should have a clear answer to questions like:
- What is this part responsible for?
- What should it know about?
- What should it not know about?
- Who should it communicate with?
- What happens if the API changes?
- What happens if the database changes?
- Can this business logic be tested without the UI?
Once I started looking at architecture this way, MVVM became much easier to understand.
MVVM: Separating What We See From What We Do
MVVM stands for:
Model - View - ViewModel
The basic idea is simple.
Instead of putting everything inside the UI, we separate the presentation responsibilities.
Think about a screen that displays a list of expenses.
The screen needs to:
- Display the expenses
- Show loading information
- Display errors
- React to user actions
But does the screen itself need to know how the data is fetched?
Not necessarily.
That is where the ViewModel becomes useful.
View
The View is what the user interacts with.
Its responsibility is mainly presentation.
For example:
- Screens
- UI components
- Buttons
- Forms
- Lists
- Loading indicators
- Error messages
The View should focus on:
What should the user see?
It should not become the place where every application decision is made.
ViewModel
The ViewModel sits between the View and the rest of the application.
It manages things such as:
- UI state
- User actions
- Presentation logic
- Loading state
- Error state
- Preparing data for the View
For example, when a user taps Save Expense, the View does not need to understand everything involved in saving that expense.
The View can simply communicate the action.
The ViewModel can then coordinate what needs to happen.
This gives us a useful separation:
View = What the user sees
ViewModel = What the UI needs to know and what should happen from a UI action
Model
The Model represents the data and concepts used by the application.
Depending on how the application is designed, this can include things such as:
- Data objects
- Entities
- Data structures
- Related data concepts
The exact meaning of "Model" can vary between different implementations of MVVM.
That is important because MVVM itself does not define every detail of the entire application's architecture.
And this leads to an important point.
MVVM Is Not the Entire Architecture
MVVM is mainly a presentation pattern.
It helps us organize how the UI communicates with presentation logic.
But what happens after the ViewModel needs to perform an actual business operation?
For example:
"Create this expense."
Should the ViewModel directly call the database?
Should it directly call an API?
Should it contain all the business rules?
As applications become larger, putting everything inside the ViewModel can simply create another problem:
A giant ViewModel.
This is where a broader architectural approach becomes useful.
That is where Clean Architecture comes in.
Clean Architecture: Separating the Core From External Details
Clean Architecture is broader than MVVM.
The main idea is to keep the important business logic of an application independent from external technologies and implementation details.
External details can include things like:
- UI frameworks
- APIs
- Databases
- Network libraries
- Storage systems
- Third-party services
The business logic should not become tightly coupled to these things.
A common way to understand Clean Architecture is through three major areas:
- Presentation
- Domain
- Data
These are not simply folders.
They represent different responsibilities and boundaries.
Presentation Layer
The Presentation layer is responsible for interacting with the user.
This is where things such as:
- Views
- ViewModels
- UI state
- User interactions
usually live.
This is also where MVVM can fit naturally.
So instead of thinking:
MVVM vs Clean Architecture
it is more useful to think:
MVVM can organize the Presentation layer inside a Clean Architecture application.
Domain Layer
The Domain layer is the heart of the application.
This is where we keep the important business concepts and rules.
The Domain layer should not need to know whether the application is using:
- REST API
- GraphQL
- PostgreSQL
- MongoDB
- SQLite
- A particular UI framework
- A particular network library
The business rules should remain independent.
Entities
Entities represent important concepts in the application's business domain.
For an expense application, an entity might represent an:
Expense
For a shopping application:
Order
For a banking application:
Account
These concepts exist regardless of which UI framework or database the application uses.
Use Cases
A Use Case represents something the application does.
For example:
- Add Expense
- Delete Expense
- Create Order
- Cancel Order
- Generate Report
- Update Profile
Instead of thinking about Use Cases as another complicated architectural term, I find it easier to think:
A Use Case represents an application action or business operation.
This gives the application a clear place for business logic.
Repository Interfaces
The Domain layer may need data, but it should not need to know exactly where that data comes from.
For example, an Add Expense use case may need to save an expense.
The Domain layer can depend on an abstraction such as a repository interface.
It does not need to know whether the repository eventually saves the data to:
- A remote API
- A local database
- Local storage
- A cache
- Some other data source
That implementation detail belongs outside the Domain layer.
Data Layer
The Data layer deals with external data sources.
This can include:
- APIs
- Databases
- Local storage
- Files
- Caches
- Repository implementations
- Data source implementations
For example, the Domain layer might say:
"I need to save an expense."
The Data layer handles how that actually happens.
This separation becomes powerful when external technologies change.
Suppose an application initially uses one database and later moves to another.
If the business logic is tightly coupled to the original database, the change can become painful.
But if the business logic communicates through abstractions, the implementation can change without forcing the business rules to understand the new technology.
The Most Important Idea: Dependency Direction
This is one of the most important ideas behind Clean Architecture.
It is not enough to separate the application into Presentation, Domain, and Data.
We also need to think about which layer depends on which.
The important principle is:
The core business logic should not depend directly on external implementation details.
Think about a restaurant.
The customer should not need to know:
- Which supplier delivered the vegetables
- Which brand of cooking oil was used
- Which kitchen equipment was used
- Where the restaurant purchased its ingredients
The customer cares about the result.
The restaurant's internal processes can change without changing what the customer expects.
In a similar way, our business logic should not become tightly connected to external details.
The database can change.
The API can change.
The UI technology can change.
The core business rules should remain relatively stable.
MVVM and Clean Architecture Together
This is where the two concepts finally connect.
They are not competing architectures.
They solve problems at different levels.
MVVM helps organize the presentation side.
Clean Architecture helps structure the broader application and control dependencies between different parts.
A simplified structure can look like this:
Presentation
│
├── View
│
└── ViewModel
│
▼
Domain
│
├── Entities
├── Use Cases
└── Repository Interfaces
│
▼
Data
│
├── Repository Implementations
└── Data Sources
│
├── API
├── Database
└── Local Storage

The important thing is not memorizing this diagram.
The important thing is understanding why the separation exists.
Following One Action Through the Application
Let's follow a simple example.
A user wants to add an expense.
1. User interacts with the View
The user enters an amount and taps Save.
The View captures the interaction.
2. View communicates with the ViewModel
The ViewModel receives the action.
It can update UI state, handle presentation concerns, and coordinate the next step.
3. ViewModel calls a Use Case
Instead of putting the actual business operation inside the ViewModel, it delegates the operation to the appropriate Use Case.
For example:
Add Expense Use Case
4. Use Case applies business rules
The Use Case determines what needs to happen according to the application's rules.
It may validate the information or coordinate the required operation.
5. Use Case communicates through a Repository abstraction
The Use Case does not need to know whether the data comes from an API, database, or local storage.
It communicates through the repository abstraction.
6. Repository implementation handles the data
The Data layer provides the actual repository implementation.
That implementation knows how to communicate with the required data source.
7. Data Source performs the actual operation
The data may finally reach:
- An API
- A database
- Local storage
- Another external system
The result then travels back through the layers.
So conceptually:
User
↓
View
↓
ViewModel
↓
Use Case
↓
Repository Interface
↓
Repository Implementation
↓
Data Source
And the result comes back in the opposite direction toward the UI.
This gives every part of the application a clear responsibility.
Why This Separation Is Useful
The biggest benefit is not simply that the project has more folders.
The real benefit is that changes become easier to manage.
Imagine the API changes.
The View should not need to change just because the API response changed.
Imagine the database changes.
The business rules should not suddenly need to understand the new database.
Imagine the UI changes.
The core business logic should not need to change just because the design changed.
Imagine we want to test a business rule.
We should be able to test that rule without launching the entire application.
This is where good boundaries become valuable.
Testing Becomes Easier
Separation also makes testing more focused.
Instead of testing the entire application every time, different responsibilities can be tested independently.
For example:
View
Can the UI display the correct state?
ViewModel
Does the correct UI state appear after an action?
Use Case
Does the business rule behave correctly?
Repository
Does the data operation work as expected?
Data Source
Does the API or database communication work correctly?
The more independent these responsibilities are, the easier it becomes to identify where a problem actually exists.
What Happens When Technology Changes?
One of the reasons I find Clean Architecture useful is that software technology constantly changes.
Today we may use one API library.
Tomorrow we may replace it.
Today we may use one database.
Later we may migrate to another.
The UI framework may change.
A third-party library may be removed.
These changes are much easier to handle when our business logic is not directly dependent on every external technology.
The goal is not to prevent change.
The goal is to contain the impact of change.
Benefits of Combining MVVM and Clean Architecture
When used appropriately, this combination can provide several benefits.
Clear separation of responsibilities
Each part of the application has a specific job.
Better maintainability
Changes can remain localized instead of spreading throughout the application.
Better testability
Business logic can be tested independently from UI and external systems.
Reduced coupling
The core logic does not need to know the implementation details of external technologies.
Easier scaling
As an application grows, clearly defined boundaries make the codebase easier to understand and extend.
Easier replacement of technologies
APIs, databases, libraries, and other external tools can potentially be replaced with less impact on the core business logic.
But There Is a Trade-Off
Architecture is not free.
A well-structured architecture usually means:
- More files
- More abstractions
- More interfaces
- More layers
- More concepts to understand
- More initial setup
For a very small application, creating a Use Case, Repository Interface, Repository Implementation, Data Source, ViewModel, and several other abstractions for a single screen may be unnecessary.
That can become overengineering.
The goal of architecture is not to create the maximum number of layers.
The goal is to create useful boundaries for the complexity that actually exists.
A small application may need a simple structure.
A large application with complicated business rules and multiple data sources may benefit from stronger architectural boundaries.
Architecture Is Not About Following a Folder Structure
This is another lesson I find important.
Someone can create a project like this:
presentation/
domain/
data/
and still have poor architecture.
Why?
Because the folder names themselves do not create separation.
If the View directly accesses the database, the boundaries are already being broken.
If the Domain layer directly imports a specific API library, it becomes coupled to that external technology.
If all the business logic still lives inside one giant ViewModel, simply calling the project "MVVM" does not solve the problem.
Architecture is about:
Responsibilities.
Boundaries.
Dependencies.
Communication between those boundaries.
The folder structure is only one way of representing those decisions.
MVVM vs Clean Architecture
It becomes much easier to understand the difference when we look at their purpose.
| MVVM | Clean Architecture |
|---|---|
| Presentation pattern | Broader architectural approach |
| Focuses mainly on UI and presentation logic | Focuses on the structure of the whole application |
| Separates View and ViewModel responsibilities | Separates application concerns and controls dependencies |
| Helps organize presentation code | Helps protect core business logic |
| Can be used inside Clean Architecture | Can use MVVM in its Presentation layer |
So instead of asking:
Which one should I use?
A better question is:
How can they work together to solve different architectural problems?
A Simple Mental Model
When looking at a piece of code, I try to ask four simple questions.
What does the user see?
View
What does the UI need to know or respond to?
ViewModel
What does the application actually do?
Use Case / Domain
Where does the data come from?
Repository / Data
This mental model is much easier to remember than trying to memorize a long list of architectural definitions.
The Bigger Picture
When I started learning architecture, the different terms felt disconnected.
MVVM felt like one topic.
Clean Architecture felt like another.
Repository felt like another.
Use Cases felt like another.
But once I started looking at them through responsibilities and dependencies, they started fitting together.
MVVM helps answer:
How should presentation logic be organized?
Clean Architecture helps answer:
How should the application be structured so that core logic stays independent from external details?
Repository helps answer:
How can the application communicate with data without tightly coupling business logic to the data source?
Use Cases help answer:
Where should an application action or business operation live?
Together, these ideas create a much clearer mental model of where code should belong.
Final Thoughts
Good architecture is not about making software complicated.
It is about making responsibilities clear.
When an application grows, complexity is inevitable.
The goal of architecture is not to eliminate complexity completely.
The goal is to organize that complexity so that it remains understandable and changeable.
MVVM helps separate what the user sees from the logic that supports the UI.
Clean Architecture helps separate the core business logic from external implementation details.
When these ideas are used together thoughtfully, the result is not simply a project with more folders.
It is a system where:
UI has a responsibility.
Presentation logic has a responsibility.
Business logic has a responsibility.
Data access has a responsibility.
And most importantly, the boundaries between them are intentional.
That, for me, is the real purpose of software architecture:
Not just deciding where code goes, but understanding why it belongs there.





Top comments (0)