GithubHelp home page GithubHelp logo

guilherme-v / flutter-clean-architecture-example Goto Github PK

View Code? Open in Web Editor NEW
488.0 13.0 109.0 6.49 MB

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..

Kotlin 0.07% Ruby 0.74% Swift 0.36% Objective-C 0.02% Dart 90.17% HTML 0.97% CMake 4.76% C++ 2.54% C 0.36%
architecture flutter bloc cubit getit mobx provider-flutter riverpod-examples flutter-architecture bloc-architecture

flutter-clean-architecture-example's Introduction

Flutter - Clean Architecture with State Management comparison

Build Status

app

Goals

  • Keep code clean
  • Keep code testable
  • Keep code base easily extensible and adaptable
  • Ensure State Management Transparency: Design the codebase to treat the chosen state management solution as an implementation detail, enabling seamless exploration and later replacement with minimal project impact.

Additional features

  • Material 3 theming support (Dark and Light)
  • Widget and Unit Tests (good when comparing different state management libraries)
  • Infinite scrolling
  • Remote API call and Caching
  • Small set of customized static analysis and lint rules

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:

  • 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

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

  • 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

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:

  • 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.

References

flutter-clean-architecture-example's People

Contributors

guilherme-v avatar poka-it avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flutter-clean-architecture-example's Issues

Should the get_it example use watch_it?

The author of get_it has overhauled the get_it_mixin package with watch_it.

Hi my friends,

I recently published my new package watch_it https://github.com/escamoteur/watch_it, an overhauled version of the get_it_mixin but with a more intuitive and streamlined API. Porting an existing project using get_it_mixin is really easy and quick.

Should the get_it example be updated to use watch_it?

using API specifications (url , ...) in data layer violates Dependency Rule?!

Hi.
Thanks for your work I learned a lot from that.
I wonder if we use this 3 layer architecture (Domain-Data-Presentation) as you did, using details from external data sources (such as API Urls, DB table names, DB syntax and etc.) in data layer, doesn't violates Clean Architecture Dependency rule? from Uncle Bob's manifest the last layer contains DB and if we consider that as raw DB and bring DBManager(ORM,...) to inner layer(adapters),It should know about outer details. Should we use Dependency Inversion again?
In your code, API's Url is hard coded in api.dart in data layer and if we consider API as an outer circle component,I think It violates Dependency Rule.
If you want to add DB as a source to this project, How you do that?
Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.