서론
자바봄 스터디에서 DDD를 지향하며 프로그래밍하는 방법을 "연습"하고 있지만 누군가 DDD가 뭐냐고 물어보면 둥둥 떠다니는 개념을 설명하기가 어려웠습니다. 그러던 중 조영호님의 우아한 객체지향을 스터디원이랑 같이 정리하며 들을 기회가 있었고, 그때 어렴풋이 이해가 가는 느낌이 들었습니다.
조금 더 개념을 잡을 기회가 없을까 하다가 예전부터 들을까했지만 DDD를 아예 모르겠어서 포기했던 우아한형제들 박재성(Jason)님의 나홀로 DDD를 듣기로 했습니다. 4시간씩 이틀동안 진행되는 강의기 때문에 시간부담도 없고, 목차를 보니 알고 싶은 내용들도 어느정도 다루는 것 같았습니다.
https://www.fastcampus.co.kr/courses/202405
목차는 아래와 같습니다.
본론
모든 강의 내용을 정리할 수는 없고 제 기억에 남는, 그리고 자주 필요할 것 같은 개념들은 정리해두려고 합니다.
첫날은 도메은주도개발의 배경, 그리고 구성하는 "용어"에 대한 설명이 주를 이루었습니다. 제가 DDD를 어려워했던 이유도 용어들이 많이 어려워서가 컸는데 강의를 통해 중요한, 자주 쓰이는 용어들은 어느정도 잡게 된 것 같아 좋았습니다 :)
평소 업무에 DDD를 도입하고 있는 스터디멤버에게 DDD에 대한 설명을 들으면 "비즈니스 로직을 도메인에 녹이고, 그렇게 해서 기획과 코드를 일치시킬 수 있다"라고 말해주었습니다. 당시에는 아 그렇구나 했는데 강의를 통해 다시 정리할 수 있었습니다.
등장배경
기존의 개발은 DB모델링에 의존하였습니다. 클래스는 곧 Table 그 자체였고 그에따라 스키마가 변경되면 코드를 잔뜩 뜯어고쳐야 했습니다.
그뿐 아니라 도메인전문가와의 소통에도 좋지 않았습니다. 도메인 전문가가 보기에 A라는 도메인이 a라는 로직을 수행해야 자연스러운데 개발자의 코드에는 A 도메인의 값을 다 꺼내와서 외부에서 작업한 뒤 A에게 set 해주고 있었으니까요.
제가 처음 스프링프레임워크를 공부했을 때가 생각났습니다. 약간 과장되긴했지만 Repository에서 조회하고 set해서 다시 Update하는 로직을 반복했습니다.
public class BoardServiceImpl{
@Autowired
private BoardRepository boardRepository;
@Transactional
public void modifyContents(Long id, String content){
Board article = boardRepository.findById(id);
article.setContent(content);
boardRepository.updateArticle(article);
}
}
이렇게 주요한 비즈니스로직을 서비스레이어에서 처리하다보니 정작 도메인인 Board 객체는 상태와 Getter,Setter 뿐이었습니다. 뿐만아니라 Board를 조회하는 로직이 BoardService에만 존재하지 않습니다. 여기저기 Board는 흩어져있고, 중복코드도 난무했습니다.
이런 도메인 모델을 Anemic Domain Model(빈약한 도메인 모델)이라고 합니다. 그리고 자연스레 서비스는 무거워지고(Big Service Layer) 온갖 중복코드를 만들어냅니다.
그런 배경속에서 도메인 주도개발이 등장하게되었습니다.
도메인주도개발
그래서 등장한 것이 도메인주도개발입니다. 도메인 전문가들이 알고있는 도메인 모델을 코드로까지 확장하는 것입니다.
여기서 유비쿼터스 언어가 등장하게 되는데, 유비쿼터스의 뜻에서도 짐작할 수 있듯이 누구나 이해할 수 있는 언어를 사용하라는 의미인데요, 도메인 전문가들의 용어를 구현까지 확장하는 것이 "도메인 주도 개발"의 핵심요소 중 하나입니다. 여기에서 스터디 멤버의 "기획자와의 소통을 빠르게 한다"의 의미를 드디어 이해했습니다.
도메인 주도 설계 아키텍처
DDD에서 비즈니스로직, 즉, 도메인전문가의 관심이 되는 로직은 "도메인", 또는 "도메인패키지"에서 수행해야합니다.
레이어 아키텍처 중 도메인레이어가 해당이 될 것 같습니다. 레이어아키텍처하니 좋은 세미나가 생각나서 추천하고 넘어가겠습니다 총총 ,,
https://www.youtube.com/watch?v=26S4VFUWlJM
도메인 모델
도메인모델은 상태(필드)와 행동(메서드)를 가지도록 설계되어야합니다. 객체지향의 사실과 오해를 읽으며 눈이 빠지게 반복해서 봤던 내용이어서 익숙했습니다. 익숙하지만 능숙하게 적용하기는 쉽지 않다고 늘 생각합니다. ㅎㅎ
도메인모델은 VO(Value Object)와 Entity로 나누어질 수 있습니다.
VO의 개념은 아래 포스팅 하단에 잘 설명되어있습니다. 이직준비할 때 큰 도움이 되었던 포스팅이기도 합니다 :)
https://d2.naver.com/news/3435170
Entity는 Spring-data-jpa를 사용하며 많이 접했던 용어인데요, 솔직히 jpa 용어인줄 알았습니다 (ㅋㅋ)
강의에서는 Entity를 다음과 같이 정의했습니다
- 기본적으로 객체는 불변이다. (VO)
- 하지만 때에따라 변화가 필요할 수 있다.
- 변화가 되었지만 그 변화를 추적해야할 필요가 있을 때 사용하는 것이 필요하다.
- 그래서 다른 데이터지만 같은 값임을 감지할 필요가 있을 때는 가변객체로 만들어줄 수 있는데 이것을 Entity라고 한다.
- 다시말해 식별자를 가진 모델을 칭한다.
어느 면접에서 Entity를 정하는 기준에 대한 질문을 받았고 대답을 잘 못했는데 여기에 답이 있었습니다 ,, ㅎㅅㅎ
도메인
수많은 도메인(Entity, VO)는 개별적으로 관리될 수 없습니다. 어떤 특정한 군집으로 관리되어야 하는데요, 그 군집을 Aggreegate라고 합니다. (한국말로는 흔히 애그리거터라고 하는 것 같습니다.)
Aggreegate
애그리거터는 제가 가장 어려워했던 개념입니다. 애그리거터, 애그리거터 루트,.. 이게 다 뭔가 했는데 생각보다 단순했습니다.(하지만 실제는 단순하지 않겠지요 ㅠ^ㅠ)
그렇다면 애그리거터는 어떻게 묶냐?
- 동일한 라이프사이클을 가지는 도메인끼리
- 같이 생성되고, 같이 변경되고, 같이 삭제되고
- 코드를 깊이 보고 판단하기보다는 거시적으로 "소프트웨어"를 바라보고 결정해야 한다. 몇발작구 떨어져서 소프트웨어를 바라보자. --> 개인적으로 가장 어려웠습니다. 이건 정말 수많은 실전을 거듭해야 숙련되지 않을까 싶습니다.
우아한 객체지향에서 패키지를 나눌 때 나온 이야기와도 일맥상통 했는데요, 제 필기에도 그런 멘트가 들어갔습니다 ㅋ_ㅋ
그리고 그 이 애그리거트를 대표하는 엔티티를 애그리거트 루트(Root Entity)라고 합니다. 대표라고 하니까 굉장히 추상적이었는데, 특정 엔티티만 통하면 어느 엔티티든 다 접근할 수 있다면 그게 애그리거트 루트다 라는 설명이 가장 와닿았습니다.
그리고 서로 다른 애그리거트간 참조는 "간접참조"를 권합니다. 김영한님의 JPA 강의를 듣고 직접참조였던 OneToOne, OneToMany 관계의 엔티티를 싹 다 id 를 통한 간접참조로 바꿨던 경험이 생각났습니다. 이전 방식은 편했지만 편한만큼 얼마든지 참조할 수 있어 위험한 시스템이지 않았나 싶습니다.
리포지터리
개인적으로 오 그렇구나! 했던 대목이었는데요, 저는 습관적으로 1 Entity : 1 Repository 를 가지는 방식을 택했었습니다. 딱히 이유는 없었습니다.
리포지토리는 애그리거트 단위로 존재하는 것이 좋다고합니다. 그도 그럴것이 외부에서 바라보는 도메인을 애그리거트 루트로 기껏 설계해놓고 리포지터리를 하나하나 만들어놓으면 말짱 도루묵일 것 같습니다.
도메인서비스
예전에 스터디 때 멤버 한명이 되게 자세히 설명해줬었는데 솔직히 이해를 1도 못했었습니다. 그땐 도메인이 뭔지도 잘 몰랐고, 아예 기반이 없던 상태였기 때문인데, 강의를 들으며 새록새록 생각났습니다.
특정 비즈니스로직은 여러 애그리거트를 참조해야 할 수 있습니다. 이때 하나의 중심이 되는 애그리거트가 이 비즈니스로직을 수행하게 될텐데요, 이렇게 하면 이 애그리거트는 수많은 애그리거트와의 "참조"를 가지게 됩니다.
이런 경우에 도메인도 지키고 서비스레이어도 지킬 수 있는 방법이 "도메인서비스" 입니다.
도메인과 관련된 서비스로직을 도메인서비스라는 도메인레이어에서 수행하는 것입니다. 클라이언트의 관심사는 애플리케이션영역, 그리고 서비스레이어영역까지입니다.(애플리케이션 영역과 서비스레이어영역은 같은 영역이라는 피드백을 주셨습니다 :)) 클라이언트가 아닌 도메인전문가의 관심이되는 도메인비즈니스 로직을 도메인 서비스로직으로 분리하는 것은 강의 내내 언급하셨던 일종의 "트레이드오프"가 아닐까 싶습니다.
여느 강의를 들어도 늘 한번씩은 언급되는 말인 "때로는 절차지향이 나을수도 있다"는 이 대목에서도 언급되었습니다.!
마무리
교육 후기는 처음이라 ,,? 후기랑은 좀 멀어진 것 같기도 합니다. ㅎㅅㅎ 두고두고 보기 위해서 가장 인상깊었던, 알고싶었던 개념 정리 위주로 기록하는 바입니다 !
그동안 도메인주도개발을 지향하려고 노력하지만 개념이 덜 잡혀있다는 생각이 들어서 수강하게 된 강의였습니다. 그동안 정확히 이해하지 못했던 개념들을 이해할 수 있었던 시간이었습니다. 후기로 남기진 않았지만 절반정도(두 번째날)는 실습시간을 가졌습니다. SpringBoot, JPA 에 대한 기본적인 설명과 함께 DDD에 기반한 간단한 프로그램 구현이었습니다. 스터디 클린코드 과제로 했던 방식과 비슷한 점이 많아서 그동안 아주 잘못하고 살진 않았구나(?) 하기도 했습니다. 반면, 그동안 테스트코드 작성에 부족함을 많이 느꼈는데 그 부분에 대해서도 같은 피드백(테스트 코드도 끊임없이 유지보수를 해야하며 중복을 없애야한다)을 또 받아서 아쉬웠습니다 ㅠㅠ 이번 넥스트스탭 TDD 신청하길 천만 다행이네요!
이틀, 8시간의 짧은 강의였고 수강생의 레벨이 천차만별이다보니 아주 기초적인 부분부터 심화된 내용까지 폭넓게 들을 수 있었습니다. 미친듯이 깊은 강의가 될 수는 없었지만 도메인 주도개발을 해보고싶다! 뭔지 다시한번 생각해보고싶다! 내가 하고있는게 도메인주도개발이 맞는것인가!(이건 저) 에 해당한다면 가성비가 매우 높은(?) 강의라고 확신합니다 !
아 제가 제대로 이해하질 못해서 언급은 못했지만 "전략적 설계"부분은 개인적으로 깊이 공부할 필요가 있지 않나 싶었습니다. Bounded Context는 많이 어렵군요 ㅠㅠ
'책, 강의 정리' 카테고리의 다른 글
스프링프레임워크 입문 (0) | 2020.04.04 |
---|