ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Domain 레이어란?
    Clean Architecture 2025. 7. 20. 21:43

    안녕하세요. 오늘 초복이네요 ^^ 비 온 뒤로 햇빛이 너무 강해서 우산을 양산처럼 쓰고 다니고 있어요. 

    오늘은 클린 아키텍처도메인 레이어에 대해 알아보고자 합니다. 먼저 저번에 보여드린 밥아저씨의 클린 아키텍처 그림을 한번 살펴보겠습니다!

    출처: https://newsletter.techworld-with-milan.com/p/what-is-clean-architecture

     

    밥아저씨의 클린 아키텍처에서 안쪽의 UseCases 와 Entities 가 위치하는 곳이 바로 도메인 레이어로 볼 수 있습니다. 도메인 레이어는 순수 비즈니스 로직과 앱의 핵심 규칙을 정의하는 영역입니다. 다른 어떤 레이어도 의존해서는 안되며, 어떤 외부 변경이 도메인 영역에 영향을 주면 안됩니다. 위의 클린 아키텍처 영역을 6개의 레이어(모듈)로 분리하면 아래와 같습니다.

    출처: https://github.com/bufferapp/clean-architecture-components-boilerplate?tab=readme-ov-file#Architecture

     

    User Interface(UI) 레이어, Presentation 레이어, Domain 레이어, Data 레이어, Remote 레이어, Cache(=Local) 레이어 총 6개의 레이어로 구성되어 있습니다. 이중에 도메인 레이어의 구성요소를 하나씩 살펴보겠습니다.

    도메인 레이어

    1. 모델(Model)

    도메인 레이어에서의 모델은 엔티티(Entity)를 의미합니다. 아까 밥아저씨의 클린아키텍처 그림에서 동심원 가장 안쪽에 있던 Entities 가 바로 도메인 레이어의 모델입니다. 이는 앱의 비즈니스를 표현하는 DTO(Data Transfer Object) 객체로, 쉽게 말하면 어떤 형체라고 이해할 수 있습니다.

    // domain layer 의 entity
    data class User(
       val name: String,
       val age: Int,
       val gender: String
    )

     

    2. 유즈케이스(UseCase)

    유즈케이스(UseCase) 는 앱의 비즈니스 프로세스를 캡슐화하는 역할을 합니다. 쉽게 말하면, 어떠한 행동(action) 을 의미합니다. 여기서 하나의 유즈케이스는 하나의 비즈니스 로직만을 처리해야하는 단일 책임 원칙(Single Responsibility Principle, SRP) 를 가집니다. 

    // 단일 책임 원칙(SRP) 를 준수하지 않은 유즈케이스
    class PlaceOrderUseCase {
        fun execute(order: Order) {
            // 1. 주문 생성
            createOrder(order)
            // 2. 결제 처리
            payMoney(order)
            // 3. 배달원 배정
            callRider(order)
            // 4. 배달 완료 알림 전송
            notifyCustomer(order)
        }
    }

     

    예를 들어, 이와 같이 유즈케이스를 작성한다고 가정합시다. 여기서 PlaceOrderUseCase 는 여러 책임을 갖습니다. 이때, 네 개의 로직 중 어느 하나라도 변경되면 PlaceOrderUseCase 전체가 영향을 받게 됩니다. 따라서, 아래와 같이 단일 책임을 갖도록  분리하는게 유지보수에 좋습니다.

    // 단일 책임 원칙(SRP) 를 준수한 유즈케이스
    class CreateOrderUseCase {
        fun execute(order: Order) { .. }
    }
    
    class PayMoneyUseCase {
        fun execute(order: Order) { .. }
    }
    
    class CallRiderUseCase {
        fun execute(order: Order) { .. }
    }
    
    class NotifyCustomerUseCase {
        fun execute(order: Order) { .. }
    }

     

    유즈케이스는 추상체(Interface)와 구현체(Implementation)로 구성되어 있습니다. 다음의 코드를 살펴보겠습니다.

    // UseCase Interface
    interface GetUserUseCase {
        fun invoke(userId: String): User
    }
    
    // UseCase Implementation
    class GetUserUseCaseImpl(private val userRepository: UserRepository): GetUserUseCase {
        override fun invoke(userId: String): User {
            return userRepository.getUserById(userId)
        }
    }

     

    예시에서, UseCaseImpl UseCase 인터페이스를 구현(implement)하면서 User 모델을 반환해야 합니다. 이때, userId 를 가지고 User 라는 데이터에 접근하기 위해 또 다른 의존성이 필요한데요. 바로, UserRepository(Interface) 을 통해 User 데이터 모델을 얻어올 수 있습니다. 

     

    3. Repository Interface

    레포지토리 추상체(repository interface)도메인 레이어(Domain layer)와 데이터 레이어(Data layer)를 연결하는 역할을 합니다. 의존 방향은 data layer → domain layer 입니다. 도메인 레이어에서는 레포지토리 내부 메소드의 상세 구현을 알지 못합니다. 예를 들어 DataBase, API, 캐시 등 어떤 데이터 소스(DataSource)를 사용하는 지 알 수 없습니다.

    // Repository 추상체 
    interface UserRepository {
        fun getUserById(userId: String): User
    }

     

    4. domain 레이어는 기획의 영역이다.

    도메인 레이어에는 앱 기획자의 의도, 생각, 설계가 담겨있습니다. 도메인 레이어를 설계하면서 "기획자의 의도가 이게 맞을까?" 라는 생각을 해야하며, 서비스를 만드는 과정에서 기획자와 얘기를 해야하는 상황이 생긴다면 도메인 레이어를 같이 살펴봐야 합니다.

     

    5. 정리

    도메인 레이어는 가장 핵심적인 비즈니스 로직을 담고 있으며, 서버 API 나 UI 와 같은 외부적 변경이 영향을 주면 안됩니다. 또한, 안드로이드 플랫폼과 독립적인 순수 코틀린 코드로 구성되어 있습니다. 메소드나 클래스를 네이밍 할 때, 직관적이고 이해하기 쉽도록 표현하는 것이 좋습니다.

     

    오늘은 도메인 레이어와 구성 요소인 Model, UseCase Interface, UseCase Implementation, Repository Interface 와 의존 관계를 알아보았습니다! 다음에는 도메인 레이어(domain layer)를 의존하는 데이터 레이어(data layer)에 대해서 알아보겠습니다🫠

    'Clean Architecture' 카테고리의 다른 글

    Local 레이어란?  (4) 2025.08.10
    Remote 레이어란?  (6) 2025.08.03
    Data 레이어란?  (2) 2025.07.27
    클린 아키텍처 파헤쳐보기  (0) 2025.04.20
    클린 아키텍처 소개  (0) 2025.04.06
Designed by Tistory.