Skip to content

Domain Layer 도입

Safari edited this page Jan 8, 2025 · 9 revisions

목차

들어가며

최근 머니몽 프로젝트의 구조 개편이 이루어지고 있다. 앱 배포 후 새로운 기능이 추가되고, 화면 구조가 개편되면서 프로젝트 구조적으로 아쉬운 점이 보여 이번 기회에 개선하는 방향으로 의사결정이 이뤄졌다.

이번에 개선해야 할 아쉬운 점은 클라이언트에게 사용하지 않는 인터페이스까지 제공된다는 것이다.

때문에 가장 먼저 시도한 것은 Domain Layer 도입이다.

Domain Layer 도입

머니몽은 모듈화를 통해 역할에 따라 모듈이 분리되어 있지만, 설계 단계에서 클린 아키텍처를 참고하였다.

출처: https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3

개발 초기엔 UseCase의 필요성을 느끼지 못했다. 왜냐하면 Repository만으로도 모든 동작을 수행할 수 있었으며, UseCase를 추가로 구현해야하는 만큼 개발 시간이 늘어나기 때문이다. 즉, 머니몽의 RepositoryRepository + UseCase의 역할을 수행했다.

하지만, API와 기능들이 확장되면서 Repository의 사이즈가 커지고, 그 결과 클라이언트에게 필요하지 않은 인터페이스까지 노출되는 문제가 발생했다. 이는 객체지향 설계 관점에서 SOLID 원칙 중 ISP(Interface Segregation Principle, 인터페이스 분리 원칙)를 위반하는 행위이며, 불필요한 인터페이스가 제공될 경우 객체의 역할을 벗어나는 동작을 수행할 가능성이 있다.

문제

Domain Layer를 도입함으로써 다음과 같은 문제를 해결하려고 한다.

  1. 클라이언트에게 불필요한 인터페이스 최소화
  2. Presentation Layer와 Data Layer 의존 관계 제거

클라이언트에게 불필요한 인터페이스 최소화

기존 구조

기존 의존 관계는 다이어그램과 같이 클라이언트가 Repository에 직접 접근해 데이터를 가져오거나, 네트워크 통신을 하였다. Repository는 많은 인터페이스를 제공하지만, MyPage에서 필요한 인터페이스는 user()logout()뿐이다. 다른 인터페이스는 사실 불필요한 인터페이스였다.

개선한 구조

위와 같이 인터페이스를 분리하기 위해 UseCase를 도입하였다.

MyPageRepository 대신 GetMyInfoUseCase와, LogoutUseCase를 통해 동작을 처리한다. 이로 인해 MyPage는 더 이상 불필요한 인터페이스가 제공되지 않으며, 각 객체가 역할에 맞는 동작만 수행할 수 있도록 있다.

Presentation Layer와 Data Layer 의존 관계 제거

Presentation Layer(머니몽에선 Feature)에 해당하는 MyPage는 Data Layer(머니몽에선 Core)에 해당하는 Repository에 접근하기 위해 Core를 import 해야했다. Core에는 Repository 외에도 Network, LocalStorage 등 클라이언트 뒤에서 동작하는 객체들이 포함되어 있다.

image

FeatureCore 두 모듈이 물리적으로 연결되어 있기 때문에 Feature는 언제든 Core에 있는 Network, LocalStorage 등에 접근할 수 있었다. 이와 같이 계층이 명확히 분리되지 않아 개발을 하다보면 MyPage에서 Network를 직접 접근하는 등 혼란이 발생할 수 있다.

Domain Layer를 도입해 두 모듈 의존성을 물리적으로 분리시킬 수 있었다.

image

Domain Layer에 해당하는 모듈들은 Interface를 가지고 있다. Feature는 이제 DomainInterface만 의존하면 되기 때문에 더 이상 Core를 직접적으로 의존할 필요가 없다.

마무리

Domain Layer를 도입하면서 2가지 문제를 해결할 수 있었다. 하지만, 장점만 있는 것은 아니었다. 동작이 많은 멤버 관리 탭의 경우,

스크린샷 2025-01-07 오후 9 25 09

무려 8개의 UseCase를 의존해야 했다. 이처럼 한 화면에서 많은 동작을 처리하는 경우, 그만큼 많은 UseCase가 필요하다. 또한, 많은 UseCase를 의존해야하기 때문에 의존성을 관리하기 어렵다는 단점이 있었다. 때문에 앞으로 추가적으로 발생한 문제를 어떻게 해결할지 고민할 계획이다.