Section 4/171 menit

4. Prinsip Dasar yang Harus Dipegang

4. Prinsip Dasar yang Harus Dipegang

Prinsip 1: Default ke Value Type Sendable

Untuk model/DTO/value object: selalu desain sebagai struct atau enum dengan stored property immutable. Mereka otomatis Sendable.

swift
// ✓ Default desain untuk model
struct UserProfile: Sendable, Identifiable, Equatable {
    let id: UUID
    let name: String
    let avatarURL: URL?
    let joinedAt: Date
}

Prinsip 2: Mutable State Hidup di Actor

Kalau ada state yang berubah dari banyak tempat, letakkan di actor. Jangan pakai class biasa dengan lock manual — itu lebih sulit di-review dan rawan bug.

swift
// ✓ Mutable state di actor
actor SessionStore {
    private var sessions: [UUID: Session] = [:]
    func add(_ s: Session) { sessions[s.id] = s }
    func remove(id: UUID) { sessions[id] = nil }
}

Prinsip 3: UI Selalu @MainActor

ViewModel, presenter, navigation coordinator, view extension — semuanya @MainActor. Tidak ada pengecualian.

swift
// ✓ ViewModel @MainActor
@MainActor
@Observable
final class HomeViewModel {
    var items: [Item] = []
    var isLoading = false
}

Prinsip 4: Function Async Hanya Kalau Memang Butuh

Jangan menambahkan async di signature kalau body fungsi tidak punya await. Async menyebar — sekali ditambah, semua caller harus jadi async.

swift
// ❌ async tanpa await
func formatName(_ name: String) async -> String {
    return name.uppercased()  // tidak ada await
}

// ✓ sync
func formatName(_ name: String) -> String {
    return name.uppercased()
}

Prinsip 5: Structured > Unstructured

Selalu prefer async let / TaskGroup / withTaskCancellationHandler daripada Task { } bebas. Structured concurrency punya garansi: parent menunggu children, cancellation propagate otomatis.

swift
// ❌ Unstructured
func loadAll() async {
    Task { await loadUsers() }  // detached lifecycle
    Task { await loadPosts() }  // bocor kalau caller dibatalkan
}

// ✓ Structured
func loadAll() async {
    async let users = loadUsers()
    async let posts = loadPosts()
    _ = await (users, posts)  // menunggu keduanya, cancellation propagate
}