Clean code architechture

Clean architecture flutter

Clean Architecture is a software design approach that aims to separate concerns and dependencies within a system, making the codebase more modular, maintainable, and testable. When implementing Clean Architecture in Flutter, you can structure your project by organizing it into layers with clear boundaries and responsibilities.

Here’s a basic outline of how you can structure your Flutter project using Clean Architecture:

Domain Layer:

  • Entities: Represent the core business logic and data structures of your application.
  • Use Cases (Interactors): Contain application-specific business rules and logic.
  • Repositories Interfaces: Define interfaces for data access methods that will be implemented by external frameworks or data sources.

Data Layer:

  • Repositories Implementations: Implement the repository interfaces defined in the domain layer. This layer interacts with external data sources, such as databases, APIs, or local storage.
  • Data Sources: Implement the actual data retrieval and storage mechanisms (e.g., API clients, database access).

Presentation Layer:

  • UI Components: Widgets and UI-related code reside here.
  • Presenters/BLoCs (Business Logic Components): Contain the presentation logic that mediates between the UI and the use cases in the domain layer.
  • Models: Convert entities from the domain layer into viewable models.

Dependency Injection (DI):

  • Use a DI framework, like get_it or dinject, to manage dependencies and inject them into the classes that need them.
  • Wire up dependencies at the app’s entry point.

External Libraries and Frameworks:

  • Keep external dependencies and framework-specific code (like Flutter-specific code) at the outermost layer.

Here’s a sample directory structure:

lib/
|-- core/
|   |-- domain/
|   |   |-- entities/
|   |   |-- use_cases/
|   |   |-- repositories/
|   |
|   |-- data/
|       |-- repositories/
|       |-- data_sources/
|
|-- presentation/
|   |-- pages/
|   |-- widgets/
|   |-- presenters/
|   |-- models/
|
|-- di/
|
|-- main.dart
  • core: Contains the domain layer.
  • data: Contains the data layer.
  • presentation: Contains the presentation layer.
  • di: Contains dependency injection code.

MVC (Model View Controller)

MVC) — iOS Apps default architecture is MVC. Every screen is split into three components:

  • Model — business entities and application models
  • View — show formatted data to the user
  • Controller — to transform data and handle user interactions

Model-View-Controller (MVC) is a design pattern that separates an application into three interconnected components: Model, View, and Controller. While Flutter doesn’t strictly follow the traditional MVC pattern, you can implement a similar separation of concerns in Flutter applications. Here’s how you can loosely map the MVC pattern in Flutter:

Model:

The model represents the data and business logic of the application.

// Example model in Flutter

class UserModel {
  String id;
  String name;

  UserModel({required this.id, required this.name});
}

View:

The view represents the user interface of the application. In Flutter, this corresponds to your widgets.

// Example view (widget) in Flutter

import 'package:flutter/material.dart';

class UserView extends StatelessWidget {
  final UserModel user;

  UserView({required this.user});

  @override
  Widget build(BuildContext context) {
    return Card(
      child: ListTile(
        title: Text(user.name),
        subtitle: Text(user.id),
      ),
    );
  }
}

Controller:

The controller manages the flow of data between the model and the view. In Flutter, this can be implemented using a Stateful widget or a separate class to handle the business logic.

// Example controller in Flutter

import 'package:flutter/material.dart';

class UserController extends StatefulWidget {
  @override
  _UserControllerState createState() => _UserControllerState();
}

class _UserControllerState extends State<UserController> {
  late UserModel _user;

  @override
  void initState() {
    super.initState();
    // Initialize or fetch the user data
    _user = UserModel(id: '1', name: 'John Doe');
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('User Details')),
      body: UserView(user: _user),
    );
  }
}

MVP (Model View Presenter)

This design closely resembles MVC, with the distinction that the presenter houses all UI business logic. To illustrate, when a button is pressed, we can instruct the presenter to display the subsequent view. Additionally, the presenter engages with a model to retrieve and process business entities. Essentially, the presenter encapsulates a method invoked by the view, carrying out actions on the view, and maintains a reference to the view in this scenario.

MVVM (Model View ViewModel)

In a similar architectural approach, the viewmodel can be perceived as an additional facet of a view abstraction. The viewmodel serves as a wrapper for model data that can be connected to the view, encompassing commands (methods) to facilitate communication with both the model and the view.

For instance, when a button is tapped, the view might request service data. The viewmodel, in turn, is tasked with retrieving the data from the service, parsing and processing it, and delivering the results to the view in an appropriate format.

A notable distinction between the ViewModel and the presenter lies in the fact that the viewmodel remains unaware of the view. Moreover, another contrast is that the viewmodel can be shared among multiple views, whereas presenters cannot. Presenters are specifically tied to a particular concrete view.

Conclusion:

In conclusion, Clean Architecture in Flutter provides a robust and scalable approach to building mobile applications. By emphasizing separation of concerns and maintaining a clear distinction between layers, Clean Architecture promotes modularity, testability, and flexibility in Flutter projects.

The core principles of Clean Architecture, such as the Dependency Rule, guide developers in organizing their codebase. The use of entities, use cases, and interfaces ensures that business logic remains independent of external frameworks and libraries, facilitating easier testing and adaptability.

Flutter’s widget-based UI framework is well-suited for integration with Clean Architecture. The presentation layer can be effectively implemented using Flutter widgets, while the business logic resides in the domain and data layers. This separation allows for the easy swapping of UI frameworks or transitioning to web applications without significant changes to the core logic.

Moreover, the introduction of packages like Provider or Riverpod complements Clean Architecture in managing dependencies and simplifying state management. These tools align with the principles of Clean Architecture, enabling developers to focus on the application’s functionality without being tightly coupled to specific implementation details.