ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Android] Repository Pattern
    안드로이드 2022. 5. 7. 17:27
    728x90
    반응형

    안드로이드 아키텍처

    발생 배경🤷🏻

    비즈니스 로직은 프로그램의 핵심이 되는 요소이며, 비즈니스 로직을 잘 짜야 원하는 결과를 올바르게 도출할 수 있습니다. 이때 비즈니스 로직은 보통 데이터베이스나 웹서비스 등의 데이터 저장소에 접근하게 되는데, 이 과정에서 여러 문제가 발생할 수 있습니다. 주로 중복되는 코드, 오류를 발생할 가능성이 있는 코드, 오타, 비즈니스 로직 테스트의 어려움 등이 있습니다.

     

    이에 따라 요구사항이 발생하는데,

    1. 비즈니스 로직과 데이터 레이어를 분리해야 한다.
    2. 중앙 집중 처리 방식을 통해 일관된 데이터 로직을 제공해야 한다.

    등장🔥

    이러한 요구사항을 해결하기 위해 등장한 디자인 패턴이 Repository Pattern입니다.

    Repository는 Data Source 계층과 비즈니스 계층 사이를 중재하는 역할을 갖게 됩니다. Repository는 데이터 소스에 쿼리를 날리거나, 데이터를 다른 Domain에서 사용할 수 있도록 새롭게 Mapping 할 수 있습니다.

     

    특징👍🏻

    1. 데이터가 있는 여러 저장소(Local Data Source, Remote Data Source)를 추상화하여 중앙 집중 처리 방식을 구현할 수 있습니다.
    2. 데이터를 사용하는 Domain에서는 비즈니스 로직에만 집중할 수 있습니다. 예를 들어, ViewModel에서는 데이터가 로컬 DB에서 오는지, 서버에서 API 응답을 통해 오는 것인지 출처를 몰라도 됩니다. Repository를 참조하여 Repository가 제공해주는 데이터를 이용하기만 하면 됩니다.
    3. Repository가 추상화되어 있으므로 항상 같은 Interface로 데이터를 요청할 수 있습니다. ViewModel이 여러 Repository를 공유하더라도 일관된 Interface를 통해 데이터 일관성을 또한 유지할 수 있습니다.

    장점🚀

    1. 데이터 로직과 비즈니스 로직을 분리할 수 있습니다.
    2. Domain에서는 일관된 인터페이스를 통해 데이터를 요청할 수 있습니다.
    3. 데이터 저장소의 데이터를 캡슐화할 수 있어 객체 지향적인 프로그래밍에 적합합니다.
    4. 단위 테스트를 통해 검증이 가능합니다.
    5. 객체 간의 결합도가 감소합니다.
    6. 애플리케이션의 전체적인 디자인이 바뀌어도 적용할 수 있는 유연한 아키텍처입니다.

    구조🏛

    View -> Presenter / ViewModel -> Repository -> DataSource(API, Local DB)

     

    ViewModel

    class UserViewModel(
        private val userRepositoryImpl: UserRepositoryImpl
    ) : ViewModel() {
        fun getAllUser() = userRepositoryImpl.getAllUser()
    }

    RepositoryImpl

     

    class UserRepositoryImpl :UserRepository{
        override suspend fun getAllUser() = userApi.getAllUser()
    }

    Repository

     

    interface UserRepository {
        suspend fun getAllUser() : UserInfo
    }

     

    주의할 점⚠️

    Repository Pattern 적용 시 주의할 점이 있습니다‼️

    바로 Repository가 DataSource의 데이터를 그대로 전달해주는 점입니다.

     

    위의 문제점은 Data스펙이 바뀌면 Presentation Layer 전반에 영향을 끼치게 됩니다. 예를 들어 클라이언트에서 User 정보를 표기해야 하는데, 서버에서 각기 다른 데이터 요청을 N번 거쳐야 한다고 할 때,  그럼 N개의 데이터에 대한 변경 사항은 모두 온전히 클라에 영향을 줄 것입니다.  더 중요한 점은 이렇게 복잡한 데이터 모델을 혼재하여 사용하게 되면 다른 개발자가 콘텍스트를 이해하기 어려워집니다.

     

    서버 데이터 구조를 그대로 가져와 사용할 경우, 팀 내 도메인 용어와 실제 코드 베이스 용어가 달라지고 커뮤니케이션 리소스가 급증하게 되는 상황이 발생합니다. 또한 도메인의 비즈니스 로직 처리에 필요한 메서드 생성 시점이 왔을 때, 서버 테이블을 반영한 객체에 추가하게 되면 해당 객체는 테이블도 표현하고, 도메인 로직도 처리하는 God Object가 될 확률이 높습니다.

     

    이를 해결하기 위해서는 Mapper 클래스를 활용하는 것이 좋습니다.

    Mapper란 말 그대로 테이블 객체 ↔ 도메인 모델 객체 간의 Mapping을 시켜주는 유틸 성 클래스를 의미합니다.

    Repository 내에서 mapper를 활용하여 테이블 객체가 아닌 도메인 모델로 전달을 해주면 Presentation Layer는 Data Layer로부터 진정한 자유를 찾을 수 있게 됩니다.

    fun UserEntity.toUseInfo() = UserInfo(
        this.id,
        this.typeEntity
    )
    출처🚀
    https://vagabond95.me/posts/android-repository-pattern/
    https://4z7l.github.io/2020/11/24/repository-pattern.html
    반응형
    728x90
    반응형

    댓글

Designed by ZibroTistory.