Flyleaf - 독서를 여행처럼/개발일지

[개발일지] 04. Composition Root (feat. 어디까지 몰라야하는가?)

여성일 2026. 3. 11. 20:54
728x90

App 레이어는 정말 Interface에만 의존할까?

이전 글에서는 "App 레이어는 Feature 내부 구현을 직접 알지 않는다. 대신 Feature의 Interface에만 의존한다."라고 이야기 했습니다. 

 

과연 그럴까요?! 제가 모듈화를 하면서 가장 고민했던 지점이 바로 이 부분이었습니다.

 

- 정말 App 레이어는 Feature 구현을 전혀 몰라야 할까?

- 그렇다면 실제 Feature 객체는 누가 생성해야 할까?

 

처음에는 "App은 Feature 구현을 전혀 몰라야한다!" 라고 생각했습니다.

그래서 AppCoordinator에서도 Feature 모듈을 import하지 않고 Interface만 의존하도록 구조를 설계했습니다.

 

예를 들어 AppCoordinator는 아래와 같이 Interface 타입만 알고 있습니다.

import HomeInterface
import LoginInterface

private let homeBuilder: HomeBuildable
private let loginBuilder: LoginBuildable

 

그리고 실제 화면을 생성할 때도 Interface를 통해 화면을 요청합니다.

let loginVC = loginBuilder.build

이 구조에서는 AppCoordinator가 LoginViewController, LoginViewModel 같은 Feature 내부 구현을 전혀 알 필요가 없습니다. 여기까지는 이상적인 구조처럼 보였습니다. 하지만 계속 구현을 하면서 한 가지 문제가 생겼습니다.


Interface의 구현체는 누가 생성해야 할까?

그렇다면 Interface의 구현체는 누가 생성할까?

Builder 패턴을 사용하더라도 결국 LoginBuilder, HomeBuilder와 같은 구현 객체는 어딘가에서 생성되어야 합니다.

 

Flyleaf에서는 이 역할을 SceneDelegate에서 담당하고 있습니다.

import HomeFeature
import LoginFeature

let homeBuilder = HomeBuilder()
let loginBuilder = LoginBuilder()

let coordinator = AppCoordinator(
  navigationController: navigationController,
  authService: authService,
  homeBuilder: homeBuilder,
  loginBuilder: loginBuilder
)

이 코드를 보면 SceneDelegate에서는 Feature 구현 모듈을 직접 import하고 있습니다.

 

처음에는 이 구조가 "결국 App Layer는 Feature에 의존할 수 밖에 없네? 이게 맞는 건가?"라는 고민이 들었습니다.


Composition Root

이 고민을 정리하는 과정에서 알게 된 개념이 바로 Composition Root였습니다.

Composition Root는 앱의 모든 객체를 조립하는 최상위 지점을 의미합니다.

 

즉,

- 어떤 객체를 생성할지

- 어떤 의존성을 주입할지

와 같은 것들을 한 곳에서 결정하는 위치입니다.


Flyleaf에서의 Composition Root

Flyleaf에서는 이 역할을 SceneDelegate가 담당합니다.

 

SceneDelegate 
    ├ Builder 생성
    └ AppCoordinator에 주입

 

이  지점에서는 Feature의 구현을 알고 있어도 괜찮습니다.

 

왜냐하면 Composition Root의 역할 자체가 모든 객체를 조립하는 것이기 때문입니다.

 

1. SceneDelegate(Composition Root)

- Feature 구현 모듈을 알고 있어도 괜찮다.

- 객체 생성과 의존성 조립을 담당한다.

 

2. AppCoordinator 이후 레이어

- Feature 구현이 아닌 Interface에만 의존한다.

 

즉, 의존성 흐름은 아래와 같습니다.


결국 중요한 것은 "어디까지 알게 할 것인가?"

Micro-Features Architecture를 적용하면서 느낀 점은

"아무도 아무것도 몰라야 한다"는 것이 목표가 아니라는 것이었습니다.

 

모듈화 아키텍처서 중요한 것은 구현 의존성이 앱 전체로 퍼지지 않도록 경계를 만드는 것이라고 생각합니다.

 

제가 모듈화를 설계하면서 가장 많이 했던 생각은

 

1. App은 Feature를 몰라야 한다.

2. Feature끼리는 서로 완전히 몰라야 한다.

3. 모든 레이어는 서로 완전히 분리되어야 한다.

 

이렇게 보면 마치 모든 모듈이 서로 완전히 독립적이어야 하는 것처럼 느껴집니다.

 

하지만 실제로 앱을 개발하다 보면 어딘가는 반드시 다른 모듈을 알아야 하는 지점이 존재합니다.

 

예를 들어

- Feature 객체는 누군가 생성해야 하고

- 의존성은 어디선가 주입되어야 하고

- 화면 흐름도 결국 하나의 지점에서 조립되어야 합니다.

 

즉, 어떤 레이어도 아무것도 모르는 상태로 앱(시스템)을 구성하는 것은 현실적으로 불가능하지 않나 생각합니다.