Skip to content

willcav/flutter_best_practices

Repository files navigation

✍️ Flutter Best Practices

This project aims to demonstrate best practices and architectural patterns for developing Flutter applications.

This project covers:

  • A way to Handle Failures in your Flutter Projects.
  • A few good practices like abstractions of third party libraries and dependency injection.

Table of Contents

  1. Features
  2. Usage
  3. Core Concepts
    1. Error Handling
    2. Clean Architecture
    3. Network Abstraction
    4. Service Locator Abstraction
  4. Contributing

Features

  • User Feature: Demonstrates the implementation of clean architecture principles (domain, data, presentation) for managing user-related functionality.
  • Network Package: Provides a comprehensive network layer abstraction with domain-driven design. It separates concerns into domain, data, and infrastructure layers, offering flexibility and ease of testing.
  • Core: Includes essential definitions and abstractions, such as Failure and Either classes for handling errors and ServiceLocator working as an abstraction of GetIt.

Usage

  1. Clone the repository:
git clone https://github.com/willcav/flutter_best_practices.git
  1. Navigate to the project directory:
cd flutter_best_practices
  1. Install dependencies
flutter pub get
  1. Explore the project structure and adapt it to your application`s needs.

Core Concepts

Error Handling

Error handling is a crucial aspect of any application, and this project employs the Either class to manage error situations effectively.

The Either class is an abstraction that represents a value of one of two possible types: L for Left, typically representing an error or failure, and R for Right, representing a successful result. This approach allows us to handle errors explicitly in our code without relying extensively on try-catch blocks.

Example usage:

// Example of a function that returns an asynchronous result
Future<Either<Failure, DogEntity>> getDog() async {
  try {
    final dog = await _repository.fetchDog();
    return Right(user); // Success
  } catch (e) {
    return Left(Failure("Failed to fetch dog")); // Failure
  }
}

// Using the result of the [getDog] function
getDog().then((result) {
  result.fold(
    (failure) {
      // Handle the error
      print("Error: ${failure.message}");
    },
    (dog) {
      // Use the dog data
      print("Dog data fetched successfully: $dog");
    },
  );
});

This approach enables us to manage error situations explicitly in our code, improving readability and reducing the likelihood of errors being overlooked or mishandled.


Clean Architecture

The project follows clean architecture principles to separate concerns and maintain a clear separation of layers: domain, data, and presentation.


Network Abstraction

The Network package provides a robust network layer abstraction, facilitating HTTP requests with flexibility and testability. It utilizes domain-driven design and inversion of control principles for effective dependency management.

The current network implementation utilizes Dio, however, it can be effortlessly replaced with another library without requiring modifications to the app, as the structure adheres to the defined interfaces.

This architecture allows for seamless integration with different HTTP client implementations while maintaining consistency and flexibility in your application's network layer. The defined interfaces facilitate dependency injection and decoupling, making it easy to adapt to changes in requirements or technology stacks without disrupting the overall architecture.

Network Schematics

network structure


network overview


network call flow


Service Locator Abstraction/Wrapper

Abstractions serve as a high-level representation of the functionality provided by third-party libraries.

By leveraging abstractions and wrappers, we can achieve greater maintainability in our codebases. When the need arises to switch to a different service locator library or upgrade to a newer version, the changes can be confined to the implementation of the abstraction or wrapper.

In this project, the GetIt dependency is encapsulated within the GetItDriver implementation, adhering to the interface we've defined.


Contributing

I welcome contributions to enhance and expand this repository! Here are some ways you can contribute:

  • Implement additional features or architectural patterns.
  • Improve documentation and code quality.
  • Address existing issues or propose new ideas.

About

This project aims to demonstrate best practices and architectural patterns for developing Flutter applications.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages