이런 정보는 쉽게 알 수 있으므로 생략한다.
이 2가지. 말 그대로 실제 활용에 대해서 포스팅하려고 한다.
그리고 무엇보다, 어려운 용어는 가능한 쓰지 않을 것이다.
DDD를 말하는 많은 포스팅들이 어렵기만한 용어로 가득차서 오히려 이해하기 어렵게 만든다.
완벽한 설명을 위해 써야하는 용어는 어쩔 수 없지만, 그저 복붙하거나 "내가 이 만큼 알고 있어요" 티를 내기 위한 글이 아닌 실제 설명을 위한 글을 지향한다.
보통 같이 등장하는 용어로는 유비쿼터스 렝귀지 / 도메인 전문가 이런 것들이 나오는데, 이걸 다- 풀어서 설명할 수 있다.
먼저, 도메인이라는 것은 '영역'을 말한다. 그러니 비즈니스상에서 도메인이란 '업무의 집합'이라고 봐야한다.
예를 들어서 스타벅스는 '커피' 도메인이고, 버거킹은 '음식' 도메인이다.
서브 도메인이라고 해서 더 구체적으로 쪼갤 수도 있지만, 가장 큰 틀에서 도메인의 의미는 위와 같다고 보면 된다.
그러면 한 IT기업이 업무를 해나가기 위해선 당연히 도메인에 대한 이해가 있어야한다.
도메인에 대한 이해가 있다는 말은 곧 지금 사원으로써 내 개인의 할일이 아니라, 회사가 활동하는 영역이 어떤 것인지, 그리고 회사가 지향하는 비즈니스 가치가 무엇인지를 파악하고 있다는 말과 같다.
때문에 '당연히'라는 말을 사용한 것이다. 도메인에 대한 이해가 있어야 개발이 편해진다.
그러나 개발자 입장에서 경력도 제각각 다르고 지금까지 개발해온 환경도 제각각 다른 사람들이 모여서 협업을 하는데, 지금 회사의 도메인에 대한 이해가 들쑥날쑥 일 것은 분명하다.
하지만 반대로 기획자라면 해당 서비스를 기획한 입장에서 도메인에 대한 이해가 적어도 개발자 보다는 높다고 볼 수 있다.
여기선 구체적으로 '기획자'라고 단정지었지만, 이렇듯 도메인에 대한 이해가 높은 직군 또는 사람을 단순히 '도메인 전문가'라고 표현한다.
결국 DDD의 핵심 가치는 '도메인 전문가'와 '소프트웨어 엔지니어'가 서로 '보편적인(유비쿼터스)' 표현으로 기획부터 개발까지 이르는 길을 구체화 시키는 과정에 모두가 참여한다는 것이다.
이렇게 되면 파생되는 장점들은 굳이 말을 안해도 떠오르는게 한 둘이 아닐테니,,
풀어서 설명했던 걸, 다시 묶어서 어려운 용어로 정의내리면
소프트웨어 엔티티와 도메인 컨셉을 항상 함께 움직이는 구조의 모델로써 가능한 가까이 일치시키는 것이다.
이것 또한 DDD를 각기 다른 방향으로 제시하는 커뮤니티가 많아지면서 아주 구체적인 부분에서는 세분화 되기도 하고, 같은 방식이지만 다른 말로 표현하기도 하더라.
때문에 나는 가장 '기본과정'을 기반으로 설명하기로 했다.
사진으로 보는 것처럼, 이벤트 스토밍이란 건 위에서 언급했던 도메인 전문가와 개발자들이 함께 모여 설계를 고민하는 방법이다.
그럼 이벤트 스토밍이라는건 대체 어떤 방식으로 진행되는지, 구체적인 프로세스를 보자.
아래의 내용에 대해 사전지식으로써 먼저 알아야할 것!
많은 포스팅에서 Aggregate를 아주 어렵게 표현한다.
사실은 그닥 어려운 개념이 아니다.
하나의 큰 카테고리로 묶을 수 있으면 그게 곧 Aggregate가 된다.
사전적 정의는 '집합'이며 여기선 '연관된 엔티티와 Value Object의 묶음'이라고 말한다.
특징은 느슨한 연관관계로 묶여있다는 것이다.
위의 사진을 통해 좀 더 이해할 수 있을텐데, 단순히 엔티티 하나가 애그리게이트 하나와 1:1 매핑하는 것이 아니라, 위처럼 여러개의 엔티티일 수 있다는 것에 주의하자.
바운디드 컨텍스트는 애그리게이트보다 좀 더 큰 개념이다.
컨텍스트의 사전적 의미인 '문맥'처럼 특정 도메인 모델에 속하는 문맥들을 묶어주는 것이다.
좀 더 구체적으로는 서브 도메인의 모델의 집합이라고 볼 수 있다.
이러한 바운디드 컨텍스트를 잘 활용하기 위해선 지켜져야할 조건이 있다.
각 바운디드 컨텍스트를 한 팀에서 개발 및 관리를 해야한다는 것이다.
즉 사내의 한 팀이 하나의 바운디드 컨텍스트를 맡는 팀이 되는 것이다.
하나의 팀이 여러개의 바운디드 컨텍스트를 가질 수도 있지만 가장 추천되는 것은 1:1 매핑이다.
실제 컨텍스트맵의 구성은 위와 같다.
U는 업스트림을 의미하고 D는 다운스트림을 의미한다. 즉 방향 표시다.
하지만 캡쳐본에서 보는 것처럼, 보리스 다이어그램을 사용할 경우 표현 방식이 약간은 다르다.
여기까지 큰 싸이클을 한번 도는 과정을 캡쳐해서 설명했다.
이벤트 스토밍 단계에서 커맨드, 이벤트, 애그리게이트, 외부 시스템 외에도 4가지 설계 용어가 더 존재한다.
1. 액터: 개인 또는 조직의 역할
2. 핫스팟: 의문사항
3. 정책: 이벤트 조건에 따라 진행되는 결정
4. 정보: 액터에게 제공되는 데이터, 결정을 내리는데에 영향을 준다.
예를 들면 보라색 포스트잇으로 붙어있는 의문사항은 핫스팟이 된다.
그러나 가장 중요한건 위에서 하나씩 설명한 4가지이다.
위와 같은 예시가 최종 모습이다!!
위에서 DDD를 지켜가며 설계하는 과정을 봤다면, 이제는 실제 개발자로써 DDD를 적용했을 때 코드가 뭐가 달라지는 지 봐야한다.
먼저 지켜야할 규칙.
JPA를 알고 사용한다고 가정한다. 따로 설명하지 않은 용어중에 모르는 용어가 있다면 JPA를 모르는 것..
DDD로 코드를 구현할때 기본이 되는 레이어드 아키텍쳐.
코드를 레이어로 구분하는데, 프레젠테이션 / 어플리케이션 / 도메인 / 인프라 이렇게 4계층으로 나뉜다.
사용자의 요청을 해석하고 응답을 책임진다.
@RestController
public class MyController {
private final CallService callService;
@GetMapping("/callme")
public Response callMeASAP(){
return Response.success(callService.call());
}
}
간단한 예시로 컨트롤러처럼 요청을 받아서 던져주고 응답을 해주는 것이 'Presentation' Layer 라고 할 수 있다.
비즈니스 로직을 정의해서 도메인 계층과 인프라 계층을 연결해주는 역할.
@Service
public class MyService {
private final MyRepository myRepository;
@Transactional(readonly = true)
public Response exam(){
ExamDTO examDTO = myRepository.findExam();
return new ResponseDTO(examDTO);
}
}
중요한건 정보를 많이 가져선 안된다는 것으로, 실제 데이터 변화는 도메인 계층에 위임해야 한다.
응용 계층에서 하는 일을 나열해보면
정도가 있다.
비지니스 규칙과 정보에 대한 실제 도메인 정보를 가지고 모든 것을 책임지는 계층.
@Entity
public class MySelf {
private Long id;
... 대충 컬럼들 생략..
public void stateChange(String name) {
if(String.isEmpty(name)){
throw new IllegalArgumentException("name 파라미터가 비어있다.");
}
this.name = name;
}
}
아까 설계하는 과정에서 봤던 것처럼 도메인은 비즈니스를 구성하는 영역이기 때문에 엔티티도 있고 여러가지 서비스들이 존재한다.
여기선 하나의 Entity로 설명한다.
도메인의 핵심은 '상태제어'다.
때문에 위에서는 컬럼들 아래에 실제 특정 값을 변경하는 로직을 구현함으로써 목적을 달성했다.
이렇게 하면 계층간의 책임 분리가 됨으로 최종적으로는 코드 간결성이 유지된다.
상위 계층을 지원하는 일반화된 기술적 기능을 제공하는 계층.
public interface MyRepository extends JpaRepository<User, Long> {
}
이런식으로 JPA 연결을 해둔 것도 이 코드를 통해서 DB에 접근하는 것임으로 인프라 계층에 속한다고 할 수 있다.
결국 인프라 계층은 외부 시스템을 호출하는 역할에 주로 쓰인다.
그리고 얻어온 데이터를 도메인 계층으로 전달하는 것까지가 임무다.
최대한 응집해서 쓰려다 보니 내용이 좀 길어졌는데,,,,
관련해서 CQRS나 육각 아키텍쳐, 클린 아키텍쳐 같은 건 시간을 두고 공부해가면서 업로드 해야겠다..
피보탈 영상 링크
https://youtu.be/QUMERCN3rZs
DDD in Code 링크
https://youtu.be/aZAEjVFpU1s