The app uses MVVM (Model–View–ViewModel) with a dedicated Networking layer
- The ViewModel owns all state transitions and is completely independent of SwiftUI, making it unit-testable without launching a UI.
- Views become pure renderers that react to
viewModel.state— no business logic leaks in.
Rather than tracking isLoading, hasError, and isEmpty as separate booleans (which can form impossible combinations), a single ViewState enum drives the entire UI.
Uses the new @Observable macro instead of ObservableObject + @Published. This eliminates boilerplate and allows the ViewModel to be held as @State in the root view rather than @StateObject.
NetworkServiceProtocol defines a single fetchDoctors() async throws -> [Doctor] method. NetworkService conforms to it using URLSession.
The project build setting SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor makes all types implicitly @MainActor. NetworkService methods are marked nonisolated so URLSession runs on a background thread rather than blocking the main thread.
AppError is a typed Error enum with a userFacingMessage property. The app never shows a raw system error message. Every error state provides a retry button that re-triggers the fetch.
Approximately 3 hours:
- 20 min: reading requirements, exploring the project scaffold, and confirming the API response shape
- 2 hrs: implementation (models, networking, ViewModel, views)
- 40 min: unit tests and README