What is Clean Architecture ? How to use it in a Flutter ?

Kalpesh Khandla
6 min readJul 19, 2024

--

Hello Everyone,
In today’s article we are going to learn about Clean Architecture. So first question arise in our mind is

What is Clean Architecture ?

Clean Architecture is a software design philosophy that emphasizes the separation of concerns and independence of frameworks. It was introduced by Robert C. Martin, also known as Uncle Bob. The key idea is to divide the codebase into layers, each with a specific responsibility, and arrange these layers in a way that dependencies flow inward.

Clean Architecture in Flutter

Lets dive deep into it step by step.

The number of layers used can vary slightly from one project to another, but by utilizing them, we promote the principle of ‘separation of concerns.’ If you’re a new developer and have never heard of it before, it’s simply a fancy way of saying, ‘Hey! I’m a layer, and I’m concerned about a single aspect of the system only’. If a layer is responsible for displaying the UI, it won’t handle database operations. Conversely, if a layer is responsible for data persistence, it won’t have any knowledge of UI components.

Usually, when working with this architecture, you’ll come across some additional terminology such as Entities, Interface Adapters, Use Cases, DTOs, and other terms. These terms are simply names given to components that also fulfill ‘single responsibilities’ within the project:

Entities: Represent the core business objects, often reflecting real-world entities. Examples include Character, Episode, or Location classes. These entities usually correspond to real-world concepts or objects, possessing properties specific to them and encapsulating behavior through their own methods. You’ll be reading, writting, and transforming entities throughout the layers

Interface Adapters: Also known as Adapters, they’re responsible for bridging the gap between layers of the system, facilitating the conversion and mapping of data between layers. There are various approaches available, such as specialized mapper classes or inheritance. The point is, by using these adapters, each layer can work with data in a format that suits better for its needs. As data moves between layers, it is mapped to a format that is suitable for the next layer. Thus, any future changes can be addressed by modifying these adapters to accommodate the updated format without impacting the layer’s internals

Use Cases: Also known as Interactors, they contain the core business logic and coordinate the flow of data. For example, they handle user login/logout, data saving or retrieval, and other functionalities. Use Case classes are typically imported and used by classes in the presentation (UI) layer. They also utilize a technique called ‘inversion of control’ to be independent of the data retrieval or sending mechanism, while coordinating the flow of data

Data Transfer Objects (DTOs): Are objects used for transferring data between different layers of the system. They serve as simple containers that carry data without any behavior or business logic.

Known limitations

  • The initial setup involves dealing with some boilerplate code
  • There is a risk of over-engineering the solution.

Known benefits

  • A/B testing can be easily applied
  • Feature toggles can be effortlessly implemented
  • All layers can be independently unit tested
  • The unidirectional data flow facilitates code comprehension
  • UI becomes an implementation detail — In fact, we could even reuse the Domain and Data layers to create things like CLIs.

In this case, we’re only using three layers: Presentation, Domain and Data.

The presentation layer (UI)

This is the layer where the Flutter framework resides. Here, you’ll find classes that are part of the framework, such as Widgets, BuildContexts, and libraries that consume the framework, including state management libraries.

Typically, the classes in this layer are responsible for:

  • Managing the application’s state.
  • Handling UI aspects of an app, such as managing page navigation, displaying data, implementing internationalization, and ensuring proper UI updates.

The domain layer

This layer represents the core domain of the problem we are addressing, encompassing the business rules. Hence, it should be an independent Dart module without dependencies on external layers. It includes:

  • Plain entity classes (like Character entity)
  • Use-case classes that encapsulate the specific business logic for a given use case (like GetAllCharacters, SignInUser, and others…)
  • Abstractions for data access, normally repository or services interfaces

A use-case has no knowledge of the data source, whether it comes from a memory cache, local storage, or the internet. All these implementation details have been abstracted out through the use of Repository Interfaces. From the use-case’s perspective, all that matters is that it receives the required data.

The data layer

This layer serves as a boundary between our application and the external world. Its primary responsibility is to load data from external sources, such as the internet or databases, and convert it to a format that aligns with our Domain expectations. It plays a vital role in supplying data to the use cases and performs the following tasks:

  • Data retrieval: It makes network and/or database calls, retrieving data from the appropriate data sources.
  • Repository implementations: It includes the implementations of the repositories defined in the domain layer, providing concrete functionality for accessing and manipulating data.
  • Data coordination: It coordinates the flow of data between multiple sources. For example, it can fetch data from the network, store it locally, and then return it to the use case.
  • Data (de)serialization: It handles the conversion of data to and from JSON format, transforming it into Data Transfer Objects (DTOs) for standardized representation.
  • Caching management: It can incorporate caching mechanisms, optimizing performance by storing frequently accessed data for quicker retrieval.

The DTOs, Entities and States

As mentioned previously, this architecture emphasizes two fundamental principles: ‘Separation of Concerns’ and ‘Single Responsibility.’ And to uphold these principles, it is crucial to allow each layer to effectively handle data according to its specific needs. This can be achieved by utilizing classes with specialized characteristics that empower their usage within each layer.

In this project, the Data layer employs Data Transfer Objects (DTOs), the Domain layer utilizes Entities, and the Presentation layer the States classes.

DTOs are specifically designed for deserializing and serializing data when communicating with the network. Hence, it is logical for them to possess the necessary knowledge of JSON serialization. Entities, on the other hand, represent the core concepts of our domain and contain ‘plain’ data or methods relevant to their purpose. Lastly, in the Presentation layer, States are used to represent the way we display and interact with the data in the user interface.

The specific usage of these classes may vary from project to project. The names assigned to them can differ, and there can even be additional types of classes, such as those specifically designed for database mapping. However, the underlying principle remains consistent: By utilizing these classes alongside mappers, we can provide each layer with a suitable data format and the flexibility to adapt to future changes.

Conclusion

Clean Architecture offers a clear and structured approach to building Flutter applications, promoting separation of concerns and modularity. By adhering to the principles of Clean Architecture, developers can create scalable, testable, and maintainable applications that are resilient to changes and easy to extend.

In this guide, we’ve covered the fundamental concepts of Clean Architecture and provided practical examples of its implementation in Flutter. By applying these principles in your Flutter projects, you can build robust and maintainable applications that stand the test of time.

You can a find link to GitHub Repo from https://github.com/Kalpesh209/flutter_clean_architecture_example

I am Kalpesh Khandla, a Creative Flutter Developer, and a Technology lover. You can find me on LinkedIn or maybe follow me on Twitter or just walk over my portfolio for more details. And of course, you can follow me on GitHub as well.

Have a nice day !!!
Keep Learning.

--

--

No responses yet