Search

도메인 모델 패턴과 Cabi 구조에 대한 고민

태그
Java
Spring
DB
분류
디자인패턴
생성 일시
2024/02/05 11:14
프로젝트
Cabi

글을 쓰게된 이유

백엔드 개발 초기에 공부하기 위해 들었던 Inflearn 김영한 강사님의 실전! 스프링부트와 JPA 활용이라는 강의 최근 강의를 다시 들으며 그동안 잊고 있었던 것은 없는지 복습하게 되었다.
강의 내용 중 비즈니스 로직의 작성에 관련된 패턴인 도메인 모델 패턴트랜잭션 스크립트 패턴을 소개한다. 이를 듣고 보니, 내가 몰랐던 두 개념에 대해서 궁금해져 이를 글로 정리 하게 되었다.
이렇게 도메인 모델 패턴과 트랜잭션 스크립트 패턴에 대해 글로 정리하고 보니, 기존의 Cabi 코드에서 이해가 가지 않던 부분이나 이전에 겪었던 불편한 경험들의 원인에 대해 얼추 짐작할 수 있게 되었다. 물론 이러한 추측이 틀릴 수 있고 이후 다시 보게 되었을 때 전혀 맞지 않는 엉터리일 수도 있지만, 그럼에도 이를 생각해보고 더 좋은 방법이 없었을까 고민해보면서 성장한다고 생각하기 때문에 글로 정리해보고자 한다.

Cabi의 코드의 트랜잭션 스크립트 패턴

Cabi의 코드 패턴과 테스트 코드 작성

이전에 Cabi에서 단위 테스트 코드를 작성할 때, Mock을 통해 작성한 적이 했었다. 대충 당시 코드 상황을 예를 들자면 다음과 같다.
// 비즈니스 로직 public void changeStatus(Long cabinetId, CabinetStatus status) { Cabinet cabinet = CabinetRepository.findById(cabinetId); ... // 검증 로직들 cabinet.changeStatus(status); } // 테스트 코드 @Mock CabinetRepository cabinetRepository; @Mock CabinetService cabinetService; public void changeStatusTest() { // given Long cabinetId = 1L; CabinetStatus status = CabinetStatus.FULL; Cabinet cabinet = Cabinet.of(...); given(cabinetRepository.findById(cabinetId)).willReturn(cabinet); ... // when cabinetService.changeStatus(status); // then then(cabinet).should().changeStatus(status); }
Java
복사
정확하지는 않지만 이와 같은 흐름으로 작성되었었다. 이처럼 테스트 코드는 비즈니스 로직 흐름을 따라가면서 호출 되는 메서드나 객체들에 대해 Mock으로 주입 하여 대신 응답을 넣어주는 식으로 테스트를 작성했었다.
이러한 과정으로 테스트 코드를 작성하다보니, 필요한 동작을 Mock으로 내가 만들면서 그 결과를 그대로 받아 assert로 검증하는 꼴이였다. 그냥 내가 필요한 동작을 넣어서 그대로 응답이 오는걸 받는데, 이렇게 테스트 하는게 무슨 의미가 있지? 라는 의문이 들었었다.
테스트 코드 작성 당시에는 공부가 지금보다 부족하기도 했고, 동아리원 다 같이 작성하는 중이여서 그러려니하고 넘어갔다. 하지만 김영한 강사님의 강의에서는 단위 테스트가 정말 좋고 중요함을 강조하며, 그 중 Mock을 잘 활용하여 순수 Java로만 작성된 단위 테스트가 좋은 테스트임을 이야기하는 것을 듣고 이를 다시 생각해보게 되었다.
강의에서는 도메인 모델 패턴으로 코드를 작성하는데, 반면 Cabi는 트랜잭션 스크립트 패턴으로 작성되어 있다. 강의처럼 도메인 모델 패턴으로 작성하여 엔티티 위주로 비즈니스 로직이 작성되어 있는 구조에서는, 각 엔티티 내부의 로직을 하나하나 확인하기 어려우니 Mock 객체를 통해 테스트하는 것이 큰 의미를 가질 수 있겠다는 생각이 들었다. 이러한 차이를 인지하고 나니, 단위 테스트가 좋다고들 하는데 그 당시의 나는 Mock으로 테스트 코드를 작성하는 것에 불편함을 느낀 이유가 Cabi의 구조가 트랜잭션 스크립트 패턴으로 작성되어서일 것이라고 추측한다.

DDD 패턴과 MSA의 실패

위의 테스트 코드 사례 외에도, 기존의 Cabi의 DDD 패턴 적용 실패와 MSA의 적용이 어려운 이유가 Cabi가 트랜잭션 스크립트 패턴으로 작성되서였지 않을까라는 생각이 들었다.
내가 Cabi에 참여하기 전에 DDD 패턴에 대해 동아리원들끼리 공부하고 이를 적용하기 위해 다들 고군분투하던 시절이 있었다고 한다. 정확한 원인은 모르지만 패턴 자체가 너무 어렵기도하고 동아리원들 중 이러한 도메인 모델 중심 개발에 익숙한 사람도 없어, 결국 완전한 구현까지 이어지지는 않고 공부만 잔뜩하고 무산되었다고 한다.
나 또한 이전에 우아콘 따라잡기 시리즈를 작성하며 Cabi에도 MSA를 적용할 수 있을까를 고민해보았는데, Cabi의 구조가 제법 복잡하고 LentHistroy와 같은 경우에는 Cabinet과 User에 각각 묶여서 조회하는 로직이 모두 존재하는 등 막상 MSA를 적용하기에는 시스템을 어떻게 나누어야할 지에 대해 너무나도 막연한 느낌이 들었다. 그 외에도 여러 이유들로 인해 MSA 적용을 시도하지는 않았다.
이 두 가지 실패와 고민들에 대한 것도 도메인 모델 패턴의 연장선이지 않을까 추측된다. 만약 Cabi가 도메인 모델 패턴으로 구현되어 있었다면, DDD 패턴을 적용하기에 더 수월했을 것이고 MSA를 적용하기에도 지금처럼 막연한 느낌을 받지는 않았을 것이라 생각된다.

개인적인 생각

Cabi는 기존에 코드 중복이 많고 코드를 한 번 정리할 필요가 있다고 느껴, 이번에 잘못 사용되고 있는 Facade 패턴을 개선하면서 단일 기능에 집중한 하위 Service Layer를 두어 최대한 재사용성을 낮추는 방향으로 리팩토링하였다. 이렇게 리팩토링 했음에도 단일 기능이 아닌 로직 자체가 비슷한 로직에서는 코드의 중복이 여전히 자주 발생하는 편이다. 이에 대한 근본적인 해결책으로 도메인 모델 패턴을 적용하는 것이 어떨까 같이 고민해보게 되었다.
위에서 언급한 여러 문제들의 원인이 트랜잭션 스크립트 패턴으로 인한 것으로 추측되는 상황이고 실제적인 코드 중복 또한 많이 존재하고 있으니, 이는 Cabi의 구조를 도메인 모델 패턴으로 변경을 해야한다는 신호가 아닐까라는 생각이 든다.
사실 개인적인 욕심으로는 지금의 트랜잭션 스크립트 패턴 구조에서 도메인 모델 패턴으로 변경하고, 더 확장하여 MSA까지 해보고 싶다. 하지만 Cabi에 공부를 많이하면 취업으로 나가고 새로 공부하기 위해 많이 들어오다보니, 러닝 커브가 높고 개발 경험이 많아야 하며 도메인 모델에 대한 이해가 있는 사람이 없으면 개발하기 힘든 도메인 모델 패턴은 실질적으로는 적용하기 어려울 것 같다. 이에 대한 경험은 다음 프로젝트나 취업 이후에 채우는 걸로…

참고