Route 단 new 연쇄를 없애는 해결: Composition Root (index.ts) 구조 도입기
2025. 5. 30. 22:23
728x90

도입 배경: Controller에 쌓여가는 new 연쇄

처음 인증 서비스를 개발할 때는 다음과 같은 방식으로 객체를 조립하고 있었습니다.

const userRepository = new UserRepository(...);
const sessionRepository = new SessionRepository(...);
const tokenIssuer = new JwtTokenIssuer();
const tokenService = new TokenService(tokenIssuer, ...);
const registerUsecase = new RegisterUserUsecase(userRepository, sessionRepository, ..., tokenService);
const registerController = new RegisterController(registerUsecase);

이 코드는 문제 없이 동작하지만, 다음과 같은 구조적 문제를 내포하고 있었습니다.

문제점 정리

구분 문제
중복 controller.ts, route.ts 등 여러 파일에서 반복적으로 인스턴스를 생성해야 함
유지보수 의존성 변경 시 모든 controller에서 일일이 수정 필요
테스트 어려움 개별 controller 단위 테스트를 위해 mock 객체 주입이 까다로움
역할 과중 Controller가 로직 실행뿐 아니라 의존성 조립까지 담당하게 됨

이러한 문제는 프로젝트가 커질수록 유지보수 비용으로 이어졌고, 이를 해결하기 위해 의존성 조립 전용 파일, 즉 index.ts를 도입하게 되었습니다.


해결 전략: Composition Root로서의 index.ts

Composition Root란 프로그램 실행 시점에 의존성을 생성하고 조립하는 시작점을 의미합니다.
이 구조는 DDD, Clean Architecture에서도 적극적으로 권장되는 방식입니다.

도입한 구조

// auth/controllers/index.ts
export const registerController = new RegisterController(registerUserUsecase);
export const loginController = new LoginController(loginUserUsecase);
// auth/use-cases/index.ts
export const registerUserUsecase = new RegisterUserUsecase(
  userRepository,
  sessionRepository,
  refreshTokenRepository,
  tokenService
);
// auth/routes/authRouter.ts
import { registerController } from '../controllers';

router.post('/register', (req, res) => registerController.handle(req, res));

이제 각 route에서는 단순히 .handle() 메서드만 호출하면 되며, 내부 조립은 전부 index 파일에 위임됩니다.


Composition Root 구조의 이점

항목 설명
유지보수성 의존성 변경 시 `index.ts`만 수정하면 됨
중복 제거 route/controller 단에서 new 연쇄 제거
테스트 용이성 Mock 객체를 주입한 조립 index를 따로 만들 수 있음
역할 분리 controller는 실행만, usecase는 로직만, index는 조립만 담당

실무 사례와 비교

프레임워크 Composition Root 역할
NestJS `@Module()`
Spring Boot `@Configuration`, `@Bean`
Node.js 수동 DI 시 `index.ts` 조립 방식 사용

마무리

인증 서비스를 개발하면서, route 단에서 반복되는 인스턴스 생성 문제를 체감했고, 이를 실무적으로 해결하고자 조립용 index.ts 구조를 도입했습니다.
이 구조는 프로젝트가 커질수록 진가를 발휘하며, 유지보수성과 테스트 용이성을 동시에 확보할 수 있습니다.

서비스의 책임을 명확하게 나누고 싶다면, 지금 바로 Composition Root를 도입해보세요.

반응형