이번 프로젝트는 RxSwift를 처음으로 적용한 프로젝트였다. 처음에는 익숙하지 않은 문법과 개념으로 개발하는데 어려움이 있었지만, 조금씩 익숙해지면서 프로젝트를 마무리 할 수 있었다.
Book2OnNon를 개발하게 된 이유
Book2OnNon를 개발하게 된 이유는 RxSwift를 공부하면서 개념적인 부분은 이해했지만 실전에서의 활용 방법에 대한 어려움이 있었기 때문에, 실제 프로젝트에서의 적용 경험이 필요했다. 이를 위해 이번 프로젝트를 시작하게 되었다.
앱 소개
📆 개발 기간
24.03.11 ~ 24.05.16
⚽️ 목표
1. RxSwift와 친해지기
➡️ 프로젝트를 통해 RxSwift를 이해하고 익숙해지기.
2. 연산자 이해하기
➡️ RxSwift에는 정말 많은 연산자가 있다. 직접 사용해보면서 이해하기.
3. RxSwift + MVVM 패턴 구현하기
➡️ RxSwift로 MVVM 패턴을 구현해보면서 MVVM 패턴에 대해 다시 한번 생각해보기.
4. CoreData
➡️ 이번 프로젝트에서는 Realm이 아닌 CoreData를 사용해보기.
5. 겁먹지말기
➡️ RxSwift를 처음 적용하는 프로젝트인 만큼, 정답'만'을 찾으려하지 말고 틀려도 되니까 과감하게 코드 써내려가기.
✅ 적용 기술
RxSwift, RxCocoa, MVVM Pattern, Delegate Pattern, Singleton Pattern,Snapkit, Alamofire, CoreData, Kingfisher, Cosmos
⚙️ 기능
1. 알라딘 API를 바탕으로 책 검색 기능 제공
2. 다 읽은 책, 관심 있는 책, 읽고 있는 책에 대한 기록을 작성할 수 있는 기능 제공
3. 내 기록을 한번에 모아볼 수 있는 모아보기 기능 제공
🎥 시연 영상
https://youtu.be/61v7EJvqf5E?si=TNJl6SssJUr7nCDF
기술적 성장
1. 언제 어떤 연산자를 사용해야하는지 ?
RxSwift에는 많은 연산자가 있다. just, create, map, filter와 같은 몇 가지 기본적인 연산자만 알고 있었다. 그러나 실제 프로젝트를 진행하면서 다양한 문제에 부딪히게 되었다.

특히 검색 이벤트 처리와 네트워크 요청과 같은 복잡한 상황에서는 더 많은 연산자가 필요했다. 이러한 문제들을 해결하기 위해 RxSwift의 다양한 연산자에 대해 간단한 예제를 만들어 가며 학습했고 실제 프로젝트에 적용해보았다. 처음에는 어렵게 느껴지던 연산자들도 프로젝트를 진행하면서 익숙해지고, 각각의 사용 용도를 파악할 수 있었다. 이러한 경험을 통해 언제 어떤 연산자를 사용해야 하는지에 대해 더 잘 이해할 수 있었다.
✅ 내가 생각하는 자주 쓰이는 연산자
filter, map, flatMap, withLatestFrom, combineLatest
2. flatMap이 도대체 뭐야 ?

flatMap 연산자를 이해하는 데 어려움이 있었다. Marble 다이어 그램을 보면서 각 단계의 데이터 흐름을 파악하는 것이 쉽지 않았고, 이는 학습하는데 어려움을 느꼈다. 처음에는 연산자의 동작 방식과 사용법을 완전히 이해하기 어려웠다. 하지만 다양한 예제와 문서를 참고하여 조금씩 익숙해졌다.
import RxSwift
let disposeBag = DisposeBag()
let numbersObservable = Observable.of(1, 2, 3, 4, 5)
numbersObservable
.flatMap { number in
return Observable.just(number * 2)
}
.subscribe(onNext: { doubledNumber in
print(doubledNumber)
})
.disposed(by: disposeBag)
flatMap을 이해하기 위해 작성한 간단한 예제코드이다. 1부터 5까지 숫자를 방출하는 Observable을 생성한 후, 각 숫자를 2배로 만들어 새로운 Observable로 변환한다. 그리고 변환된 Observable을 구독하여 각 숫자를 출력한다.

보통 flatMap은 네트워크 요청이나 DB 쿼리와 같은 비동기 작업을 수행한다. 이러한 작업은 Observable 형태로 비동기적으로 결과를 반환하게 된다. 그런데 만약 여러 개의 비동기 작업을 연달아 수행해야 한다면, 각각의 작업을 순차적으로 실행하기보다는 병렬로 실행하고 그 결과를 조합하는 것이 효율적일 것이다.
이때, flatMap을 사용하면, 각각의 비동기 작업을 Observable로 매핑하여 병렬로 실행할 수 있다. 그리고 flatMap은 내부 Observable들의 결과를 하나의 Observable로 합쳐서 반환하기 때문에, 최종 결과를 쉽게 다룰 수 있다.
3. Single
Single은 RxSwift에서 네트워크 요청과 같은 비동기 작업을 처리하기 위한 Observable의 한 유형이다. Single을 사용하는 이유는 단일 결과를 반환하기 때문이다. Single은 하나의 결과 또는 오류를 방출할 수 있기 때문에 네트워크 요청과 같은 작업에서 한 번의 성공 또는 실패를 기대할 때 사용된다. 또, 성공 또는 실패 둘 중 하나의 결과를 방출하므로, 오류처리가 명확하다.

위 코드는 네트워크 요청을 통해 책 검색 데이터를 가져오는 메소드를 정의한 것이다. 이 메소드는 Single을 반환하며, 결과로는 Result<Book, Error>를 내보낸다. 이 결과는 성공 시 책 데이터를 담고 있는 Book 객체를, 실패 시 에러를 포함한다. 이렇게 구성 된 메소드는 Single을 사용하여 네트워크 요청을 수행하고, 결과를 방출한다. 결과로는 성공 또는 실패가 포함된 Result 객체를 반환한다.
4. 의존성 주입
MVVM은 의존성 역전 원칙을 따른다. 즉, View가 Model이나 ViewModel에 직접 의존하지 않고 외부에서 의존성을 주입받아야 한다.

MyLibraryViewController의 생성자를 통해 ViewModel을 주입했다.
private let viewModel: MyLibraryViewModelType
init(viewModel: MyLibraryViewModelType = MyLibraryViewModel()) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
간단하게 코드를 분석해보면, viewModel은 MyLibraryViewModelType 프로토콜을 준수하는 타입이다. 이는 추상화를 통해 구체적인 ViewModel 타입에 의존하지 않고, 인터페이스에만 의존한다. init 메소드에서 ViewModel을 매개변수로 받는다. viewModel 매개변수에는 기본값이 설정되어 있다. 이는 외부에서 매개변수를 전달하지 않으면 자동으로 MyLibraryViewModel이 사용됨을 의미한다. 이 코드를 통해 ViewController는 ViewModel을 외부에서 주입받을 수 있다.

ViewModel을 프로토콜로 정의하여 구현했다. ViewModel을 사용하는 다른 객체들이 ViewModel의 구체적인 구현이 아니라 프로토콜을 통해 의존하게 되는데, 이는 객체 간의 결합도를 낮추고 의존성 역전을 일으켜 유연하고 확장 가능한 코드를 작성하는데 도움이 된다.

실제로 ViewController에서 ViewModel의 Output 값에 접근할 때, ViewModel의 구체적인 변수 outputFinishedReadingBookRecordItem가 아닌 프로토콜 프로퍼티인 finishedReadingBookRecordItem에 접근하여 바인딩 한다.
내 생각
1. RxSwift는 비동기 처리를 할 때 강력한 무기이다.
RxSwift는 비동기 작업을 쉽게 처리할 수 있다. Observable을 사용하여 비동기 이벤트 스트림을 생성하고, 이에 대한 처리를 간단한 연산자를 사용하여 수행할 수 있다. 예를들어, 네트워크 요청으로 Observable를 반환 받으면 요청의 결과를 Subscrbie하여 효과적으로 처리할 수 있다. 또, 다양한 연산자를 제공하기 때문에 비동기 작업의 흐름을 유연하고 효율적으로 제어할 수 있다.
func fetchData() -> Single<Data> {
return Single<Data>.create { single in
URLSession.shared.dataTask(with: URL(string: "https://seongil.com")!) { (data, response, error) in
if let error = error {
single(.error(error))
} else if let data = data {
single(.success(data))
}
}.resume()
return Disposables.create()
}
}
func formatString() -> Single<String> {
return fetchData()
.map { data in
if let jsonString = String(data: data, encoding: .utf8) {
return jsonString
} else {
throw NSError(domain: "DataError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to convert data to string"])
}
}
.flatMap { jsonString in
return Single<String>.just("String으로 변환되었습니다. : \(jsonString)")
}
}
이 예제에서는 fetchData()를 호출하여 네트워크 요청을 보내고 받아온 데이터를 처리하는데, map 연산자를 이용하여 String으로 변환한다. 그리고 flatMap 연산자를 사용하여 처리된 데이터를 가지고 추가적인 작업을 수행한다. 이처럼 다양한 연산자를 사용하여 비동기 작업의 흐름을 유연하고 효율적으로 제어할 수 있다.
2. RxSwift와 MVVM의 조합은 최고다.
RxSwift로 MVVM을 구현하면 ViewModel과 View 사이의 양방향 데이터 바인딩을 쉽게 구현할 수 있다. ViewModel에서 발생하는 변경 사항은 Observable로 View로 전달되고, View에서 사용자 이벤트가 발생하면 ViewModel로 전달된다. 이를 통해 복잡한 데이터 흐름 문제를 해결할 수 있다. 뿐만 아니라, 상태관리가 용이해진다. ViewModel은 데이터 스트림을 사용하여 앱의 상태를 표현하고, 이를 통해 View의 상태를 업데이트 할 수 있다. 상태 관리를 효과적으로 수행함으로써 앱의 복잡성을 줄이고 유지보수성을 높일 수 있다.

View에서 saveButton을 Tap하는 이벤트가 발생하면 ViewModel로 전달한다. ViewModel에서 recordData의 변경 사항이 발생하면 Observable로 View에 전달 된다. ViewModel이 recordData를 관리하고, ViewController가 해당 데이터를 표시하는 역할을 한다. 이로써 ViewController는 사용자 입력 및 상태 변경에 대한 응답을 단순히 처리하고, 비즈니스 로직은 ViewModel이 담당한다.
3. 여전히 변수명, 함수명 짓는건 어렵다.
함수명과 변수명을 짓는 것은 여전히 어렵다. 코드를 작성할 때 가장 많은 시간을 소비하는 부분 중 하나는 적절한 이름을 선택하는 것이다. 이름 짓기는 협업이나 코드의 가독성과 유지보수에 직접적인 영향을 미치기 때문에 신중하게 지어야한다.
이름 짓기란 왜이리 어려운건지 😥.. 좋은 이름을 지어주기 위해 다른 코드를 많이 참고하고, 자주 사용되는 용어를 학습하는 등 노력은 하고 있지만 좀처럼 쉽게 지어지지 않는다. 노력이 부족한 것이겠지 ! 더 열심히 해서 더 좋은 이름을 지어줘야겠다.
4. ViewController에 생성해야하는 UI가 많으면 어떻게 처리해야할까?
VC에 생성해야하는 UI 요소가 많으면 어떻게 처리해야할까?
나는 섹션별로 UIView를 만들어서 구현하고, 해당 View를 ViewController에 추가하여 사용하는 방법을 선택했다.
이유는 간단하다. 가독성이 좋아지고 유지보수하기 쉽기 때문이다.
프로그래밍에는 어떻게 하는게 '정답'이다 라는 것은 없기 때문에 ! !
프로젝트의 방향성에 맞게 개발하면 되는데 .. 팀 프로젝트 경험이 부족하기 때문에 이런 부분에 있어서 정말로 고민이 많다 .. !
마무리
이번 프로젝트는 약 두 달의 시간을 투자하여 완성했다. 비록 결과물이 간단한 앱이지만, RxSwift를 깊이 있게 공부하고 적용해볼 수 있었던 소중한 경험이었다. 많은 고민과 노력을 통해 개발했기 때문에 개발 기간이 오래 걸렸지만, 이 과정에서 많은 것을 배우고 성장할 수 있었다.
프로젝트를 진행하면서 복사 붙여넣기 식이 아닌 직접적인 이해와 예제 코드를 만들어보며 공부하고 프로젝트에 적용하는 방식으로 접근했다. 이러한 노력 덕분에 프로젝트가 끝난 지금 이 시점에서 많이 성장했음을 느꼈다.
앞으로의 목표는 이제 진정한 의미의 프로젝트를 만드는 것이다. 지금까지의 학습과 경험을 기반으로 실제로 유용하고 완성도 있는 개인 프로젝트를 구상하고 구현해보려고 한다.
'ToyProject - Book2OnNon (모바일 서재)' 카테고리의 다른 글
[Book2onNon] 하위 View에 상위 ViewController의 ViewModel 주입하기 (0) | 2024.03.26 |
---|---|
[Book2onNon] 무한 스크롤을 구현하고 스크롤링 이벤트 발생 시 새로운 데이터를 요청해보는 것을 구현해보자. (1) | 2024.03.16 |
이번 프로젝트는 RxSwift를 처음으로 적용한 프로젝트였다. 처음에는 익숙하지 않은 문법과 개념으로 개발하는데 어려움이 있었지만, 조금씩 익숙해지면서 프로젝트를 마무리 할 수 있었다.
Book2OnNon를 개발하게 된 이유
Book2OnNon를 개발하게 된 이유는 RxSwift를 공부하면서 개념적인 부분은 이해했지만 실전에서의 활용 방법에 대한 어려움이 있었기 때문에, 실제 프로젝트에서의 적용 경험이 필요했다. 이를 위해 이번 프로젝트를 시작하게 되었다.
앱 소개
📆 개발 기간
24.03.11 ~ 24.05.16
⚽️ 목표
1. RxSwift와 친해지기
➡️ 프로젝트를 통해 RxSwift를 이해하고 익숙해지기.
2. 연산자 이해하기
➡️ RxSwift에는 정말 많은 연산자가 있다. 직접 사용해보면서 이해하기.
3. RxSwift + MVVM 패턴 구현하기
➡️ RxSwift로 MVVM 패턴을 구현해보면서 MVVM 패턴에 대해 다시 한번 생각해보기.
4. CoreData
➡️ 이번 프로젝트에서는 Realm이 아닌 CoreData를 사용해보기.
5. 겁먹지말기
➡️ RxSwift를 처음 적용하는 프로젝트인 만큼, 정답'만'을 찾으려하지 말고 틀려도 되니까 과감하게 코드 써내려가기.
✅ 적용 기술
RxSwift, RxCocoa, MVVM Pattern, Delegate Pattern, Singleton Pattern,Snapkit, Alamofire, CoreData, Kingfisher, Cosmos
⚙️ 기능
1. 알라딘 API를 바탕으로 책 검색 기능 제공
2. 다 읽은 책, 관심 있는 책, 읽고 있는 책에 대한 기록을 작성할 수 있는 기능 제공
3. 내 기록을 한번에 모아볼 수 있는 모아보기 기능 제공
🎥 시연 영상
https://youtu.be/61v7EJvqf5E?si=TNJl6SssJUr7nCDF
기술적 성장
1. 언제 어떤 연산자를 사용해야하는지 ?
RxSwift에는 많은 연산자가 있다. just, create, map, filter와 같은 몇 가지 기본적인 연산자만 알고 있었다. 그러나 실제 프로젝트를 진행하면서 다양한 문제에 부딪히게 되었다.

특히 검색 이벤트 처리와 네트워크 요청과 같은 복잡한 상황에서는 더 많은 연산자가 필요했다. 이러한 문제들을 해결하기 위해 RxSwift의 다양한 연산자에 대해 간단한 예제를 만들어 가며 학습했고 실제 프로젝트에 적용해보았다. 처음에는 어렵게 느껴지던 연산자들도 프로젝트를 진행하면서 익숙해지고, 각각의 사용 용도를 파악할 수 있었다. 이러한 경험을 통해 언제 어떤 연산자를 사용해야 하는지에 대해 더 잘 이해할 수 있었다.
✅ 내가 생각하는 자주 쓰이는 연산자
filter, map, flatMap, withLatestFrom, combineLatest
2. flatMap이 도대체 뭐야 ?

flatMap 연산자를 이해하는 데 어려움이 있었다. Marble 다이어 그램을 보면서 각 단계의 데이터 흐름을 파악하는 것이 쉽지 않았고, 이는 학습하는데 어려움을 느꼈다. 처음에는 연산자의 동작 방식과 사용법을 완전히 이해하기 어려웠다. 하지만 다양한 예제와 문서를 참고하여 조금씩 익숙해졌다.
import RxSwift
let disposeBag = DisposeBag()
let numbersObservable = Observable.of(1, 2, 3, 4, 5)
numbersObservable
.flatMap { number in
return Observable.just(number * 2)
}
.subscribe(onNext: { doubledNumber in
print(doubledNumber)
})
.disposed(by: disposeBag)
flatMap을 이해하기 위해 작성한 간단한 예제코드이다. 1부터 5까지 숫자를 방출하는 Observable을 생성한 후, 각 숫자를 2배로 만들어 새로운 Observable로 변환한다. 그리고 변환된 Observable을 구독하여 각 숫자를 출력한다.

보통 flatMap은 네트워크 요청이나 DB 쿼리와 같은 비동기 작업을 수행한다. 이러한 작업은 Observable 형태로 비동기적으로 결과를 반환하게 된다. 그런데 만약 여러 개의 비동기 작업을 연달아 수행해야 한다면, 각각의 작업을 순차적으로 실행하기보다는 병렬로 실행하고 그 결과를 조합하는 것이 효율적일 것이다.
이때, flatMap을 사용하면, 각각의 비동기 작업을 Observable로 매핑하여 병렬로 실행할 수 있다. 그리고 flatMap은 내부 Observable들의 결과를 하나의 Observable로 합쳐서 반환하기 때문에, 최종 결과를 쉽게 다룰 수 있다.
3. Single
Single은 RxSwift에서 네트워크 요청과 같은 비동기 작업을 처리하기 위한 Observable의 한 유형이다. Single을 사용하는 이유는 단일 결과를 반환하기 때문이다. Single은 하나의 결과 또는 오류를 방출할 수 있기 때문에 네트워크 요청과 같은 작업에서 한 번의 성공 또는 실패를 기대할 때 사용된다. 또, 성공 또는 실패 둘 중 하나의 결과를 방출하므로, 오류처리가 명확하다.

위 코드는 네트워크 요청을 통해 책 검색 데이터를 가져오는 메소드를 정의한 것이다. 이 메소드는 Single을 반환하며, 결과로는 Result<Book, Error>를 내보낸다. 이 결과는 성공 시 책 데이터를 담고 있는 Book 객체를, 실패 시 에러를 포함한다. 이렇게 구성 된 메소드는 Single을 사용하여 네트워크 요청을 수행하고, 결과를 방출한다. 결과로는 성공 또는 실패가 포함된 Result 객체를 반환한다.
4. 의존성 주입
MVVM은 의존성 역전 원칙을 따른다. 즉, View가 Model이나 ViewModel에 직접 의존하지 않고 외부에서 의존성을 주입받아야 한다.

MyLibraryViewController의 생성자를 통해 ViewModel을 주입했다.
private let viewModel: MyLibraryViewModelType
init(viewModel: MyLibraryViewModelType = MyLibraryViewModel()) {
self.viewModel = viewModel
super.init(nibName: nil, bundle: nil)
}
간단하게 코드를 분석해보면, viewModel은 MyLibraryViewModelType 프로토콜을 준수하는 타입이다. 이는 추상화를 통해 구체적인 ViewModel 타입에 의존하지 않고, 인터페이스에만 의존한다. init 메소드에서 ViewModel을 매개변수로 받는다. viewModel 매개변수에는 기본값이 설정되어 있다. 이는 외부에서 매개변수를 전달하지 않으면 자동으로 MyLibraryViewModel이 사용됨을 의미한다. 이 코드를 통해 ViewController는 ViewModel을 외부에서 주입받을 수 있다.

ViewModel을 프로토콜로 정의하여 구현했다. ViewModel을 사용하는 다른 객체들이 ViewModel의 구체적인 구현이 아니라 프로토콜을 통해 의존하게 되는데, 이는 객체 간의 결합도를 낮추고 의존성 역전을 일으켜 유연하고 확장 가능한 코드를 작성하는데 도움이 된다.

실제로 ViewController에서 ViewModel의 Output 값에 접근할 때, ViewModel의 구체적인 변수 outputFinishedReadingBookRecordItem가 아닌 프로토콜 프로퍼티인 finishedReadingBookRecordItem에 접근하여 바인딩 한다.
내 생각
1. RxSwift는 비동기 처리를 할 때 강력한 무기이다.
RxSwift는 비동기 작업을 쉽게 처리할 수 있다. Observable을 사용하여 비동기 이벤트 스트림을 생성하고, 이에 대한 처리를 간단한 연산자를 사용하여 수행할 수 있다. 예를들어, 네트워크 요청으로 Observable를 반환 받으면 요청의 결과를 Subscrbie하여 효과적으로 처리할 수 있다. 또, 다양한 연산자를 제공하기 때문에 비동기 작업의 흐름을 유연하고 효율적으로 제어할 수 있다.
func fetchData() -> Single<Data> {
return Single<Data>.create { single in
URLSession.shared.dataTask(with: URL(string: "https://seongil.com")!) { (data, response, error) in
if let error = error {
single(.error(error))
} else if let data = data {
single(.success(data))
}
}.resume()
return Disposables.create()
}
}
func formatString() -> Single<String> {
return fetchData()
.map { data in
if let jsonString = String(data: data, encoding: .utf8) {
return jsonString
} else {
throw NSError(domain: "DataError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to convert data to string"])
}
}
.flatMap { jsonString in
return Single<String>.just("String으로 변환되었습니다. : \(jsonString)")
}
}
이 예제에서는 fetchData()를 호출하여 네트워크 요청을 보내고 받아온 데이터를 처리하는데, map 연산자를 이용하여 String으로 변환한다. 그리고 flatMap 연산자를 사용하여 처리된 데이터를 가지고 추가적인 작업을 수행한다. 이처럼 다양한 연산자를 사용하여 비동기 작업의 흐름을 유연하고 효율적으로 제어할 수 있다.
2. RxSwift와 MVVM의 조합은 최고다.
RxSwift로 MVVM을 구현하면 ViewModel과 View 사이의 양방향 데이터 바인딩을 쉽게 구현할 수 있다. ViewModel에서 발생하는 변경 사항은 Observable로 View로 전달되고, View에서 사용자 이벤트가 발생하면 ViewModel로 전달된다. 이를 통해 복잡한 데이터 흐름 문제를 해결할 수 있다. 뿐만 아니라, 상태관리가 용이해진다. ViewModel은 데이터 스트림을 사용하여 앱의 상태를 표현하고, 이를 통해 View의 상태를 업데이트 할 수 있다. 상태 관리를 효과적으로 수행함으로써 앱의 복잡성을 줄이고 유지보수성을 높일 수 있다.

View에서 saveButton을 Tap하는 이벤트가 발생하면 ViewModel로 전달한다. ViewModel에서 recordData의 변경 사항이 발생하면 Observable로 View에 전달 된다. ViewModel이 recordData를 관리하고, ViewController가 해당 데이터를 표시하는 역할을 한다. 이로써 ViewController는 사용자 입력 및 상태 변경에 대한 응답을 단순히 처리하고, 비즈니스 로직은 ViewModel이 담당한다.
3. 여전히 변수명, 함수명 짓는건 어렵다.
함수명과 변수명을 짓는 것은 여전히 어렵다. 코드를 작성할 때 가장 많은 시간을 소비하는 부분 중 하나는 적절한 이름을 선택하는 것이다. 이름 짓기는 협업이나 코드의 가독성과 유지보수에 직접적인 영향을 미치기 때문에 신중하게 지어야한다.
이름 짓기란 왜이리 어려운건지 😥.. 좋은 이름을 지어주기 위해 다른 코드를 많이 참고하고, 자주 사용되는 용어를 학습하는 등 노력은 하고 있지만 좀처럼 쉽게 지어지지 않는다. 노력이 부족한 것이겠지 ! 더 열심히 해서 더 좋은 이름을 지어줘야겠다.
4. ViewController에 생성해야하는 UI가 많으면 어떻게 처리해야할까?
VC에 생성해야하는 UI 요소가 많으면 어떻게 처리해야할까?
나는 섹션별로 UIView를 만들어서 구현하고, 해당 View를 ViewController에 추가하여 사용하는 방법을 선택했다.
이유는 간단하다. 가독성이 좋아지고 유지보수하기 쉽기 때문이다.
프로그래밍에는 어떻게 하는게 '정답'이다 라는 것은 없기 때문에 ! !
프로젝트의 방향성에 맞게 개발하면 되는데 .. 팀 프로젝트 경험이 부족하기 때문에 이런 부분에 있어서 정말로 고민이 많다 .. !
마무리
이번 프로젝트는 약 두 달의 시간을 투자하여 완성했다. 비록 결과물이 간단한 앱이지만, RxSwift를 깊이 있게 공부하고 적용해볼 수 있었던 소중한 경험이었다. 많은 고민과 노력을 통해 개발했기 때문에 개발 기간이 오래 걸렸지만, 이 과정에서 많은 것을 배우고 성장할 수 있었다.
프로젝트를 진행하면서 복사 붙여넣기 식이 아닌 직접적인 이해와 예제 코드를 만들어보며 공부하고 프로젝트에 적용하는 방식으로 접근했다. 이러한 노력 덕분에 프로젝트가 끝난 지금 이 시점에서 많이 성장했음을 느꼈다.
앞으로의 목표는 이제 진정한 의미의 프로젝트를 만드는 것이다. 지금까지의 학습과 경험을 기반으로 실제로 유용하고 완성도 있는 개인 프로젝트를 구상하고 구현해보려고 한다.
'ToyProject - Book2OnNon (모바일 서재)' 카테고리의 다른 글
[Book2onNon] 하위 View에 상위 ViewController의 ViewModel 주입하기 (0) | 2024.03.26 |
---|---|
[Book2onNon] 무한 스크롤을 구현하고 스크롤링 이벤트 발생 시 새로운 데이터를 요청해보는 것을 구현해보자. (1) | 2024.03.16 |