Section 12/131 menit

12. Real Use Cases

12. Real Use Cases

Use Case 1: Startup Menghilangkan Merge Conflict dengan XcodeGen

Tim iOS 6 developer di fintech startup mengalami merge conflict .xcodeproj setiap sprint. Setiap feature branch yang menyentuh folder berbeda menghasilkan conflict UUID yang harus di-resolve manual.

Setup XcodeGen:

swift
# project.yml — konfigurasi lengkap untuk startup app

name: FinanceApp
options:
  bundleIdPrefix: com.fintech
  deploymentTarget:
    iOS: "17.0"
  defaultConfig: Debug
  createIntermediateGroups: true  # mirror folder structure di project navigator
  xcodeVersion: "16.2"
  transitivelyLinkDependencies: true

settings:
  base:
    SWIFT_VERSION: 6.0
    SWIFT_STRICT_CONCURRENCY: complete
    ENABLE_BITCODE: NO
    DEBUG_INFORMATION_FORMAT: dwarf-with-dsym
  configs:
    Debug:
      OTHER_SWIFT_FLAGS: "$(inherited) -DDEBUG"
      SWIFT_OPTIMIZATION_LEVEL: "-Onone"
    Staging:
      OTHER_SWIFT_FLAGS: "$(inherited) -DSTAGING"
      SWIFT_OPTIMIZATION_LEVEL: "-O"
      VALIDATE_PRODUCT: YES
    Release:
      SWIFT_OPTIMIZATION_LEVEL: "-O"
      VALIDATE_PRODUCT: YES

targets:
  FinanceApp:
    type: application
    platform: iOS
    sources:
      - path: Sources/App
        excludes:
          - "**/__Snapshots__"
    resources:
      - Sources/App/Assets.xcassets
      - Sources/App/Localizable.strings
    dependencies:
      - target: NetworkKit
      - target: AuthKit
      - target: FeatureDashboard
      - target: FeatureTransaction
      - package: FirebaseAnalytics
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.fintech.app
        ASSETCATALOG_COMPILER_APPICON_NAME: AppIcon
      configs:
        Debug:
          PRODUCT_BUNDLE_IDENTIFIER: com.fintech.app.debug
        Staging:
          PRODUCT_BUNDLE_IDENTIFIER: com.fintech.app.staging

  NetworkKit:
    type: framework
    platform: iOS
    sources: Modules/NetworkKit/Sources
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.fintech.networkkit

  AuthKit:
    type: framework
    platform: iOS
    sources: Modules/AuthKit/Sources
    dependencies:
      - target: NetworkKit
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.fintech.authkit

  FeatureDashboard:
    type: framework
    platform: iOS
    sources: Modules/FeatureDashboard/Sources
    dependencies:
      - target: NetworkKit
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.fintech.featuredashboard

  FeatureTransaction:
    type: framework
    platform: iOS
    sources: Modules/FeatureTransaction/Sources
    dependencies:
      - target: NetworkKit
    settings:
      base:
        PRODUCT_BUNDLE_IDENTIFIER: com.fintech.featuretransaction

  FinanceAppTests:
    type: bundle.unit-test
    platform: iOS
    sources: Tests/FinanceAppTests
    dependencies:
      - target: FinanceApp

packages:
  Firebase:
    url: https://github.com/firebase/firebase-ios-sdk
    from: "11.0.0"
  FirebaseAnalytics:
    package: Firebase
    product: FirebaseAnalytics

Makefile untuk workflow:

swift
# Makefile — shortcut untuk developer

.PHONY: generate clean bootstrap

generate:
	xcodegen generate

clean:
	rm -rf FinanceApp.xcodeproj FinanceApp.xcworkspace

bootstrap: generate
	@echo "Project generated. Open FinanceApp.xcodeproj"

# Git hook setup
setup-hooks:
	cp scripts/post-checkout .git/hooks/post-checkout
	chmod +x .git/hooks/post-checkout
	@echo "Git hooks installed"

Use Case 2: Scale-Up ke Tuist dengan Binary Caching

Perusahaan e-commerce dengan 15 iOS developer dan 20+ module membutuhkan solusi untuk build time yang sudah 25 menit di CI.

Workspace.swift:

swift
// Workspace.swift
import ProjectDescription

let workspace = Workspace(
    name: "ShopApp",
    projects: [
        "Projects/App",
        "Projects/Core/NetworkKit",
        "Projects/Core/AuthKit",
        "Projects/Core/AnalyticsKit",
        "Projects/Core/SharedUI",
        "Projects/Features/FeatureHome",
        "Projects/Features/FeatureSearch",
        "Projects/Features/FeatureCart",
        "Projects/Features/FeatureCheckout",
        "Projects/Features/FeatureProfile",
        "Projects/Features/FeatureOrders",
    ],
    generationOptions: .options(
        automaticSchemesOptions: .enabled(
            targetSchemesGrouping: .byNameSuffix(
                build: [],
                test: ["Tests"],
                run: ["App"]
            )
        )
    )
)

Project.swift untuk FeatureCheckout:

swift
// Projects/Features/FeatureCheckout/Project.swift
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.feature(
    name: "FeatureCheckout",
    dependencies: [
        .project(target: "NetworkKit", path: "../../Core/NetworkKit"),
        .project(target: "AuthKit", path: "../../Core/AuthKit"),
        .project(target: "SharedUI", path: "../../Core/SharedUI"),
        .external(name: "Stripe"),
    ],
    additionalResources: [
        "Resources/Localizable.strings",
        "Resources/PaymentAssets.xcassets",
    ]
)

CI script dengan Tuist cache:

swift
#!/bin/bash
# scripts/ci-build.sh — digunakan di GitHub Actions

set -euo pipefail

echo "=== Setting up Tuist ==="
mise install

echo "=== Warming cache ==="
# Dalam CI: coba gunakan cache yang tersimpan
tuist cache --external-only 2>/dev/null || true

echo "=== Generating project ==="
tuist install
tuist generate

echo "=== Building ==="
xcodebuild build-for-testing \
    -scheme ShopApp \
    -destination "platform=iOS Simulator,name=iPhone 15" \
    -derivedDataPath DerivedData \
    | xcpretty

echo "=== Running tests ==="
xcodebuild test-without-building \
    -scheme ShopApp \
    -destination "platform=iOS Simulator,name=iPhone 15" \
    -derivedDataPath DerivedData \
    -resultBundlePath TestResults.xcresult \
    | xcpretty

echo "=== Done ==="

Hasilnya: build time CI turun dari 25 menit menjadi 7 menit rata-rata karena modul Core (NetworkKit, AuthKit, SharedUI) tidak perlu dikompilasi ulang ketika hanya feature module yang berubah.