guilherme-v / flutter-clean-architecture-example

A flutter's implementation of a "clean architecture" comparing BLoC, Cubit, GetIt, MobX, Provider, and Riverpod. It includes tests to all libraries and additional features like Material 3 theming, Widget and Unit Tests, Infinite scrolling, Remote API calls, Caching and etc..
587 stars 133 forks source link
architecture bloc bloc-architecture clean-architecture cubit flutter flutter-architecture getit material-3 material-3-design mobx provider provider-flutter riverpod riverpod-examples

Flutter - Clean Architecture with State Management comparison

Build Status

app

πŸ‘€ Seeking New Opportunities - Open to Work πŸ‘‹

I am currently seeking new career opportunities as a mobile developer. If you know of any roles that align with my skills and experience, I would love to hear from you!

About Me

Contact Information

Resume

Feel free to check out my resume/CV for more details about my professional background and qualifications.

Thank you for considering me for any suitable positions!


Goals

Additional features

Exploration Summary

An overview of the current state management libraries explored is presented below:

State Manager Applied Unit tests Widget tests
Provider Yes Yes Yes
Riverpod Yes Yes In Progress
Bloc Yes Yes Yes
Cubit Yes Yes Yes
GetIt Yes Yes Yes
MobX Yes Yes In Progress

Tip

Don't just apply the architecture blindly. Work wisely by using the appropriate levels of abstraction for each project. In the end, this architecture is just a collection of good ideas based on well-founded principles (like Separation of concerns). Seek to understand the problem that each architectural decision aims to solve, so you can determine when and how to apply it.

THINK first, then ACT.

A short description about "Clean Architecture"

architecture

There are two main points to understand about the architecture: it splits the project into different layers and conforms to the Dependency rule.

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

And what about the Dependency rule? Let's put it in simple terms. First, you need to understand that the layers discussed above are not stacked on top of each other; instead, they resemble the layers of an 'onion.' There is a central layer surrounded by outer layers. The Dependency rule states that classes within a layer can only access classes from their own layer or the outer layers, but never from the inner layers

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:

I recommend checking out this link, provided by Robert C. Martin ('Uncle Bob'), which offers what today may be considered the 'official' explanation

Known limitations

Known benefits

Clean Architecture and how it's applied in this project

The figure bellow represents the variation applied in this project:

architecture

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:

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:

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:

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.

References