도메인 주도 설계(DDD)를 설명해보다.

Junyeong·2022년 6월 3일
17

설명해보다

목록 보기
7/7

  • DDD를 왜 적용해야 하는가.
  • DDD의 장점은 무엇인가.
  • DDD의 단점은 무엇인가.

    이런 정보는 쉽게 알 수 있으므로 생략한다.

지금부터는

  • DDD를 실제로 어떻게 하는가.
  • DDD를 적용하는 코드는 어떤것이고 어떻게 구현하는가.

    이 2가지. 말 그대로 실제 활용에 대해서 포스팅하려고 한다.

그리고 무엇보다, 어려운 용어는 가능한 쓰지 않을 것이다.
DDD를 말하는 많은 포스팅들이 어렵기만한 용어로 가득차서 오히려 이해하기 어렵게 만든다.
완벽한 설명을 위해 써야하는 용어는 어쩔 수 없지만, 그저 복붙하거나 "내가 이 만큼 알고 있어요" 티를 내기 위한 글이 아닌 실제 설명을 위한 글을 지향한다.


도메인 주도 설계 (DDD)

  • 도메인 모델을 중심에 두고 설계하는 방식을 말한다.

보통 같이 등장하는 용어로는 유비쿼터스 렝귀지 / 도메인 전문가 이런 것들이 나오는데, 이걸 다- 풀어서 설명할 수 있다.

먼저, 도메인이라는 것은 '영역'을 말한다. 그러니 비즈니스상에서 도메인이란 '업무의 집합'이라고 봐야한다.
예를 들어서 스타벅스는 '커피' 도메인이고, 버거킹은 '음식' 도메인이다.
서브 도메인이라고 해서 더 구체적으로 쪼갤 수도 있지만, 가장 큰 틀에서 도메인의 의미는 위와 같다고 보면 된다.

그러면 한 IT기업이 업무를 해나가기 위해선 당연히 도메인에 대한 이해가 있어야한다.
도메인에 대한 이해가 있다는 말은 곧 지금 사원으로써 내 개인의 할일이 아니라, 회사가 활동하는 영역이 어떤 것인지, 그리고 회사가 지향하는 비즈니스 가치가 무엇인지를 파악하고 있다는 말과 같다.

때문에 '당연히'라는 말을 사용한 것이다. 도메인에 대한 이해가 있어야 개발이 편해진다.

그러나 개발자 입장에서 경력도 제각각 다르고 지금까지 개발해온 환경도 제각각 다른 사람들이 모여서 협업을 하는데, 지금 회사의 도메인에 대한 이해가 들쑥날쑥 일 것은 분명하다.
하지만 반대로 기획자라면 해당 서비스를 기획한 입장에서 도메인에 대한 이해가 적어도 개발자 보다는 높다고 볼 수 있다.
여기선 구체적으로 '기획자'라고 단정지었지만, 이렇듯 도메인에 대한 이해가 높은 직군 또는 사람을 단순히 '도메인 전문가'라고 표현한다.

결국 DDD의 핵심 가치는 '도메인 전문가'와 '소프트웨어 엔지니어'가 서로 '보편적인(유비쿼터스)' 표현으로 기획부터 개발까지 이르는 길을 구체화 시키는 과정에 모두가 참여한다는 것이다.

이렇게 되면 파생되는 장점들은 굳이 말을 안해도 떠오르는게 한 둘이 아닐테니,,

풀어서 설명했던 걸, 다시 묶어서 어려운 용어로 정의내리면

소프트웨어 엔티티와 도메인 컨셉을 항상 함께 움직이는 구조의 모델로써 가능한 가까이 일치시키는 것이다.


DDD를 하기 위한 '함께'의 과정

이것 또한 DDD를 각기 다른 방향으로 제시하는 커뮤니티가 많아지면서 아주 구체적인 부분에서는 세분화 되기도 하고, 같은 방식이지만 다른 말로 표현하기도 하더라.
때문에 나는 가장 '기본과정'을 기반으로 설명하기로 했다.

이벤트 스토밍 + 바운디드 컨텍스트 + 컨텍스트 맵

사진으로 보는 것처럼, 이벤트 스토밍이란 건 위에서 언급했던 도메인 전문가와 개발자들이 함께 모여 설계를 고민하는 방법이다.
그럼 이벤트 스토밍이라는건 대체 어떤 방식으로 진행되는지, 구체적인 프로세스를 보자.

아래의 내용에 대해 사전지식으로써 먼저 알아야할 것!

  • 여러 색상의 포스트잇과 큰 벽이 필요하다.
  • 커맨드, 애그리게이트 등을 서로 다른 색상의 포스트잇으로 붙인다.
  • 짧은 시간동안 인텐시브하게 진행하기 위해 모두 서서 진행한다.
  • 아래에서 회원가입 하는 과정을 이벤트 스토밍의 예시로 살펴볼 것이다. (Feat. Pivotal)

  • 파란색은 커맨드를 의미한다.
  • 커맨트란 일종의 트리거와 같은데, 사용자가 회원가입을 하겠다고 클릭했다는 뜻이다.
  • 트리거와 같은 의미임으로 주로 '요청'에 파란색이 쓰인다고 볼 수 있다.

  • 두번째로 주황색은 이벤트를 의미한다.
  • 사용자가 위에서 회원가입링크를 선택했으니 가입 폼의 데이터를 채워서 제출했을 것이다.
  • 때문에 사용자의 데이터가 입력되었다는 이벤트가 발생하였다.
  • 이벤트는 주로 상태변경, Notification에 쓰이며 과거형 수동형 문장으로 쓴다.

  • 데이터 입력을 완료하였으니 실제 리퀘스트를 명령(커맨드)하게 된다.

  • 그러면 그 결과로 사용자가 생성 될 수 있고,

  • 반대로 사용자 생성이 실패할 수도 있다.
  • 때문에 여기서는 이벤트를 위아래로 배치해서 or 조건임을 명시한다.

  • 그리고 생성에 성공했다면 생성했다는 알림을 전송하게 될텐데 이 또한 이벤트에 해당한다.

  • 그러나 보통 알림을 메일로 전송한다고 하면 외부 프로토콜을 호출하게 된다.
  • 메일 서버가 내부에 구현되어 있더라도, 지금 서비스의 외부의 것이라면 '외부'라고 여긴다.
  • 그리고 외부에 호출하는 것은 모두 핑크색으로 표현한다.

  • 마지막으로 회원가입에 성공하면 로그인으로 화면이 넘어갈 것이다. (이벤트)

  • 이제부터가 중요하다.
  • 알림을 전송하고 외부 SMTP 프로토콜을 사용해서 메일을 쏘는 일은 '사용자'와는 관련이 없는 일이다.
  • 때문에 '알림전송' 포스트잇과 '외부 SMTP' 프로토콜을 모두 다른곳으로 옮기고 '사용자'와 관련된 것만 남긴다.

  • 그리고 나면 여기서 노란색 포스트잇으로 'Aggregate'를 표현한다.

    많은 포스팅에서 Aggregate를 아주 어렵게 표현한다.
    사실은 그닥 어려운 개념이 아니다.
    하나의 큰 카테고리로 묶을 수 있으면 그게 곧 Aggregate가 된다.
    사전적 정의는 '집합'이며 여기선 '연관된 엔티티와 Value Object의 묶음'이라고 말한다.
    특징은 느슨한 연관관계로 묶여있다는 것이다.

위의 사진을 통해 좀 더 이해할 수 있을텐데, 단순히 엔티티 하나가 애그리게이트 하나와 1:1 매핑하는 것이 아니라, 위처럼 여러개의 엔티티일 수 있다는 것에 주의하자.

  • 애그리게이트를 설정하고 나면 그 다음 등장하는 용어가 '바운디드 컨텍스트'다.
  • 실제 벽에 파란 줄의 테이프로 표시하고 있다.

바운디드 컨텍스트는 애그리게이트보다 좀 더 큰 개념이다.
컨텍스트의 사전적 의미인 '문맥'처럼 특정 도메인 모델에 속하는 문맥들을 묶어주는 것이다.
좀 더 구체적으로는 서브 도메인의 모델의 집합이라고 볼 수 있다.
이러한 바운디드 컨텍스트를 잘 활용하기 위해선 지켜져야할 조건이 있다.
각 바운디드 컨텍스트를 한 팀에서 개발 및 관리를 해야한다는 것이다.
즉 사내의 한 팀이 하나의 바운디드 컨텍스트를 맡는 팀이 되는 것이다.
하나의 팀이 여러개의 바운디드 컨텍스트를 가질 수도 있지만 가장 추천되는 것은 1:1 매핑이다.

  • 그 다음 등장하는 것이 위의 캡쳐와 같은 컨텍스트 맵이다.
  • 이번엔 바운디드 컨텍스트를 더 확장시킨 개념이라고 보면 된다.
  • 컨텍스트 맵의 핵심은 상호 교류하는 시스템의 목록을 제공하는 것이다.
  • 때문에 방향 표시가 중요하다.
  • 위의 캡쳐는 정확히 말해서 '보리스 다이어그램'이다. (컨텍스트 맵을 표기하는 여러 방법론중 하나)
  • 보리스에서는 비동기와 동기를 구별해서 표기하는데, 빨간줄은 비동기 호출일 경우이고 파란 줄은 동기 호출일 경우다.

    실제 컨텍스트맵의 구성은 위와 같다.
    U는 업스트림을 의미하고 D는 다운스트림을 의미한다. 즉 방향 표시다.
    하지만 캡쳐본에서 보는 것처럼, 보리스 다이어그램을 사용할 경우 표현 방식이 약간은 다르다.

  • 마지막은 Snap-E 라는 과정이다.
  • 여기서는 포스트잇 색상의 의미가 이전 단계들과 다르다.
  • 포스트잇의 색상 의미 보다는 실제 API, DATA 등 표기해둔 문자로 구분한다.
  • Snap-E 과정을 통해 하나의 서비스가 가지게 될 API와 유저 흐름 등을 정리해둘 수 있게 된다.

여기까지 큰 싸이클을 한번 도는 과정을 캡쳐해서 설명했다.

이벤트 스토밍 단계에서 커맨드, 이벤트, 애그리게이트, 외부 시스템 외에도 4가지 설계 용어가 더 존재한다.
1. 액터: 개인 또는 조직의 역할
2. 핫스팟: 의문사항
3. 정책: 이벤트 조건에 따라 진행되는 결정
4. 정보: 액터에게 제공되는 데이터, 결정을 내리는데에 영향을 준다.


예를 들면 보라색 포스트잇으로 붙어있는 의문사항은 핫스팟이 된다.
그러나 가장 중요한건 위에서 하나씩 설명한 4가지이다.

위와 같은 예시가 최종 모습이다!!


DDD를 코드로 풀어보면!

위에서 DDD를 지켜가며 설계하는 과정을 봤다면, 이제는 실제 개발자로써 DDD를 적용했을 때 코드가 뭐가 달라지는 지 봐야한다.

먼저 지켜야할 규칙.

  • 도메인 객체는 게터와 세터를 넣지 않는다.
  • Value Object는 불변 객체로 사용한다.

JPA를 알고 사용한다고 가정한다. 따로 설명하지 않은 용어중에 모르는 용어가 있다면 JPA를 모르는 것..

Layered Architecture

DDD로 코드를 구현할때 기본이 되는 레이어드 아키텍쳐.

코드를 레이어로 구분하는데, 프레젠테이션 / 어플리케이션 / 도메인 / 인프라 이렇게 4계층으로 나뉜다.

Presentation [표현 계층]

사용자의 요청을 해석하고 응답을 책임진다.

@RestController
public class MyController {

	private final CallService callService;
    
    @GetMapping("/callme")
    public Response callMeASAP(){
    	return Response.success(callService.call());
    }
}

간단한 예시로 컨트롤러처럼 요청을 받아서 던져주고 응답을 해주는 것이 'Presentation' Layer 라고 할 수 있다.

Application [응용 계층]

비즈니스 로직을 정의해서 도메인 계층과 인프라 계층을 연결해주는 역할.

@Service
public class MyService {

	private final MyRepository myRepository;
    
    @Transactional(readonly = true)
    public Response exam(){
    	ExamDTO examDTO = myRepository.findExam();
        return new ResponseDTO(examDTO);
    }
}

중요한건 정보를 많이 가져선 안된다는 것으로, 실제 데이터 변화는 도메인 계층에 위임해야 한다.
응용 계층에서 하는 일을 나열해보면

  • 트랜잭션 관리
  • DTO 변환
  • 모듈간의 연계

정도가 있다.

Domain [모델 계층]

비지니스 규칙과 정보에 대한 실제 도메인 정보를 가지고 모든 것을 책임지는 계층.

@Entity
public class MySelf {
	private Long id;
    
    ... 대충 컬럼들 생략..
    
    public void stateChange(String name) {
    	if(String.isEmpty(name)){
        	throw new IllegalArgumentException("name 파라미터가 비어있다.");
        }
        this.name = name;
    }
}

아까 설계하는 과정에서 봤던 것처럼 도메인은 비즈니스를 구성하는 영역이기 때문에 엔티티도 있고 여러가지 서비스들이 존재한다.
여기선 하나의 Entity로 설명한다.

도메인의 핵심은 '상태제어'다.
때문에 위에서는 컬럼들 아래에 실제 특정 값을 변경하는 로직을 구현함으로써 목적을 달성했다.
이렇게 하면 계층간의 책임 분리가 됨으로 최종적으로는 코드 간결성이 유지된다.

Infra [인프라 계층]

상위 계층을 지원하는 일반화된 기술적 기능을 제공하는 계층.

public interface MyRepository extends JpaRepository<User, Long> {

}

이런식으로 JPA 연결을 해둔 것도 이 코드를 통해서 DB에 접근하는 것임으로 인프라 계층에 속한다고 할 수 있다.
결국 인프라 계층은 외부 시스템을 호출하는 역할에 주로 쓰인다.
그리고 얻어온 데이터를 도메인 계층으로 전달하는 것까지가 임무다.


DDD in Code

  • 코드 마지막 부분이 짤리긴 했지만,,, 실제 DDD 적용해서 얻는 코드의 이점을 표시한 내용이다.
  • 우선 매직 넘버를 줄인다던지 하는 것들은 클린코드 기반한 내용이라고 생각하고
  • 그 외에도 역할분리와 책임분리 덕분에 코드가 간결해지는 걸 확인할 수 있다.

최대한 응집해서 쓰려다 보니 내용이 좀 길어졌는데,,,,
관련해서 CQRS나 육각 아키텍쳐, 클린 아키텍쳐 같은 건 시간을 두고 공부해가면서 업로드 해야겠다..

피보탈 영상 링크
https://youtu.be/QUMERCN3rZs

DDD in Code 링크
https://youtu.be/aZAEjVFpU1s

profile
좋아하는 것을 계속 좋아하자.

0개의 댓글