🧐TIL
[DDD] 의존 관계 제어
date
Mar 11, 2023
thumbnail
slug
ddd-dependency
author
status
Public
summary
“도메인 주도 설계 철저 입문”을 읽으며 공부한 내용을 정리합니다.
type
Post
category
🧐TIL
tags
TIL
DDD
Architecture
updatedAt
Jun 18, 2023 05:57 AM
의존 (Dependency)
— 의존은 도메인 주도 설계에서 나온 개념은 아니다. 다만 소프트웨어의 유연성을 위해서 도메인 주도 설계에서도 의존 관계를 제어하는 것을 강조하고 있다.
그렇다면 의존이란 무엇일까? 더 깊게 알아보려면 다른 참고 자료들도 많겠지만 여기서는 “도메인 주도 설계 철저 입문”에서 다루는 내용을 중점적으로 요약해본다.
의존이란 무엇인가
의존은 한 객체가 다른 객체를 참조하면서 발생한다.
만약 A라는 객체는 B라는 객체를 속성으로 갖는다고 정의되어 있다면 B가 정의되어 있지 않을 경우 A의 정의는 성립할 수 없다. 이럴 때 A가 B에 의존한다고 한다.
또한 반드시 참조가 아니더라도 인터페이스와 구현 클래스의 사이에서도 의존은 발생한다.
의존 관계는 왜 제어되어야 하는가
프로그램을 만들면서 의존 관계는 자연스럽게 발생한다. 다만 개발이 어느정도 진행된 이후 중요한 역할을 하는 객체를 변경해야 하는 경우가 생겼을 때 무턱대고 객체를 수정했다가는 해당 객체를 참조하는 다른 객체들이 영향을 받고 치명적인 버그로 이어질 수 있다.
그럼에도 수정은 불가피한데 의존 관계가 복잡하게 얽혀 있을수록 수정 작업은 까다로워지고 유연하지 못한 프로그램이 될 것이다. 그렇다고 의존 자체를 막거나 피하는 것에는 한계가 있기 때문에 최대한 특정 기술에 의존하지 않도록 의존성을 제어하는 것이 중요하다.
의존 관계 역전 원칙
의존 관계 역전 법칙(Dependency Inversion Principle, DIP)은 객체 지향 설계 원칙인 SOLID의 하나로 의존 관계를 제어하는 방법이다.
DIP는 다음과 같이 요약할 수 있다.
- 추상화 수준이 높은 모듈이 낮은 모듈에 의존해서는 안 되며 두 모듈 모두 추상 타입에 의존해야 한다.
- 추상 타입이 구현의 세부 사항에 의존해서는 안 된다. 구현의 세부 사항이 추상 타입에 의존해야 한다.
추상 타입에 의존하라
추상화 수준은 입/출력으로부터의 거리를 뜻하는데, 기계의 동작에 가까운 구체적인 처리들은 추상화 수준이 낮다고 표현하며 서비스 객체처럼 클라이언트가 요구한 사항의 처리에 가까울 수록 추상화 수준이 높다고 표현한다.
DDD에서 리포지토리와 애플리케이션 서비스를 비교하면 리포지토리가 더 추상화 수준이 낮은데, 애플리케이션 서비스 구현을 위해 리포지토리를 참고한다면 추상화 수준이 높은 모듈이 낮은 모듈에 의존하므로 의존 관계 역전 원칙을 위배한다.
이럴 때는 리포지토리 구현체 대신 인터페이스(추상 타입)을 만들고 애플리케이션 객체가 인터페이스를 참조하도록 하면 리포지토리 구현체가 RDBMS를 통해 데이터를 조회하든 NoSQL을 사용하든 상관 없게 되므로 의존성이 해소 된다.
주도권을 추상 타입에 둬라
앞에서 인터페이스는 구현체에 의존하지 않기 위해 사용되었다. 그런데 추상 타입(인터페이스)가 세부 사항(구현체)에 의존하게 되면 추상화 수준이 높은 모듈이 낮은 모듈에 의존하는 형태를 해소하기 위함이라는 추상 타입의 사용 목적을 무의미하게 만든다.
낮은 추상화 수준 모듈에서 일어난 변경 때문에 추상화 수준이 높은 모듈을 수정해야 하는 상황은 바람직하지 못하다.
의존 관계 제어 패턴
Service Locator 패턴
이름에 서비스가 들어가 있으나 DDD에서 말하는 도메인 서비스나 애플리케이션 서비스를 말하는 것은 아니다.
서비스 로케이터는 의존 해소가 필요한 객체의 위치를 미리 등록해 둔 객체로 참조가 일어나는 위치에 서비스 로케이터를 대신 참조하도록 하고 서비스 로케이터를 통해 필요한 인스턴스를 받아 사용하도록 하는 패턴이다.
장점과 단점
서비스 로케이터 패턴은 처음부터 커다란 설정을 만들 필요가 없기 때문에 최조 도입이 쉽다. 하지만 해당 패턴을 안티 패턴으로 보는 사람들도 있는데 그 이유는 다음과 같다.
- 의존 관계를 외부에서 보기 어렵다
- 테스트 유지가 어렵다
IoC Container 패턴
IoC (Inversion of Control) 컨테이너는 DI (Dependency Injection) 컨테이너라고도 불리며 의존 관계 주입을 통해 의존성을 해소시킨다.
의존 관계 주입이란 의존하는 모듈을 생성자 메소드를 통해 외부에서 인자로 주입하도록 하는 것이다. 의존할 객체 인스턴스를 외부에서 제어할 수 있기 때문에 유연성이 늘어난다.
하지만 단순 의존 관계 주입만으로는 의존하는 객체를 만드는 코드를 여기저기 반복해서 작성해야 하는 불편함이 있는데 이런 문제를 해결하기 위해 대신 인스턴스를 받아오는 DI 컨테이너를 사용하게 된다.