-
Local 레이어란?Clean Architecture 2025. 8. 10. 20:40
안녕하세요~ 주말에 '좀비딸'이라는 영화를 봤는데요. 좀비 영화인데 공포랑 코미디랑 같이 섞어서 재밌더라고요ㅎㅎ 감동적이면서도 비교적 가볍게 보기 좋은 영화였던 것 같아요. 저번주에는 데이터 레이어를 의존하는 원격 레이어에 대해서 알아봤었는데요. 오늘은 데이터 레이어를 의존하는 또 다른 레이어인 로컬 레이어에 대해서 알아보려고 합니다.
출처: https://github.com/bufferapp/clean-architecture-components-boilerplate?tab=readme-ov-file#Architecture 1. 로컬 레이어 정의와 구성요소
로컬 레이어는 로컬 데이터를 저장하고 읽어오는 계층으로 DB, SharedPreferences, 파일 시스템으로 관리합니다. 로컬 레이어의 구성요소로는 DataSource Implementation, Database, Local model, Local Model Mapper가 있습니다. 하나씩 살펴보겠습니다.
2. DataSource Implementation
class UserLocalDataSourceImpl( private val userDao: UserDao, private val userMapper: UserMapper ): UserLocalDataSource { override suspend fun getUserById(userId: Int): UserEntity? { val localUser = userDao.getUserById(userId) return userMapper.mapLocalToEntity } override suspend fun saveUser(user: UserEntity) { val localUser = userMapper.mapEntityToLocal(user) userDao.insertUser(local) } }
LocalDataSourceImpl은 데이터 레이어의 LocalDataSoure 인터페이스를 구현합니다. 첫번째 메소드에서는 userId를 통해 유저데이터를 가져오는 로직이 필요합니다.이때, 로컬 데이터베이스인 DAO를 의존하여 관련 데이터를 가져옵니다. 가져온 데이터는 Local 레이어에서 쓸 수 있는 모델이기 때문에 이를 다시 데이터 레이어의 모델인 엔티티로 변환하기 위해서 mapper를 의존합니다. 두번째 메소드에서는 데이터 레이어의 모델을 로컬 레이어에 저장합니다. 이때, 서로 다른 모델간의 변환을 위해 mapper를 사용하고 마찬가지로 로컬 데이터베이스에 저장합니다.
3. Database (= DAO)
@Dao interface userDao: BaseDao<UserLocal> { @Query("SELECT * FROM {RoomConstant.Table.USER} WHERE id = :userId") suspend fun getUser(userId: Int): UserLocal? @Insert(onConflict = OnConflictStrategy.REPLACE) suspend fun insertUser(user: UserLocal) }
DAO 데이터베이스에서는 Room의 SQL문을 통해 사용자의 정보에 대한 조회, 추가, 업데이트 등의 기능을 합니다. 이때 조회 기능을 하는 getUser 메소드에서 리턴값인 유저 정보는 물음표(?)를 통해 null 처리를 해야합니다. 왜냐하면 로컬 데이터는 '언제든 데이터가 삭제될 수 있다'는 가정으로 설계해야하기 때문입니다. 또한 데이터 추가를 하는 @Insert 어노테이션 옆의 onConflict는 기존 데이터가 존재할때 덮어쓴다는 것을 의미합니다.
4. Mapper
internal class UserMapper { fun mapLocalToEntity(userLocal: UserLocal): UserEntity { return UserEntity( id = userLocal.id, name = userLocal.name, address = userLoal.address ) } fun mapEntityToLocal(userEntity: UserEntity): UserLocal { return UserLocal( id = userEntity.id, name = userEntity.name, address = userEntity.address ) } }
매퍼(Mapper)는 로컬 레이어의 모델과 데이터 레이어의 모델 사이를 변환해주는 역할을 합니다.
5. 추가 정리
첫번째로, 데이터베이스에서 데이터를 가져오는 과정을 UI 스레드인 메인 스레드에서 실행하게 되면 화면이 멈추는 ANR(Application Not Responding) 오류가 생길 수 있습니다. 따라서 코루틴 등을 이용하여 다른 스레드에서 실행하는 비동기 처리가 필요합니다. 두번째로, 데이터저장소 중 Room을 사용할 지 아니면 SharedPreference 사용할 지에 대한 고민 과정이 필요합니다. Room의 경우 객체와 같은 비교적 무거운 데이터를, SharedPreference는 토큰과 같은 String primitive type을 저장할 수 있는 가벼운 데이터가 적합합니다. 물론 객체를 Gson, Moshi를 이용해 String으로 직렬화하여 Room이 아닌 SharedPreference에 저장할 수 있는데 상황에 따라 잘 파악하는게 좋습니다. 세번째로, 데이터베이스의 DTO 필드 구조가 변경될 때 적절히 대응해야합니다. 기본값을 추가하거나, nullable 필드로 선언하는 방법이 있습니다. 마지막으로, 로컬 레이어와 원격 레이어는 각각 데이터 레이어에 의존할 뿐 서로를 의존하지 않습니다.
오늘은 데이터 레이어를 의존하는 로컬 레이어에 대해서 알아보았습니다. 다음에는 도메인 레이어를 의존하는 Presentation 레이어에 대해서 알아보겠습니다. 도움이 되셨다면 좋겠습니다 이번주 화이팅하세요! 🙌
'Clean Architecture' 카테고리의 다른 글
UI 레이어란? (3) 2025.08.24 Presentation 레이어란? (8) 2025.08.17 Remote 레이어란? (6) 2025.08.03 Data 레이어란? (2) 2025.07.27 Domain 레이어란? (2) 2025.07.20