Section 6/71 menit
6. Real Use Cases
6. Real Use Cases
Use Case 1: SDK Multi-Modul — Networking + Analytics
swift
NetworkSDK (Package.swift)
├── NetworkCore/ — request, response, auth
├── Caching/ — response cache
├── Analytics/ — telemetry dan logging
└── NetworkUI/ — loading indicators, retry UI
swift
// NetworkCore/Authentication.swift
// package: dibutuhkan oleh Analytics untuk attach auth info ke events
package struct AuthContext {
package let userID: String?
package let sessionID: String
package let deviceID: String
package static var current: AuthContext {
AuthContext(
userID: AuthStore.shared.currentUserID,
sessionID: SessionManager.shared.sessionID,
deviceID: DeviceIdentifier.current
)
}
}
// NetworkCore/RequestPipeline.swift
// package: Analytics perlu hook ke pipeline untuk record timing
package protocol RequestMiddleware {
package func process(_ request: URLRequest) async throws -> URLRequest
package func process(_ response: HTTPURLResponse, data: Data) async throws -> Data
}
package class RequestPipeline {
package var middlewares: [any RequestMiddleware] = []
package func execute(_ request: URLRequest) async throws -> (Data, HTTPURLResponse) {
var mutableRequest = request
for middleware in middlewares {
mutableRequest = try await middleware.process(mutableRequest)
}
// ... execute request
return (Data(), HTTPURLResponse())
}
}
// Analytics/NetworkAnalyticsMiddleware.swift
import NetworkCore
// Analytics bisa inject middleware ke dalam pipeline — tanpa end-user tahu cara ini
package class NetworkAnalyticsMiddleware: RequestMiddleware {
package init() {}
package func process(_ request: URLRequest) async throws -> URLRequest {
let auth = AuthContext.current // ✅ package access — sama paket
recordRequestStart(url: request.url, userID: auth.userID)
return request
}
package func process(_ response: HTTPURLResponse, data: Data) async throws -> Data {
recordRequestEnd(statusCode: response.statusCode, size: data.count)
return data
}
private func recordRequestStart(url: URL?, userID: String?) {
print("Request started: \(url?.absoluteString ?? "unknown")")
}
private func recordRequestEnd(statusCode: Int, size: Int) {
print("Request ended: \(statusCode), \(size) bytes")
}
}
// NetworkSDK/Setup.swift — entry point yang public
import NetworkCore
import Analytics
public class NetworkSDK {
public static let shared = NetworkSDK()
private let pipeline = RequestPipeline()
private init() {
// Setup internal — end-user tidak perlu tahu ini
pipeline.middlewares.append(NetworkAnalyticsMiddleware())
}
// Ini yang public — clean API untuk end-user
public func fetch(url: URL) async throws -> Data {
let request = URLRequest(url: url)
let (data, _) = try await pipeline.execute(request)
return data
}
}
Use Case 2: Shared Test Infrastructure
swift
AppTests (Test Targets dalam satu Package)
├── CoreTests/
├── FeatureTests/
└── TestHelpers/ — shared test utilities
swift
// TestHelpers/MockFactory.swift
package class MockFactory {
package static func makeUser(
id: String = "test_user",
name: String = "Test User",
role: UserRole = .basic
) -> User {
User(id: id, name: name, role: role)
}
package static func makeOrder(
id: String = "test_order",
items: [OrderItem] = [makeOrderItem()]
) -> Order {
Order(id: id, items: items, createdAt: Date())
}
package static func makeOrderItem(
productID: String = "prod_1",
quantity: Int = 1,
price: Decimal = 10.0
) -> OrderItem {
OrderItem(productID: productID, quantity: quantity, price: price)
}
}
// TestHelpers/AssertionHelpers.swift
import Testing
// Custom assertion helpers yang di-share semua test targets
package func assertUserEquals(
_ actual: User,
_ expected: User,
sourceLocation: SourceLocation = #_sourceLocation
) {
#expect(actual.id == expected.id, sourceLocation: sourceLocation)
#expect(actual.name == expected.name, sourceLocation: sourceLocation)
#expect(actual.role == expected.role, sourceLocation: sourceLocation)
}
// CoreTests/UserServiceTests.swift
import TestHelpers
import Testing
@Suite("UserService")
struct UserServiceTests {
@Test
func createUser() async throws {
let input = MockFactory.makeUser(name: "Ari") // ✅ package access
let created = try await UserService().create(input)
assertUserEquals(created, input) // ✅ package access
}
}
// FeatureTests/CheckoutTests.swift
import TestHelpers
import Testing
@Suite("Checkout")
struct CheckoutTests {
@Test
func checkout() async throws {
let user = MockFactory.makeUser(role: .premium) // ✅ re-use mock factory
let order = MockFactory.makeOrder()
// ...
}
}
Use Case 3: Feature Flags System
swift
// FeatureFlags module (dalam SDK package)
package class FeatureFlagRegistry {
package static let shared = FeatureFlagRegistry()
private var flags: [String: Bool] = [:]
package func register(flag: String, defaultValue: Bool) {
flags[flag] = defaultValue
}
package func isEnabled(_ flag: String) -> Bool {
flags[flag] ?? false
}
// Internal ke SDK — tidak untuk end-user
package func override(flag: String, value: Bool) {
flags[flag] = value
}
}
// Feature modules — register flags saat init
// FeatureA module
import FeatureFlags
package enum FeatureAFlags {
package static let newOnboarding = "feature_a.new_onboarding"
package static let betaCheckout = "feature_a.beta_checkout"
}
package func setupFeatureA() {
FeatureFlagRegistry.shared.register(flag: FeatureAFlags.newOnboarding, defaultValue: false)
FeatureFlagRegistry.shared.register(flag: FeatureAFlags.betaCheckout, defaultValue: false)
}
// Public entry point — end-user hanya perlu ini
public class AppSDK {
public static func initialize() {
setupFeatureA() // package — end-user tidak bisa panggil langsung
setupFeatureB()
setupFeatureC()
}
// End-user API: hanya bisa cek flag via nama yang di-expose
public func isFeatureEnabled(_ name: PublicFeatureFlag) -> Bool {
FeatureFlagRegistry.shared.isEnabled(name.rawValue)
}
}
public enum PublicFeatureFlag: String {
case newOnboarding = "feature_a.new_onboarding"
// Hanya expose flag yang memang boleh dikontrol end-user
}