Android UI State Modeling 어떤게 좋을까?
우리는 안드로이드를 개발 할 때 MVVM 패턴을 사용하면서 ViewModel에서 데이터를 요청하고 결과를 UI로 만들고는 합니다.
데이터 요청은 로딩이 따라오고 항상 성공만 하지는 않습니다.
또한 UI는 한 가지 상태만을 가지고 있지 않습니다.
이를 위해 여러 개의 State를 만드는 법부터 sealed class를 활용한 State Modeling 전략까지 다양한 방법이 이용되고 있습니다.
이러한 방법들을 다양하게 시도 해 보면서 언제 사용하는게 적합한지 그리고 어떤 장・단점이 있었는지에 대한 생각을 정리해볼까 합니다.
UI 모델링을 처리하는 방법은 정말 많지만 일반적으로 사용되는 4가지 모델링 패턴으로 얘기를 해보도록 하겠습니다.
- 여러 개의 State를 만들고 Loading, Error 별도로 만들기
- sealed class로 하나의 State를 만들고 상태 개수만큼 구현체 만들기
- 하나의 State data class를 만들어서 관리하기
- 하나의 State data class와 Loading, Error 별도로 만들기
한 가지 시나리오를 가정하고 위의 네 가지 방법으로 구현 해보겠습니다.
들어가기에 앞서 프로젝트를 직접 실행 해 보고 싶으시다면
아래 GitHub 프로젝트를 확인 해주세요.
| 요구사항 |
“유저 정보를 받아와 2초정도 후에 이름과 나이를 화면에 그려주세요.
오류가 발생하면 따로 표시 해 주세요”
State 1
여러개의 State를 만들고 Loading, Error 별도로 만들기
Pros.
- 개별적으로 State를 정의함으로써 원하는 데이터만 변경이 가능하다.
- 각 State가 서로에게 영향을 발생시키지 않는다.
- 데이터바인딩 코드를 작성하기 쉽다
Cons.
- State 가짓수가 많아 실수를 유발하기 쉽다.
- Event를 통해 상태가 어떻게 변경될지 예측이 어렵다.
- 구독을 처리하는 코드가 많고 복잡하다.
When.
- Base 구조를 사용하지 않는 간단한 화면에 적합
- State와 데이터바인딩을 1:1 구조로 사용하는 경우
State 2
sealed class로 하나의 State를 만들고 상태 개수만큼 구현체 만들기
Pros.
- MVI와 유사한 형태의 구현으로 UI에 대한 의도를 명확하게 표현이 가능
- sealed class를 활용함으로써 객체지향적인 처리에 유리하다.
- UI를 변경하는 코드가 분산되지 않아 코드 분석이 편하다.
- 한 가지 상태만 가지기 때문에 상태가 섞이는 것을 고려하지 않아도 된다.
Cons.
- 표현하고자 하는 모든 상태를 나열해야 하기 때문에 화면이 복잡해지면 상태가 비약적으로 늘어나고 부분적인 업데이트가 불가하다.
- 각 상태가 변경되면 이전 상태를 별도로 보관하지 않는 한 이전 상태에 대한 데이터를 복구할 방법이 없다.
- 공통으로 쓰이는 상태를 표현하기가 어렵고 공유하는 것은 더욱 복잡함
- 데이터바인딩을 사용하기가 상당히 어렵다.
When.
- 명확한 의도를 갖고 UI를 표현하는 경우 (생각을 바로 상태로 변경 가능)
- 로딩이나 오류를 전체 상태로 취급할 수 있는 경우
- 부분적인 데이터 수정 혹은 이전 상태가 필요없는 경우
State 3
하나의 State data class를 만들어서 관리하기
Pros.
- 하나의 데이터에 필요한 모든 상태를 포함할 수 있어 UI에 대한 비즈니스 로직 처리가 편하다.
- data class를 사용함으로써 copy라는 강력한 부분 업데이트 수단을 제공
- UI를 변경하는 코드가 분산되지 않아 코드 분석이 편하다.
- LiveData나 StateFlow의 map 함수와 distinctUntilChanged를 조합해 원하는 형태로 데이터바인딩에 적용 가능
Cons.
- copy가 어느정도 안전성을 보장하지만 데이터 변경에 대한 동시성 이슈에 취약하다.
- 화면이 복잡해지는 경우 data class에 필요한 프로퍼티가 비약적으로 늘어난다.
- data class 특성상 하나의 프로퍼티 값만 바뀌어도 구독하고 있는 모든 옵저버에 변경을 알려 애니메이션같은 1회성 동작에 주의가 필요하다.
When.
- UI에 대한 부분적인 수정이 빈번하게 일어나는 경우
- UI 비즈니스 로직이 다소 복잡한 경우
- 상태를 조합하여 자주 사용하는 경우
- 로딩이나 오류도 상태에 포함하여 취급할 수 있는 경우
State 4
하나의 State data class와 Loading, Error 별도로 만들기
Pros.
- UI 상태가 로딩이나 오류에 의존적이지 않아 따로 처리가 가능하다.
- Base를 사용하는 경우 확장성 있는 구조를 제공한다.
Cons.
- UI 상태가 로딩이나 오류와 의존성이 있는 경우 처리가 다소 복잡하다.
- 로딩 상태를 여러 곳에서 변경할 수 있기 때문에 상태 변경에 주의가 필요하다.
When.
- UI 상태를 로딩과 오류와 나누어서 사용하는 경우
- Base에서 로딩과 오류를 일반적으로 처리하고 싶은 경우
여러분은 어떤 UI State Modeling 전략을 사용하고 계신가요?
저는 디자인 요구사항과 아키텍처 그리고 팀원들과의 컨벤션까지 고려하다보면 결국 이 물음에 대한 완벽한 정답은 없다고 생각합니다.
Best Practice 보다는 Team Practice가 더욱 중요하기도 하구요.
최근 LiveData나 StateFlow를 이용해 상태를 어떻게 처리해야 좋을까요?
라는 질문을 많이 받는데 이 내용을 통해 자기만의 적합한 UI State Modeling을 비교해 보면서 좋은 구조를 찾아가시길 바랍니다.
다음에는 Compose에서의 UI State Modeling을 주제로 찾아뵙겠습니다.
끝.
읽어보기 )