Modern Clean Architecture SwiftUI

repository·master·Indexed 26 days ago

https://github.com/sergdort/moderncleanarchitectureswiftui

A reference implementation of Modern Clean Architecture for iOS, demonstrating Domain-Driven Design (DDD) and modularization using Tuist and SwiftUI. The project features a layered architecture consisting of Domain, Features, Application, Platform, and Core layers, and implements navigation using the Coordinator pattern.

Tokens
706
Snippets
2
Records
3
Agent score
38%

What's inside moderncleanarchitectureswiftui

  1. Understand the Layered Architecture responsibilities

    master

    The project follows a layered architecture inspired by Domain-Driven Design (DDD) and Clean Architecture. The layers are structured as follows:

    • Domain: Encapsulates core business logic, rules, entities, value objects, and aggregates. It contains UseCase definitions and implementations. It is isolated from UI and infrastructure.
    • Features: Implements UI business requirements and individual screens. It coordinates Domain UseCases. Features can use different UI patterns (e.g., MVVM or TCA) without affecting other layers. Feature modules depend only on the Domain layer and the UI.
    • Application: Responsible for creating the main user interface, managing navigation, and instantiating concrete UseCase implementations. It uses the @Dependency library to inject dependencies into the Features layer.
    • Platform: Provides concrete implementations by utilizing the Core layer and Domain business rules. It acts as a "plugin architecture" where implementations (like MoviesAPI or MoviesDB) can be swapped (e.g., changing a database or API provider) without affecting business rules.
    • Core: Provides foundational infrastructure such as HTTP libraries, SwiftData extensions, Apollo extensions, and FileCache.
  2. Implement navigation using the Coordinator pattern

    master

    Navigation is abstracted using the Coordinator pattern, which functions as a specialized implementation of the Delegate pattern. From the perspective of a ViewModel or Reducer, navigation is treated as a side effect delegated to a coordinator object. This allows the Features layer to remain decoupled from the specific navigation implementation.

    Example of a MoviesCoordinator protocol and its usage in a MoviesViewModel:

    @MainActor
    public protocol MoviesCoordinator {
        func showDetail(for movie: Movie)
        func showDetail(for person: Person)
        func showAddMovieToCustomList(for movie: Movie)
    }
    
    public final class MoviesViewModel {
        @ObservationIgnored
        private let coordinator: MoviesCoordinator
        
        func didSelect(movie: Movie) {
            coordinator.showDetail(for: movie)
        }
    }