Section 16/171 menit

15. Real Use Cases

15. Real Use Cases

Use Case 1: Fintech App dengan 30 Module dan Team 20 Developer

Sebuah fintech app dengan arsitektur modular ketat: Core (4 module), Shared (5 module), Feature (20 module), App (1 module). Sebelum Tuist, clean build CI butuh 28 menit.

Struktur workspace:

swift
FinanceApp/
├── Tuist/
│   ├── Config.swift
│   ├── Package.swift
│   └── ProjectDescriptionHelpers/
│       ├── Settings/
│       │   └── Settings+Layers.swift
│       ├── Target/
│       │   └── Target+Module.swift
│       └── Project/
│           └── Project+Module.swift
├── Workspace.swift
├── Projects/
│   ├── App/
│   │   └── Project.swift
│   ├── Core/
│   │   ├── NetworkKit/Project.swift
│   │   ├── AuthKit/Project.swift
│   │   ├── AnalyticsKit/Project.swift
│   │   └── PersistenceKit/Project.swift
│   ├── Shared/
│   │   ├── SharedUI/Project.swift
│   │   ├── SharedModels/Project.swift
│   │   ├── DesignSystem/Project.swift
│   │   └── TestHelpers/Project.swift
│   └── Features/
│       ├── FeatureDashboard/Project.swift
│       ├── FeatureTransfer/Project.swift
│       └── ... (17 feature modules)
├── TestPlans/
│   ├── UnitTests.xctestplan
│   └── AllTests.xctestplan
└── Makefile

Config.swift dengan Tuist Cloud:

swift
// Tuist/Config.swift
import ProjectDescription

let config = Config(
    cloud: .cloud(
        projectId: "financeapp/ios",
        url: "https://tuist.financeapp.internal",
        options: [.optional]  // CI jalan meski cloud tidak available
    ),
    compatibleXcodeVersions: .list(["16.2"]),
    swiftVersion: "6.0"
)

Architecture enforcement di Project.swift:

swift
// Tuist/ProjectDescriptionHelpers/Architecture/LayerRules.swift
import ProjectDescription

public enum ModuleLayer: String, CaseIterable {
    case core, shared, feature, app
}

// Compile-time-safe dependency declarations
public extension TargetDependency {
    static func core(_ module: CoreModule) -> TargetDependency {
        .project(
            target: module.rawValue,
            path: .relativeToManifest("../../Core/\(module.rawValue)")
        )
    }
    static func shared(_ module: SharedModule) -> TargetDependency {
        .project(
            target: module.rawValue,
            path: .relativeToManifest("../../Shared/\(module.rawValue)")
        )
    }
}

public enum CoreModule: String {
    case networkKit = "NetworkKit"
    case authKit = "AuthKit"
    case analyticsKit = "AnalyticsKit"
    case persistenceKit = "PersistenceKit"
}

public enum SharedModule: String {
    case sharedUI = "SharedUI"
    case sharedModels = "SharedModels"
    case designSystem = "DesignSystem"
    case testHelpers = "TestHelpers"
}
swift
// Projects/Features/FeatureTransfer/Project.swift
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.module(
    name: "FeatureTransfer",
    layer: .feature,
    dependencies: [
        .core(.networkKit),    // type-safe — typo langsung error di manifest compile
        .core(.authKit),
        .shared(.sharedUI),
        .shared(.sharedModels),
        .external(name: "Stripe"),
    ],
    hasExampleApp: true
)

Hasil setelah implementasi Tuist:

  • Clean build CI: 28 menit → 6 menit (cache hit Core + Shared = 22 menit saved)
  • Onboarding developer baru: setup dari nol sampai bisa build = 15 menit (make setup)
  • Implicit import violations ditemukan: 12 (semua diperbaiki saat migrasi)
  • Circular dependency potential terdeteksi: 2 (sebelumnya tidak ketahuan)

Use Case 2: Rapid Development dengan Feature Example Apps

Tim membutuhkan cara untuk mengerjakan feature module secara isolated tanpa harus compile seluruh workspace:

swift
// Tuist/ProjectDescriptionHelpers/Target+ExampleApp.swift

import ProjectDescription

public extension Project {

    static func moduleWithExample(
        name: String,
        layer: FeatureLayer,
        dependencies: [TargetDependency] = [],
        exampleDependencies: [TargetDependency] = []
    ) -> Project {

        var targets = Target.make(name: name, layer: layer, dependencies: dependencies)

        // Example app untuk isolated development
        let exampleSources: [SourceFileGlob] = [
            .glob("Example/Sources/**"),
        ]

        // Check jika Example/ folder ada
        let exampleTarget = Target.target(
            name: "\(name)Example",
            destinations: .iOS,
            product: .app,
            bundleId: "com.company.\(name.lowercased()).example",
            deploymentTargets: .iOS("17.0"),
            infoPlist: .extendingDefault(with: [
                "UILaunchScreen": .dictionary([:]),
            ]),
            sources: SourceFilesList(globs: exampleSources),
            resources: "Example/Resources/**",
            dependencies: [
                .target(name: name),
                .project(target: "TestHelpers", path: "../../Shared/TestHelpers"),
            ] + exampleDependencies,
            settings: .settings(
                base: [
                    "PRODUCT_BUNDLE_IDENTIFIER": "com.company.\(name.lowercased()).example",
                ]
            )
        )
        targets.append(exampleTarget)

        return Project(
            name: name,
            targets: targets,
            schemes: [
                // Scheme untuk open isolated example app
                .scheme(
                    name: "\(name)-Example",
                    buildAction: .buildAction(targets: [
                        .target("\(name)Example")
                    ]),
                    runAction: .runAction(
                        executable: .target("\(name)Example")
                    )
                ),
            ]
        )
    }
}

Developer workflow dengan example app:

swift
# Buka hanya FeatureCheckout dalam isolation
cd Projects/Features/FeatureCheckout

# Generate mini-workspace hanya untuk module ini
tuist generate

# Xcode buka dengan project berisi:
# - FeatureCheckout (framework)
# - FeatureCheckoutTests (unit tests)  
# - FeatureCheckoutExample (standalone app)
# Pre-built: NetworkKit, SharedUI, dll (dari cache)

# Full compile time: ~30 detik (vs 8+ menit untuk seluruh workspace)