Flutter Clean Architecture Combination Pattern Style YoClean

September 28, 2025 (1d ago)

Refactor β˜•

this concept is Combination pattern style between KauΓͺ and Arktekko thats i applied on open source project by mani53-dev. For a detailed explanation, check out the Medium article: Implementing Clean Architecture with GetX and MVVM in Flutter. write by the owner of code starterpack thats i modified.

Purpose & Why β˜•

The goals make the project code is testability, more clean, and readable easy scaleable and maintained.

πŸ•΅πŸΌβ€β™‚οΈ Before After πŸ’‘

BEFORE

Clean Architecture using GetX and MVVM, adhering to SOLID principles. project follows a structured approach to building scalable Flutter applications with GetX for state management and dependency injection. It implements Clean Architecture to separate concerns and improve maintainability.

  • GetX for State Management
  • MVVM Architecture
  • Dio for API Calls
  • Interceptor for API Authorization
  • Caching with DioCacheInterceptor
  • Shared Preferences for Local Storage
  • SOLID Principles Implementation

πŸ“‚ Project Structure (BEFORE Modified)

lib/
β”‚
β”œβ”€β”€ common/                # Shared utilities, themes, constants
β”‚
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ exceptions/        # Custom exception handling
β”‚   β”œβ”€β”€ global_widgets/    # Reusable UI components
β”‚   β”œβ”€β”€ middlewares/       # Route guards and middlewares
β”‚   β”œβ”€β”€ models/            # Entity definitions (business models)
β”‚   β”œβ”€β”€ modules/           # Feature-based segregation
β”‚   β”‚   β”œβ”€β”€ auth/
β”‚   β”‚   β”‚   β”œβ”€β”€ bindings/      # Dependency bindings
β”‚   β”‚   β”‚   β”œβ”€β”€ controllers/   # State management using GetX
β”‚   β”‚   β”‚   β”œβ”€β”€ services/      # Business logic and use cases
β”‚   β”‚   β”‚   β”œβ”€β”€ views/         # UI components
β”‚   β”‚   β”‚   β”œβ”€β”€ widgets/       # Reusable widgets on module level
β”‚   β”‚   β”œβ”€β”€ dashboard/
β”‚   β”‚   β”œβ”€β”€ root/          # Root navigation & app entry point
β”‚   β”œβ”€β”€ providers/         # API services and data sources
β”‚   β”œβ”€β”€ routes/            # Navigation and route management
β”‚   β”œβ”€β”€ services/          # Global services (e.g., Auth, Storage)
β”‚
β”œβ”€β”€ main.dart              # Application entry point

AFTER

Clean Architecture with GetX (DDD-style), adhering strictly to SOLID principles and testability. A Flutter project implementing Clean Architecture with GetX, following SOLID and Onion principles (Domain-Driven), with clear separation of Data, Domain, and Presentation layers.

πŸ“‚ Project Structure (AFTER Modified)

lib/
β”‚
β”œβ”€β”€ common/                   # Shared utilities, themes, constants (colors, styles, helpers)
β”‚
β”œβ”€β”€ app/
β”‚   β”œβ”€β”€ exceptions/            # Custom exception classes (e.g., AuthException, NetworkException)
β”‚   β”œβ”€β”€ global_widgets/        # Reusable UI widgets used across modules (e.g., Button, TextField)
β”‚   β”œβ”€β”€ middlewares/           # GetX middlewares (auth guard, onboarding guard, etc.)
β”‚   β”œβ”€β”€ models/                # Pure business models/entities (domain-level extends, yes/no JSON here depends on requirement, mapping)
β”‚   β”œβ”€β”€ modules/               # Feature-based separation (DDD style)
β”‚   β”‚   β”œβ”€β”€ auth/              # Authentication module
β”‚   β”‚   β”‚   β”œβ”€β”€ bindings/          # Dependency Injection for controllers & usecases
β”‚   β”‚   β”‚   β”œβ”€β”€ data/              # Data layer (API, DB, RepositoryImpl, DTOs)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ datasources/       # Remote/local sources (e.g., AuthRemoteDataSource)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ dto/               # Data Transfer Objects (login_result_dto.dart)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ payload/           # Request payloads (login_payload.dart)
β”‚   β”‚   β”‚   β”‚   └── repositories/      # Repository implementations
β”‚   β”‚   β”‚   β”œβ”€β”€ domain/            # Domain layer (rules, contracts)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ entities/          # Business entities (User, no JSON here)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ repositories/      # Repository interfaces (AuthRepository)
β”‚   β”‚   β”‚   β”‚   └── usecase/           # Use cases (LoginUseCase, RegisterUseCase)
β”‚   β”‚   β”‚   β”œβ”€β”€ presentation/     # Presentation layer
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ controllers/  # GetX Controllers (LoginController, RegisterController)
β”‚   β”‚   β”‚   β”‚   β”œβ”€β”€ views/        # UI screens (LoginView, RegisterView)
β”‚   β”‚   β”‚   β”‚   └── widgets/      # Module-specific reusable widgets (LoginForm, RegisterForm)
β”‚   β”‚   β”‚   β”œβ”€β”€ services/          # Local business services (optional helpers, e.g., AggregateService)
β”‚   β”‚   β”‚   β”œβ”€β”€ controllers/       # GetX Controllers (LoginController, RegisterController)
β”‚   β”‚   β”‚   β”œβ”€β”€ views/             # UI screens (LoginView, RegisterView)
β”‚   β”‚   β”œβ”€β”€ dashboard/         # Example: Dashboard module with same structure
β”‚   β”‚   └── root/              # Root module (main navigation, splash, app entry)
β”‚   β”‚
β”‚   β”œβ”€β”€ providers/             # Global API clients, interceptors, and HTTP providers
β”‚   β”œβ”€β”€ routes/                # App routes & navigation configuration
β”‚   β”œβ”€β”€ services/              # App-wide services (LocalStorageService, UserService, NotificationService, CrashReportingService)
β”‚
β”œβ”€β”€ main.dart                  # Application entry point (init DI, runApp, setup services)
β”‚
integration_test/          # Full app flows (needs device/emulator)
β”‚   └── login_flow_test.dart   # E2E test for login journey
test/                      # Unit & widget tests (run in memory, fast)
β”‚
β”œβ”€β”€ unit/                  # Business logic only (no UI, no Flutter engine)
β”‚   └── login_usecase_test.dart   # Tests domain logic of login usecase
β”‚
└── widget/                # UI components in isolation (with fake dependencies)
    └── login_view_test.dart     # Tests rendering & interactions of login view

🚦 Comparison Overview (Testability)

Folder Runs On Scope Speed Example
integration_test/ Emulator/Device Full app flows Slow Login end-to-end
test/unit/ Dart VM Single class/function Fast UseCase logic
test/widget/ Dart VM Widget in isolation Medium LoginView UI rendering

πŸ”„ Alur Data (contoh login flow)

[ UI Layer ]               [ Domain Layer ]                [ Data Layer ]              [ External ]
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ LoginView     β”‚        β”‚ LoginUseCase     β”‚           β”‚ AuthRepository  β”‚        β”‚ API / Storage β”‚
β”‚ (presentation)│◀──────▢│ (business logic) │◀────────▢│ Impl            │◀──────▢│ (Dio / DB)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β–²                          β–²                           β–²
        β”‚                          β”‚                           β”‚
        β”‚                          β”‚                           β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ LoginControllerβ”‚        β”‚ AuthRepository   β”‚           β”‚ DataSources     β”‚
β”‚ (GetX State)   │◀──────▢│ (interface)      │◀────────▢│ Remote/Local    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“Œ Penjelasan Flow

  1. User input di UI

    • User isi email & password di LoginView.
    • LoginController (state management) handle event tombol login.
  2. Controller memanggil UseCase

    • controller.login() β†’ panggil LoginUseCase.execute(LoginPayload).
  3. UseCase panggil Repository Interface

    • LoginUseCase butuh kontrak dari AuthRepository.
    • Interface ini ada di domain/repositories/.
  4. Repository Impl (Data Layer)

    • AuthRepositoryImpl (di data/repositories/) implement interface tadi.
    • Dia yang menentukan data diambil dari RemoteDataSource (API) atau LocalDataSource (cache).
  5. Datasource

    • AuthRemoteDataSource β†’ call API pakai DioProvider.
    • AuthLocalDataSource β†’ simpan ambil token di SharedPreferences/Hive.
  6. Balik ke atas

    • Response API β†’ diubah ke DTO β†’ di-mapping ke Entity.
    • Entity dikirim ke UseCase β†’ Controller β†’ update Rx<User> β†’ UI otomatis refresh (Obx).

🧩 Layer Responsibility

  • UI (Presentation) = Tampilan & interaksi user.
  • Controller (GetX) = State & event handler.
  • Domain (Entities & UseCase) = Business logic murni.
  • Repository Interface = Kontrak data.
  • Repository Impl = Bridge antara Domain ↔ Data.
  • DataSource = Tempat asli ambil data (API, DB, cache).

flowchart TD
    A[LoginView<br>(UI Layer)] --> B[LoginController<br>(GetX State)]
    B --> C[LoginUseCase<br>(Domain)]
    C --> D[AuthRepository<br>(Interface)]
    D --> E[AuthRepositoryImpl<br>(Data Layer)]
    E --> F1[AuthRemoteDataSource<br>(API)]
    E --> F2[AuthLocalDataSource<br>(Storage)]
    F1 --> G[External API<br>(Dio/HTTP)]
    F2 --> H[Local Storage<br>(SharedPref/Hive)]
 
    %% Return flow
    G --> F1
    H --> F2
    F1 --> E
    F2 --> E
    E --> D
    D --> C
    C --> B
    B --> A

ko-fi

Thanks for being here πŸ™Œ Stay sharp, ship clean code, and don’t forget to take a break.

– just for eat developer 🍽️ πŸ‘¨β€πŸ³ πŸ•


I’ll be publishing an open-source project soon! I’ll also clean up the old code and put it in the navigation menu under Open Source Projects. Stay tune https://github.com/yogithesymbian

Source Also From

πŸ“– Referensi

  • Uncle Bob-Clean Architecture (2012) β†’ Entities ada di paling dalam, paling stabil, bebas framework.
  • ResoCoder-Flutter TDD Clean Architecture Course β†’ implementasi di Flutter yang populer.
  • Very Good Ventures (VGV)-Flutter Best Practices β†’ banyak dipakai buat production apps.
  • Stacked architecture (FilledStacks) β†’ agak mirip tapi lebih pragmatis.