---
title: Tách biệt logic xử lý và truy cập dữ liệu trong tầng service
impact: HIGH
impactDescription: Kết hợp logic nghiệp vụ và data access trong cùng một class làm khó test, khó thay đổi storage layer và vi phạm Single Responsibility.
tags: swift, ios, architecture, repository-pattern, service, code-quality
---

## Tách biệt logic xử lý và truy cập dữ liệu trong tầng service

ViewModel/Presenter không nên gọi trực tiếp Core Data, UserDefaults, hay network. Tách thành **Repository** (data access) và **UseCase/Service** (business logic). Điều này tuân theo kiến trúc Clean Architecture được Apple khuyến nghị.

**Incorrect (trộn lẫn nghiệp vụ và data access):**

```swift
class OrderViewModel {
    func placeOrder(items: [CartItem], userId: String) {
        // Gọi API trực tiếp trong ViewModel
        let request = URLRequest(url: URL(string: "https://api.example.com/orders")!)
        URLSession.shared.dataTask(with: request) { data, _, error in
            // Xử lý JSON thủ công trong ViewModel
            guard let data = data,
                  let order = try? JSONDecoder().decode(Order.self, from: data) else { return }

            // Lưu Core Data trực tiếp trong ViewModel
            let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
            let entity = OrderEntity(context: context)
            entity.id = order.id
            try? context.save()
        }.resume()
    }
}
```

**Correct (Repository + UseCase tách biệt):**

```swift
// Repository: chỉ lo data access
protocol OrderRepositoryProtocol {
    func createOrder(request: CreateOrderRequest) async throws -> Order
    func saveOrderLocally(_ order: Order) throws
}

class OrderRepository: OrderRepositoryProtocol {
    private let apiClient: APIClientProtocol
    private let coreDataManager: CoreDataManagerProtocol

    init(apiClient: APIClientProtocol, coreDataManager: CoreDataManagerProtocol) {
        self.apiClient = apiClient
        self.coreDataManager = coreDataManager
    }

    func createOrder(request: CreateOrderRequest) async throws -> Order {
        return try await apiClient.post("/orders", body: request)
    }

    func saveOrderLocally(_ order: Order) throws {
        try coreDataManager.insert(order, entityType: OrderEntity.self)
    }
}

// UseCase: chỉ lo nghiệp vụ
class PlaceOrderUseCase {
    private let orderRepository: OrderRepositoryProtocol
    private let inventoryService: InventoryServiceProtocol

    func execute(items: [CartItem], userId: String) async throws -> Order {
        // Kiểm tra tồn kho
        try await inventoryService.validateAvailability(items: items)
        let request = CreateOrderRequest(items: items, userId: userId)
        let order = try await orderRepository.createOrder(request: request)
        try orderRepository.saveOrderLocally(order)
        return order
    }
}

// ViewModel: chỉ gọi UseCase
class OrderViewModel {
    private let placeOrderUseCase: PlaceOrderUseCase

    func placeOrder(items: [CartItem]) async {
        do {
            order = try await placeOrderUseCase.execute(items: items, userId: currentUserId)
        } catch { /* handle */ }
    }
}
```

**Tools:** Code Review, Unit Tests (mock repository dễ dàng)

