Clean Architecture in Frontend Applications. Overview

The article shares my experience of implementing Clean Architecture in frontend applications. Repository with example: https://github.com/harunou/react-tanstack-react-query-clean-architecture Introduction to Clean Architecture Clean Architecture is a "divide et impera" framework introduced by Robert C. Martin (Uncle Bob). It defines a set of principles and patterns that allow for building maintainable and scalable applications. A description can be found in Uncle Bob's article The Clean Architecture. The most confusing aspect I face when working on Clean Architecture implementation in frontend projects is the principle of building an application independent of frameworks. This goal is more idealistic than pragmatic for real-world frontend applications. Even if a frontend application is tied to a framework, Clean Architecture still provides organizational clarity, creates portable code units, and governs application flows. In addition to the benefits mentioned in Uncle Bob's article, it is worth adding: Limited context when working with a codebase. This helps to avoid keeping the whole application in mind and reduces cognitive load. This is achieved by isolating code units. Unified control and data flow throughout the application. Debugging is made easier as at every point in the application, it is clear what will be called next and where the data flows from and to. Testable code with clear boundaries for unit and integration tests, where tests are inline application specifications. Resistance to code degradation even after multiple modifications by AI Assistants. Clean Architecture Visualization The image below represents Clean Architecture implementation for a typical frontend application with a store and API integration. The diagram shows the following units: Enterprise Business Entity (EB Entity): Unit that encapsulates enterprise business rules and data. These entities represent the core business concepts and are technology-agnostic. Application Business Entity (AB Entity): Unit that encapsulates application-specific business rules and data. These represent concepts that only exist within the context of the application. Data and rules specific to how information is presented to users, including display preferences, UI behavior, and interaction patterns. Store: An aggregate unit that maintains a collection of business and/or UI entities and their states. Selector: Unit that derives values or data structures from the state without modifying it, implementing read-only queries against the state, implements application business rules. Transaction: Unit with logic that transitions a store between two valid states, ensuring business rules are maintained. Use Case: Unit that orchestrates the flow of data in the application by coordinating entities, gateways, and transactions to fulfill specific user goals, implements application business rules. Controller: Unit that handles input data from the view and converts it into use case invocations. Presenter: Unit that transforms the application state into output data suitable for the view, often using selectors. View: Unit that is responsible for displaying information to the user based on the data prepared by the Presenter and for capturing user input and transferring it to the Controller. Gateway: Unit that isolates external resources by providing interfaces for data access, mapping data from external resources into entities, and potentially caching data. External Resource: External systems or services that the application interacts with, such as APIs, databases, storages, or other applications. Definition of concepts utilized by the units: Enterprise Business Rules and Data: The most general and high-level rules and data that would exist even if the application didn't. These are enterprise-wide rules that rarely change and are independent of any specific application. Application Business Rules and Data: Rules and data specific to the application's functionality and presentation. This includes how business concepts are presented to users, interaction flows, UI state management, and application-specific behaviors. These are more likely to change compared to enterprise rules. State: The value of a store at a given point in time, typically represented as an object structure. Valid State: One of a finite number of store values that is conceptually considered valid according to business and application rules. Core and Stability Gradient The image represents a stability gradient. The most stable components, which are less likely to change, form the "core" of the application, while more volatile components reside outside. Flow of Control The flow of control follows the same principle as defined in Clean Architecture: it starts with the controller, goes through the use case, and ends with the presenter. Flow of Data The data flow is unified. Data originates from user interactions/

Mar 11, 2025 - 10:10
 0
Clean Architecture in Frontend Applications. Overview

The article shares my experience of implementing Clean Architecture in frontend applications.

Repository with example:
https://github.com/harunou/react-tanstack-react-query-clean-architecture

Introduction to Clean Architecture

Clean Architecture is a "divide et impera" framework introduced by Robert C.
Martin (Uncle Bob). It defines a set of principles and patterns that allow for
building maintainable and scalable applications. A description can be found in
Uncle Bob's article The Clean Architecture.

The most confusing aspect I face when working on Clean Architecture
implementation in frontend projects is the principle of building an application
independent of frameworks. This goal is more idealistic than pragmatic for
real-world frontend applications. Even if a frontend application is tied to a
framework, Clean Architecture still provides organizational clarity, creates
portable code units, and governs application flows.

In addition to the benefits mentioned in Uncle Bob's article, it is worth
adding:

  • Limited context when working with a codebase. This helps to avoid keeping the whole application in mind and reduces cognitive load. This is achieved by isolating code units.
  • Unified control and data flow throughout the application. Debugging is made easier as at every point in the application, it is clear what will be called next and where the data flows from and to.
  • Testable code with clear boundaries for unit and integration tests, where tests are inline application specifications.
  • Resistance to code degradation even after multiple modifications by AI Assistants.

Clean Architecture Visualization

The image below represents Clean Architecture implementation for a typical frontend application with a store and API integration.

clean architecture diagram

The diagram shows the following units:

  • Enterprise Business Entity (EB Entity): Unit that encapsulates enterprise business rules and data. These entities represent the core business concepts and are technology-agnostic.
  • Application Business Entity (AB Entity): Unit that encapsulates application-specific business rules and data. These represent concepts that only exist within the context of the application. Data and rules specific to how information is presented to users, including display preferences, UI behavior, and interaction patterns.
  • Store: An aggregate unit that maintains a collection of business and/or UI entities and their states.
  • Selector: Unit that derives values or data structures from the state without modifying it, implementing read-only queries against the state, implements application business rules.
  • Transaction: Unit with logic that transitions a store between two valid states, ensuring business rules are maintained.
  • Use Case: Unit that orchestrates the flow of data in the application by coordinating entities, gateways, and transactions to fulfill specific user goals, implements application business rules.
  • Controller: Unit that handles input data from the view and converts it into use case invocations.
  • Presenter: Unit that transforms the application state into output data suitable for the view, often using selectors.
  • View: Unit that is responsible for displaying information to the user based on the data prepared by the Presenter and for capturing user input and transferring it to the Controller.
  • Gateway: Unit that isolates external resources by providing interfaces for data access, mapping data from external resources into entities, and potentially caching data.
  • External Resource: External systems or services that the application interacts with, such as APIs, databases, storages, or other applications.

Definition of concepts utilized by the units:

  • Enterprise Business Rules and Data: The most general and high-level rules and data that would exist even if the application didn't. These are enterprise-wide rules that rarely change and are independent of any specific application.
  • Application Business Rules and Data: Rules and data specific to the application's functionality and presentation. This includes how business concepts are presented to users, interaction flows, UI state management, and application-specific behaviors. These are more likely to change compared to enterprise rules.
  • State: The value of a store at a given point in time, typically represented as an object structure.
  • Valid State: One of a finite number of store values that is conceptually considered valid according to business and application rules.

Core and Stability Gradient

The image represents a stability gradient. The most stable components, which are
less likely to change, form the "core" of the application, while more volatile
components reside outside.

core and stability gradient diagram

Flow of Control

The flow of control follows the same principle as defined in Clean Architecture: it starts with the controller, goes through the use case, and ends with the presenter.

flow of control diagram

Flow of Data

The data flow is unified. Data originates from user interactions/events captured
by the view, follows the flow of control, and returns back to the view.

Pessimistic Flow of Data

In the pessimistic flow of data, the data captured by the view is processed by
external resources before reaching the core and then returning to the view.

NOTE: Selectors can depend on gateways to obtain data fetch statuses (loading, error, success) or cached data. This is particularly applicable when the gateway implementation supports such features, for example, when using Tanstack React Query.

pessimistic flow of data diagram

Optimistic Flow of Data

In the optimistic flow of data, the data captured by the view is processed by
the core first and then by the external resources. The first time, data reaches
the view after the core has processed it. The second time (optional), data
reaches the view after the external resources have processed it.

NOTE: Selectors can depend on gateways to obtain data fetch statuses (loading, error, success) or cached data. This is particularly applicable when the gateway implementation supports such features, for example, when using Tanstack React Query.

optimistic flow of data diagram

Testing

The layered structure creates natural boundaries for different types of tests,
making them more stable. For example, tests written for units that belong to the
application core are less likely to change when the views or external resources evolve.

NOTE: Resource integration tests evaluate how the gateway integrates with the external resource

testing diagram

Drivers and Alternative Interfaces

While the primary interface is typically the view rendered in a browser, Clean
Architecture allows for multiple ways to interact with the application core
through different drivers during runtime. In fact, the view itself is a driver.
One common alternative driver I implement is a CLI.

drivers diagram

Application Scale and Clean Architecture

Clean Architecture principles are scale-agnostic and can be effectively applied
to applications of any size. Whether you're working on an enterprise-scale SPA
or a simple single-file React app, the architectural boundaries and patterns
remain valuable. To benefit, developers should have a clear understanding of how their code maps to Clean Architecture units while maintaining unified control and data flows.

scale diagram

Web Workers and Browser Storage (extra)

Web Workers and browser storage mechanisms (e.g., localStorage, etc.) are suggested to be treated as external resources and accessed through gateways. Later, they can be easily replaced with a backend service.

web workers diagram

Conclusion

While perfect framework independence may be ambitious in frontend applications, the core benefits of Clean Architecture remain achievable in practice.