swift/swift 공부

[RxSwift, MVVM, Clean Architecture] 프로젝트에 viewmodel의 input, output을 적용하면서 느낀점들

isak(이삭) 2024. 2. 16. 22:42

( 작은 단위에 제한된 느낀점들임 )


우선 위에서 빨갛게 해놓은 작은 단위에 대한 설명부터 하기전에, 지금 하는 프로젝트의 특징을 먼저 나열해보겠다 !

- 서버 X, 데이터는 UserDefaults에 저장함. 

- 로그인 기능 없음

- 위치 정보 확인함

- local notification을 활용할 예정

 

로그인 기능이 없기 때문에 마이 페이지도 없다. 그렇기 때문에 탭 3개 중 하나는 현재 앱 버전, 기본 알림 설정, 위치정보활용방침을 설정하거나 볼 수 있는 탭이다.

 

이 설정 탭을 구현하면서 이 프로젝트에 적용하기로 했던 것들(MVVM, Clean Architecture, RxSwift)을 적용해보면서 느낀점에 대해서 적어볼 예정이다 ! 


구현 화면은 아래와 같다 ! (UIView에 tap gesture를 넣어 rx.event 로 데이터를 넘겨주는 내용은 여기 ! )

아직은 공사중으로 컴포넌트의 위치나 형태는 계속 업데이트 될 것.

 

보면 알겠지만 유저와 크게 상호작용을 해서 업데이트 된 데이터를 뷰에 적용 해준다거나 그럴 화면이 없다.

결국 Viewmodel의 output을 만들어서 view에 업데이트를 해줄 것이 없다는 것이다 !

 

왜 output이 없는 것에 밑줄을 치면서 이 글을 작성하게 되었을까 ?

 

그 이유는, 이 프로젝트에서 적용하기로 했던 아키텍쳐, 디자인 패턴이 설정의 부분에서 만큼오버 엔지니어링이라고 느껴졌기 때문이다.

 

ViewModel의 형태가 불편했던 이유

user 입장에서의 흐름

 

이 설정 리스트의 어떤 것을 선택하더라도 흐름이 이렇게 될텐데,

한 프로젝트 안에서 통일된 형태를 갖추기 위해 viewmodel의 input, output, func transform의 형태로 구현해야한다는게 불편했다.

 

Viewmodel의 형태를 in,output으로 구현했을 때의 코드는 이렇고,

 // VM의 일부 코드
public func transform(input: Input) -> Output {
        let output = Output()
        
        input.defaultAlarmTapEvent
            .withUnretained(self)
            .subscribe(onNext: { viewModel, _ in
                // 뷰 이동
                viewModel.coordinator.setDefaultAlarm()
                print("알람설정 tap")
            })
            .disposed(by: disposeBag)
        
        input.termsTapEvent
            .withUnretained(self)
            .subscribe(onNext: { viewModel, _ in
                viewModel.coordinator.presentTermsPrivacy()
                print("이용약관 tap")
            })
            .disposed(by: disposeBag)
        
        return output
    }


extension SettingsViewModel {
    public struct Input {
        let defaultAlarmTapEvent: Observable<Void>
        let termsTapEvent: Observable<Void>
    }
    
    public struct Output {
    }
}

 

viewmodel의 형태를 in,output을 사용하지 않았더라면 이렇게 구현할 수 있었을 것 같다.

public func tapDefaultAlarmBtn() {
    coordinator.setDefaultAlarm()
    print("알람설정 tap")
}

public func tapTermsOfPrivacyBtn() {
    coordinator.presentTermsPrivacy()
    print("이용약관 tap")
}

 

8줄의 코드로 구현이 가능한데 구조를 맞추기 위해 필요한 코드들을 넣어 몇 배로 불려 작성한 코드..  과연 좋은 프로그래밍인가 ? 

라는 생각을 지울 수 없다.

 

물론 전체 프로젝트로 생각한다면

ViewModel의 형태를 Input, output, func transform으로 선택한 것도 데이터의 흐름이나 이 viewmodel을 사용하는 viewController에서 어떤 일이 일어날지 예측이 가능하다는 장점을 확실히 느낄 수 있어서 채택한 것에 대해 완전히 반대하는 것이 아니다 !

(장황하게 썼지만 이 viewmodel 새롭고 좋았다 ! )