Belajar Swift - Architecture & Design Patterns
Episode 16 of 23

Belajar Swift - Architecture & Design Patterns

Episode ini membahas arsitektur aplikasi Swift: perbandingan MVC, MVVM, MVP, dan Clean Architecture, protocol-oriented design dengan dependency injection, pola coordinator untuk navigation, serta state management menggunakan Combine dan SwiftUI.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Pendahuluan

Saat aplikasi tumbuh dari puluhan menjadi ribuan file, arsitektur menentukan apakah perubahan tetap terasa ringan atau berubah menjadi mimpi buruk. Episode 16 membahas architecture dan design patterns di Swift: MVC, MVVM, MVP, Clean Architecture, serta pola pendukung seperti dependency injection, coordinator, dan Combine.

Tidak ada arsitektur yang benar untuk semua kasus. Yang kalian pelajari di sini adalah prinsip yang membedakan arsitektur baik dari buruk: pemisahan tanggung jawab, arah dependensi yang terkendali, dan pengujian yang mudah.

Pola Arsitektur Utama

MVC dan MVP

MVC (Model-View-Controller) adalah arsitektur bawaan UIKit: View menampilkan data, Controller memediasi, dan Model memegang data. Masalah klasiknya adalah Massive View Controller — controller menyerap semua logika karena jadi satu-satunya tempat menaruh kode.

MVP (Model-View-Presenter) memindahkan logika tampilan ke Presenter, dengan View hanya meneruskan event dan menampilkan hasil. Presenter bisa diuji tanpa UI nyata — tetapi View harus menerapkan protocol yang menambah boilerplate.

MVVM: Arsitektur Modern

MVVM (Model-View-ViewModel) memisahkan state dan logika tampilan ke ViewModel yang tidak bergantung pada View. View mengamati ViewModel dan merespons perubahannya:

ViewModel dengan Combine
import Combine
import Foundation
 
final class LoginViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var pesanError: String?
 
    var bisaSubmit: Bool {
        !email.isEmpty && !password.isEmpty
    }
}

@Published var email = "" membuat properti yang bisa diamati oleh View, dan var bisaSubmit menyediakan state turunan. ViewModel murni Swift bisa diuji tanpa UI — inilah daya tarik utama MVVM untuk aplikasi SwiftUI.

Clean Architecture

Clean Architecture memusatkan aturan bisnis di inti, terpisah dari framework dan antarmuka. Lapisan luarnya (UI, database, jaringan) bergantung pada inti, bukan sebaliknya. Di Swift, inti diekspresikan dengan protocol dan use case, sementara framework berdiam di lapisan terluar.

Protocol-Oriented Design dan Dependency Injection

Desain Berbasis Protocol

Episode 5 memperkenalkan protocol; dalam arsitektur, protocol menjadi titik keputusan desain. Dependency diarahkan ke abtraksi, bukan implementasi:

Dependency injection berbasis protocol
protocol PenyimpanCatatan {
    func simpan(_ teks: String) throws
}
 
struct PenyimpanFile: PenyimpanCatatan {
    func simpan(_ teks: String) throws {
        let url = docs.appendingPathComponent("catatan.txt")
        try teks.write(to: url, atomically: true, encoding: .utf8)
    }
}
 
struct PenyimpanInMemory: PenyimpanCatatan {
    var data: [String] = []
    func simpan(_ teks: String) throws {
        data.append(teks)
    }
}

protocol PenyimpanCatatan mendefinisikan kontrak penyimpanan. ViewModel menerima PenyimpanCatatan saat dibuat — test menyuntikkan PenyimpanInMemory, produksi memakai PenyimpanFile. Ini dependency injection: dependensi diberikan dari luar, bukan diciptakan di dalam.

Manfaat DI

DI menawarkan tiga keuntungan nyata:

  • Testabilitas: dependency asli bisa diganti tiruan.
  • Fleksibilitas: implementasi bisa ditukar tanpa mengubah pemakai.
  • Kejelasan: dependensi objek terlihat eksplisit saat inisialisasi.

Coordinator dan Navigation

Memisahkan Navigasi

Coordinator memindahkan logika navigasi keluar dari View Controller, sehingga View Controller tidak perlu tahu harus berpindah ke layar apa:

Coordinator sederhana
final class MainCoordinator {
    private let navigator: UINavigationController
 
    init(navigator: UINavigationController) {
        self.navigator = navigator
    }
 
    func mulai() {
        let vc = DaftarViewController(coordinator: self)
        navigator.pushViewController(vc, animated: true)
    }
 
    func bukaDetail(id: Int) {
        let vc = DetailViewController(id: id)
        navigator.pushViewController(vc, animated: true)
    }
}

MainCoordinator mengatur transisi antar layar di satu tempat. View Controller cukup memanggil metode coordinator — navigasi menjadi terpusat, mudah diuji, dan mudah diubah. Di SwiftUI, peran ini sering digantikan oleh nilai route yang terdefinisi secara eksplisit.

State Management dengan Combine dan SwiftUI

Combine: Aliran Nilai

Combine adalah framework untuk memproses aliran nilai berubah seiring waktu. Intinya adalah Publisher yang memancarkan nilai dan Subscriber yang menerimanya:

Publisher dan sink
let publisher = Just("Halo Combine")
let cancellable = publisher.sink { nilai in
    print(nilai)
}

Just("Halo Combine") adalah publisher yang memancarkan satu nilai lalu selesai. publisher.sink { ... } menerima nilai tersebut. Combine menyediakan operator transformasi seperti map, filter, dan combineLatest yang membuat state app mengalir secara deklaratif.

SwiftUI dan @StateObject

SwiftUI mengintegrasikan Combine secara native. View mengamati ObservableObject melalui property wrapper:

SwiftUI dengan ObservableObject
import SwiftUI
 
struct LoginView: View {
    @StateObject var viewModel = LoginViewModel()
 
    var body: some View {
        VStack {
            TextField("Email", text: $viewModel.email)
            SecureField("Password", text: $viewModel.password)
            if let pesan = viewModel.pesanError {
                Text(pesan)
            }
        }
    }
}

@StateObject var viewModel = LoginViewModel() membuat ViewModel dimiliki view dan tetap hidup saat view di-render ulang. Setiap @Published yang berubah memicu ulang rendering view — inilah inti state management SwiftUI yang akan kita dalami di episode 17.

Info

Arsitektur terbaik adalah yang sesuai konteks. Mulai sederhana dengan MVVM untuk fitur kecil, dan adopsi pola yang lebih ketat — Clean Architecture, coordinator, modularization — saat tim dan codebase tumbuh. Jangan pernah memaksakan arsitektur sebagai dogma.

Penutup

Inti yang harus dibawa pulang:

  • MVC, MVP, dan MVVM membagi tanggung jawab dengan cara yang berbeda.
  • MVVM dengan ObservableObject menjadi fondasi state management SwiftUI.
  • Clean Architecture memusatkan aturan bisnis dan membalik arah dependensi.
  • Dependency injection berbasis protocol meningkatkan testabilitas.
  • Coordinator memusatkan logika navigasi di satu tempat.
  • Combine menghubungkan publisher dan subscriber untuk aliran state deklaratif.

Di episode 17 selanjutnya kita akan membahas SwiftUI dan declarative UI — dasar views dan layout, state management dengan @State, @Binding, @ObservedObject, dan @EnvironmentObject, animasi dan transisi dengan adaptive UI, serta integrasi antara UIKit dan SwiftUI. UI kalian akan menjadi deklaratif dan hidup!

Belajar Swift - Architecture & Design Patterns | Belajar Swift