Open lminsu opened 3 weeks ago
프래그먼트가 제공하는 함수를 사용
하여 데이터를 바인드하는 경우)
bindAView()
함수를 호출하는 것 대신 bindBView()
함수를 호출하도록 변경해야 함뷰가 수정될 때 뷰모델이 수정될 가능성이 존재한다는 것
뷰 로직만 변경
될 때, ⚠️state를 관리하는 로직을 안 건드리도록 주의하면서
뷰 로직을 변경해야 함뷰 로직은 그대로고 state를 관리하는 로직만 변경
되었을 때도, 뷰 로직을 안 건드리도록 주의하면서
state 관리 로직을 변경해야 함최소 몇 문자
조건만 있다가 특수문자 포함
조건이 추가된 경우뷰로직은 건들지 않도록 주의
하면서 개발해야 함SSOT는 어떤 데이터의 생성 및 수정을 한 클래스에서만 하도록 강제
하는 것
A 클래스에서 제공된 인스턴스 그대로 사용되고 있음
을 확신한 채로 디버깅 가능A 클래스의 a 메소드에서만
데이터의 생성 및 수정이 일어난다면A 클래스의 a 메소드
뿐 아니라, B클래스의 b 메소드
에서도 데이터의 생성 및 수정이 일어난다면TmdbMovies 클래스에 정의한 경우 코드는 아래처럼 구현됨
Movie 인스턴스를 만들 때 재료가 되는 클래스
이므로 Movie가TmdbMovies를 의존해야지, 그 반대가 되어서는 안 됨만약 라이브러리에서 A(또는 B)에 대한 의존성이 없었다면?
class MovieRepository {
private val remoteDataSource: RemoteDataSource = RemoteDataSource()
suspend fun getMovies(): List
data class TmdbMovies(
val page: Long?,
val results: List
MovieRepository 클래스에 정의한 경우
TmdbMovies 클래스의 Movie 클래스 의존성을 제거할 수 있음
class MovieRepository {
private val remoteDataSource: RemoteDataSource = RemoteDataSource()
suspend fun getMovies(): List<Movie>? {
return remoteDataSource.getTmdbMovies()?.toMovies()
}
private fun TmdbMovies.toMovies(): List<Movie>? {
return getTmdbMovies()
?.map { it.toMovie() }
?.filterNotNull()
}
private fun TmdbMovie.toMovie(): Movie? {
return Movie(
id = id ?: return null,
title = title,
overview = overview,
releaseDate = releaseDate,
posterPath = makePosterPathWithBaseUrl()
)
}
}
data class TmdbMovies(
val page: Long?,
val results: List
Single Source of truth
이런 패턴은 아래와 같은 장점들을 가져온다.
offline-first application(앱 첫 시작 때 네트워크를 통해 데이터를 불러오지 않는 앱)의 경우, 앱 데이터의 SSOT는 보통 데이터베이스이다. 다른 경우에 SSOT는 뷰모델이나 심지어 UI가 될 수도 있다.
Unidirectional Data Flow
Recommended app architecture
위에서 설명한 내용들(SSOT, UDF)을 따르려면 최소한 두 개의 layer가 존재해야 한다.(UI 레이어, data 레이어)
클래스들 간의 의존성
을 의미한다. 예를 들어서, domain layer는 data layer 클래스들에 의존한다.UI layer
UI 레이어는 아래 두 개로 이루어져 있음
Data Layer
repository
로 이루어져 있고 각각의 repository는 0부터 여러 개의data source
를 가지고 있음MoviesRepository
또는 결제와 관련된 데이터를 담당하는PaymentsRepository
가 있을 수 있음