안녕하세요 Niro 🚗 입니다!
Treehouse 라는 앱을 SwiftUI 로 개발하고 있고 개발 과정 중 Observation 프레임워크를 채택한 이유에 대해서 경험을 나누면 좋겠다는 생각을 했습니다.
개발적인 내용도 있지만 도입 과정 중 당시의 상황과 고민, 해결방안에 초점을 맞춘 글이 되지 않을까 싶습니다!
정의나 문법 등 다른 정보가 필요하시다면 정리가 잘되어있는 다른 글을 읽고 오시면 더욱 좋을거 같습니다!
프레임워크를 선택할 때 가장 중요한 질문은 '타당한 근거가 있냐?' 입니다.
많은 개발자들이 이 질문에 직면했을 때 다음과 같은 답변을 하곤 합니다
"많이 사용하니까요."
"취업에 도움이 될거 같아서요!"
"나 이만큼 할줄 알아요를 나타내는 기준이잖아요!"
하지만 이러한 피상적인 접근은 장기적으로 문제를 야기한다 생각합니다.
제 경험상 이런 고민에 앞서서 어떤 가치관을 갖고 있는지, 그 가치관을 통해 결정이 흔들리지 않고 견고하고 정확한 판단으로 이어지고 더 빠르고 정확한 의사결정을 가능하게 합니다.
뭐든지 일을 할때 가장 중요한 것이 투입한 자본 대비 얼마나 더 효율적으로 만들었냐가 가장 중요하죠!
그래서 프레임워크를 선정하는 것에 있어 제가 생각하는 가장 중요한 가치를 만들어보았습니다.
개발 편의성 - 고민을 줄이고 얼마나 더 편하게 개발을 할 수 있나?
부작용 최소화 - Side Effect 을 얼마나 줄일 수 있나?
학습 용이성 - 다른 팀원들이 쉽게 습득하고 활용할 수 있는가?
학습 용이성의 경우 전문적인 개발자가 되기 위해선 미리 새로운 프레임워크를 익혀야한다고 생각합니다. 언젠가 도입 논의에서 장단점을 명확하게 제시할 수 있게하며 실무 적용에 신속한 대응을 가능하게 하죠!
다만 지금 실무가 아닌 개발자가 되기 위해 노력하는 학생으로 관점을 바꾸어 상단한 간극이 존재합니다.
학업과 병행하며 온전히 프로젝트에 시간을 쏟기 힘든 상황이고 개발을 한다는 것은 혼자가 아닌 팀단위로 움직여야 하고 모두가 잘 참여할 수 있도록 환경을 만들어야 한다는 것입니다.
위와 같은 고민을 통해 우리 팀에선 다음과 같은 가치를 중심으로 프레임워크를 선정하게 되었습니다!
"우리의 상황에 가장 적합하고, 모두가 끝까지 즐겁게 참여할 수 있으며, 각자에게 의미 있는 경험을 제공할 수 있는 선택"
그것이 바로 Observation
프레임워크 였고 어떤 이점이 존재했는지 적어보기 전에 일단 왜 나오게 됐는지 기존에 어떤 문제점이 있는지 알아보겠습니다.
SwiftUI 를 MVVM 패턴으로 사용하면서 자주 직면하는 고민이 있습니다.
ViewModel 을
@StateObject
로 선언해야 돼..? ,@ObservedObject
로 선언해야돼..?
어떤 차이가 있고 어떤 Side Effect 가 발생할까..?
라는 고민을 많이 해보셨을겁니다.
단순하게 생각할 수 있지만 두 차이점과 적절한 사용법을 알지 못하면 앱의 성능과 사용자 경험에 가장 큰 영향을 미치는 주요한 부작용이 발생합니다.
두 프로퍼티 래퍼에 대한 설명을 자세히 설명하기 보다 문제점에 초점을 맞춰보겠습니다.
SwiftUI 의 가장 큰 장점은 데이터가 변하면 알아서 View 가 다시 그려져 개발자가 직접 관리를 하지 않아도 된다는 장점이 있습니다.
다만 View 가 업데이트 될 때 @ObservedObject
로 선언된 객체도 같이 초기화 되면서 값이 변한거 같지만.. 초기 값으로 되돌아 가는 문제점이 발생합니다..
또한 가장 중요한 단점 중 하나는 ObservableObject
내의 @Published
프로퍼티 중 View 에서 직접적으로 사용하지 않더라도 프로퍼티가 바뀌면 View 가 재생성되는 문제도 존재합니다.
그래서 iOS 14 이상에서는 @ObservedObject
가 아닌 @StateObject
를 사용하여 이 문제를 해결하게 됩니다.
@StateObject
의 경우 View 자체가 아닌 SwiftUI 프레임 워크 내부의 별도 저장소에 객체를 저장하게 되고
고유한 식별자를 갖고 있어 SwiftUI 는 이 식별자를 통해 객체를 추적하고 관리하여 View 가 재생성되더라도 기존 객체가 존재하면 재사용하게 되는 것이죠!
물론 View 가 완전히 제거된다면 연관된 @StateObject
도 함께 제거가 됩니다.
이러한
@StateObject
의 매커니즘으로 인해 View 생명주기동안 안정적으로 객체를 유지하며@ObservedObject
의 재초기화 문제를 효과적으로 해결을 했습니다.
결론적으로 @StateObject
와 @ObservedObject
는 SwiftUI 에서 상태관리를 위해 필요하지만 각 특성을 정확히 알아야 하고 잠재적인 부작용을 이해하고 사용하는 것이 중요합니다.
하지만.. 이러한 문제점들은 개발자가 @StateObject
와 @ObservedObject
를 얼마나 잘 이해하고 있는지, 얼마나 신중하게 사용하는지와 관계없이 발생할 수 있습니다. 사람은 실수를 할 수 있고 복잡한 대규모 앱에서는 이러한 문제를 완벽히 예방하는 것이 거의 불가능에 가깝다고 생각합니다.
우리는 사람인지라 아무리 정확히 알고 있어도 실수를 하게 되고 이 둘을 정확하게 사용하기 위해 많은 고민을 하는 것이 과연 우리에게 더 나은 결과물을 제공할까요?
Observation 프레임워크는 개발 편의성 측면에서 큰 이점을 제공하게 됩니다.
Observation 프레임워크를 사용하면 상태 관리 코드가 놀랍도록 간결해집니다. 더 이상ObservableObject
프로토콜을 채택하거나 각 프로퍼티에 @Published
를 붙일 필요가 없습니다. 단순히 클래스에 @Observable
매크로만 추가하면 됩니다.
// 이전 방식
// 모든 관찰 가능한 프로퍼티에 @Published를 붙여야 합니다.
// @Published를 추가하지 않으면 해당 프로퍼티의 변경사항이 View에 반영되지 않습니다.
class UserViewModel: ObservableObject { // ObservableObject 프로토콜을 채택
@Published ar name: String = "Niro"
@Published var age: Int = 28
}
// Observation 방식
@Observable
class UserViewModel {
// @Observable이 모든 프로퍼티를 자동으로 관찰합니다.
var name: String = "Niro"
var age: Int = 28
}
단순히 클래스에 @Observable
매크로만 추가하면 모든 프로퍼티가 자동으로 관찰 대상이 됩니다. 코드를 더 간결하고 일관되게 만들어 실수를 줄일 수 있다고 생각합니다!
이런 간소화는 특히 큰 ViewModel 을 다룰 때 프로퍼티가 많아질수록 @Published
를 빼먹는 상황을 방지할 수 있어 코드의 안정성과 유지보수성이 크게 향상됩니다.
당연하다고 생각하지만 코드를 작성할 때 이런 작은 부분들이 효율성을 증가시키는 요인이라 생각합니다!
우리가 생각지도 못한 Side Effect 를 얼마나 줄일 수 있나에 대해 알아보겠습니다.
Observation 프레임워크의 가장 큰 장점 중 하나는 불필요한 View 업데이트를 효과적으로 방지한다는 것입니다. 이전의 @Published
및 ObservableObject
방식과 비교하여 큰 개선이 이루어졌습니다.
기존에는 @Published
프로퍼티가 변경되면 해당 ObservableObject
를 사용하는 모든 뷰가 redraw 되는 문제가 있었죠 ㅠㅠㅠㅠ
즉, 변경된 프로퍼티를 직접 사용하지 않는 View 도 불필요한 업데이트 결과를 초래하게 됩니다..
예시를 보겠습니다!
// 기존 방식
class UserViewModel: ObservableObject {
@Published var name: String = "Niro"
@Published var age: Int = 28
}
struct UserView: View {
@ObservedObject var viewModel: UserViewModel
var body: some View {
VStack {
Text(viewModel.name)
// age가 변경되면 Text는 불필요하게 업데이트됨
}
}
}
// Observation 방식
@Observable class UserViewModel {
var name: String = "Niro"
var age: Int = 28
}
struct UserView: View {
@State private var viewModel = UserViewModel()
var body: some View {
VStack {
Text(viewModel.name)
// age가 변경되어도 Text는 업데이트되지 않음
}
}
}
코드만 봐도 양이 줄어든게 너무나 좋은거 같습니다..
일단 Observation 방식에서는 name
프로퍼티만 실제로 사용되므로, age
가 변경되어도 View 는 업데이트되지 않습니다.
우리가 개발을 하면서 해당 프로퍼티가 View 와 의존성이 있는지~
값이 바뀌면 View 도 업데이트가 되어야 하는 역할인건지~
단순히 값만 갖고 다른 프로퍼티와 연관되어있는지~
어려운 고민을 하지 않고 Observation 에게 넘기게 되는 것입니다!
물론, 좋은 개발자가 되려면 끊임없는 고민과 생각을 해야하고 동시에 효율적으로 개발을 할 수있어야 하기 때문에 SwiftUI 로 iOS 17 이상 프로젝트를 한다면 Observation 은 필수 선택일거 같습니다.
앞서 많은 코드들을 보셨겠지만 굉장히 직관적이고 간단하게 만들어서 팀 내에서 쉽게 습득 할 수 있습니다
기존 ObservableObject 으로 사용했던 패턴과 크게 다르지 않기 때문에 SwiftUI 를 써본 분들은 쉽게 전환할 수 있으며 SwiftUI 를 처음접하는 분들에게도 Side Effect 를 최소화 시키면서 상태관리를 명확하게 할 수 있게 됩니다.
앞서 말씀드렸던 Side Effect 부분에 대한 고민을 단번에 해결할 수 있다는 것이 가장 큰 장점이 아닐까 생각됩니다.
이제 정리를 해보겠습니다.
SwiftUI 프로젝트에 Observation 을 선택하게 되면서 다음과 같은 큰 장점을 얻을 수 있었습니다!
- 불필요한 View 업데이트가 줄어들어 앱 성능이 개선
- 상태 변경 시 어떤 View 에 영향을 미칠지 명확하게 예측
- 기존 패턴과 유사하여 러닝 커브가 낮음
- 일관된 코드 패턴으로 품질개선 및 생산성 향상
결과적으로 Observation 프레임워크는 개발자의 고민을 크게 줄이고 더 짧고 동일한 패턴으로 효율적인 개발 경험을 제공할 수 있게 됩니다.
기존에 이미 출시된 서비스라면 하위 버전을 iOS 17 로 맞춰야 사용가능하다는 큰 단점이 존재하지만 새롭게 만들거나 최소버전을 iOS 17 로 맞춘다면 Observation 이 가장 좋은 선택인거 같습니다!
앞서 보신 것처럼 어떤 프레임워크, 라이브러리를 선택할 때 단순히 좋고, 많이 사용해서 라는 이유보다 얼마나 더 편한지, 어떤 부작용을 최소화 할수 있는지, 팀원들이 배우기 어렵지는 않은지 3가지 핵심 가치를 통해 선택을 해보았습니다.
어떤 서비스를 통해 수익화가 목적이라면 또 다른 기준을 선택하겠지만 현재 프로젝트 상황에 맞게 고려했고 이런 경험은 앞으로 개발자로서 선택의 갈림길에 존재했을때 도움이되는 경험이지 않았을까 생각합니다.
글이 길어지다보니 두서 없이 적게된거 같은데 저와 같은 고민을 하거나 경험이 있으신 분들이 계시다면 토론의 장이 되면 더욱 좋을거 같습니다.
또는 Observation 을 사용해야하나? 라는 고민이 있으신 분들에게 도움이 되는 글이였으면 좋겠네요!
긴 글 읽어주셔서 감사하고 앞으로 더 좋은 글 작성하도록 하겠습니다!