티스토리 뷰
"코드를 기능별로 잘 나누는 것만으로 정말 좋은 아키텍처가 될까?"
아키텍처 패턴을 고민할 때 가장 중요한 것은 코드를 단순히 레이어별로 나누는 것이 아니라, 각 레이어가 올바르게 역할을 수행하고, 의존성이 잘 정리되어 있는지를 따지는 것이다.
Clean Architecture는 Layer Separation(레이어 분리) 와 Dependency Rule(의존성 규칙) 을 통해 확장성 높은 소프트웨어를 만드는 것을 목표로 한다.
1️⃣ Clean Architecture란?
Clean Architecture는 로버트 C. 마틴(Uncle Bob) 이 제안한 소프트웨어 설계 원칙으로,
애플리케이션을 책임에 따라 계층(Layer)으로 분리하고, 의존성을 내부 도메인 중심으로 흐르게 하는 구조를 말한다.
✅ 핵심 목표:
- 비즈니스 로직과 UI를 분리하여 유지보수성을 높인다.
- 의존성을 도메인 중심으로 설계하여, 외부 요소(Database, UI, Frameworks)에 영향을 덜 받도록 한다.
- 테스트가 용이한 구조를 만들어 단위 테스트(Unit Test)가 쉽도록 한다.
Clean Architecture는 계층 구조와 의존성 규칙(Dependency Rule) 을 기반으로 설계된다.
2️⃣ Clean Architecture의 레이어 구조
Clean Architecture는 아래와 같은 4개의 계층(Layer)으로 나뉜다.
[ UI Layer ] → View, ViewModel (iOS에서는 SwiftUI, UIKit 등)
[ Interface Layer ] → Use Case (Interactor)
[ Domain Layer ] → Entities (비즈니스 로직)
[ Data Layer ] → Repository, Data Sources (DB, API)
📌 레이어별 역할 정리
| 레이어 | 역할 | 예시 |
| UI Layer (프레젠테이션 계층) | 사용자 입력을 받고, 화면을 구성 | ViewController, SwiftUI View |
| Interface Layer (Use Case 계층) | UI와 도메인 사이의 연결 역할, 비즈니스 규칙 실행 | UseCase, Interactor |
| Domain Layer (도메인 계층) | 애플리케이션의 핵심 로직, 엔티티 정의 | UserEntity, ProductEntity |
| Data Layer (데이터 계층) | 데이터 관리 (DB, API, Local Storage) | Repository, NetworkService, Database |
3️⃣ Dependency Rule(의존성 규칙)
Clean Architecture에서 가장 중요한 개념은 의존성이 바깥쪽에서 안쪽으로만 흐른다는 점이다.
UI → Interface(Use Case) → Domain(Entity) → Data
✅ 의존성이 내부 도메인 중심으로 흐르는 이유
- 비즈니스 로직을 UI와 분리하여 UI 변경이 비즈니스 로직에 영향을 주지 않도록 한다.
- 외부 요소(DB, API, 프레임워크 등)에 대한 의존성을 줄여 확장성을 높인다.
- 단위 테스트가 용이하도록 구조화하여 유지보수성을 높인다.
💡 즉, 핵심 비즈니스 로직은 어떤 프레임워크나 라이브러리에도 의존하지 않도록 한다!
4️⃣ Clean Architecture를 iOS 프로젝트에 적용하기
이제 Clean Architecture를 iOS 프로젝트에서 어떻게 구현할 수 있는지 살펴보자.
✅ 1. Entity (Domain Layer)
도메인 계층의 핵심 비즈니스 로직을 담당하는 엔티티(Entity)이다.
struct User {
let id: Int
let name: String
}
✅ 2. Use Case (Interface Layer)
비즈니스 로직을 실행하는 역할을 한다.
UI와 도메인 사이의 연결고리 역할을 하며, Repository를 사용해 데이터를 가져온다.
protocol FetchUserUseCase {
func execute(userId: Int) async throws -> User
}
class FetchUserInteractor: FetchUserUseCase {
private let repository: UserRepository
init(repository: UserRepository) {
self.repository = repository
}
func execute(userId: Int) async throws -> User {
return try await repository.getUser(by: userId)
}
}
✅ 3. Repository (Data Layer)
Repository는 데이터를 가져오는 인터페이스 역할을 한다.
protocol UserRepository {
func getUser(by id: Int) async throws -> User
}
class UserRepositoryImpl: UserRepository {
private let apiClient: APIClient
init(apiClient: APIClient) {
self.apiClient = apiClient
}
func getUser(by id: Int) async throws -> User {
let response = try await apiClient.request(endpoint: "/users/\(id)")
return User(id: response["id"] as! Int, name: response["name"] as! String)
}
}
✅ 4. ViewModel (UI Layer)
ViewModel은 UI에서 데이터를 받아오고 상태를 관리하는 역할을 한다.
class UserViewModel: ObservableObject {
private let fetchUserUseCase: FetchUserUseCase
@Published var user: User?
init(fetchUserUseCase: FetchUserUseCase) {
self.fetchUserUseCase = fetchUserUseCase
}
func loadUser(userId: Int) async {
do {
let user = try await fetchUserUseCase.execute(userId: userId)
DispatchQueue.main.async {
self.user = user
}
} catch {
print("Error loading user: \(error)")
}
}
}
✅ 5. View (UI Layer)
SwiftUI에서 ViewModel을 사용해 UI를 업데이트한다.
struct UserView: View {
@StateObject private var viewModel = UserViewModel(fetchUserUseCase: FetchUserInteractor(repository: UserRepositoryImpl(apiClient: APIClient())))
var body: some View {
VStack {
if let user = viewModel.user {
Text(user.name)
} else {
ProgressView()
}
}
.onAppear {
Task {
await viewModel.loadUser(userId: 1)
}
}
}
}
5️⃣ Clean Architecture 적용 시 고려할 점
✅ 언제 적용하면 좋을까?
- 대규모 프로젝트에서 코드의 확장성과 유지보수성을 높이고 싶을 때
- 테스트가 중요한 프로젝트에서 UI와 비즈니스 로직을 분리하고 싶을 때
- 팀 협업이 필요한 경우 (각 레이어별로 역할이 나뉘므로 개발이 분리됨)
✅ 언제 과할 수 있을까?
- 작은 프로젝트에서는 계층이 많아져서 오히려 복잡성이 증가할 수도 있다.
- 모든 프로젝트에서 반드시 Clean Architecture를 적용할 필요는 없으며, 프로젝트의 규모와 요구사항을 고려해야 한다.
정리
✅ Clean Architecture는 비즈니스 로직과 UI를 분리하여 유지보수를 쉽게 만드는 설계 패턴이다.
✅ 핵심 개념은 Layer Separation(레이어 분리)과 Dependency Rule(의존성 규칙) 을 따르는 것!
✅ 도메인 계층이 외부 요소(UI, DB, API 등)에 의존하지 않도록 설계해야 한다.
✅ iOS에서는 Entity, UseCase, Repository, ViewModel, View로 분리하여 적용할 수 있다.
✅ 실무에서 적용할 때는 프로젝트 규모와 필요에 따라 적절히 활용하는 것이 중요하다.
Clean Architecture는 처음에는 조금 복잡해 보일 수 있지만, 한 번 익숙해지면 유지보수성과 확장성이 뛰어난 코드를 작성할 수 있다.
프로젝트에서 직접 적용해보면서 어떤 부분이 도움이 되는지 경험해보는 것이 가장 중요하다.
이제, Clean Architecture를 적용해 더 깔끔한 iOS 앱을 만들어보자!
'프로그래밍 공부' 카테고리의 다른 글
| MVVM(Model-View-ViewModel) 패턴 제대로 이해하기 (0) | 2025.03.07 |
|---|---|
| iOS 개발에서 의존성 주입(Dependency Injection, DI)이 중요한 이유 (0) | 2025.03.06 |
| ARC(Automatic Reference Counting) – Swift는 어떻게 메모리를 관리할까? (1) | 2025.02.20 |
| Swift – iOS 개발자가 알아야 할 모든 것 (2) | 2025.02.19 |
| 객체 지향 설계의 SOLID 원칙 – 제대로 알고 써보자! (0) | 2025.02.18 |