작성자 : 김다희
처음 프로젝트를 시작할 때 controller - service - repository 구조로 디렉토리를 잡았다.
빠르게 개발하고, 프로젝트가 커지는 시점에 다시 리팩토링을 하는게 좋을 것 같다고 판단했기때문이다.
개발 시작이 되고 점점 프로젝트가 커지면서 불편한 단계에 접어 들었다.
변경 전 디렉토리 구조
- 도메인 분리가 안된 상태이다 보니 디렉토리 전환이 많아서 불편했고
- 더 큰 프로젝트가 되었을 경우에 이를 모듈로 분리, MSA로 전환할 수 있는 구조가 될 수 있을까? 싶었다.
변경 전 디렉토리 구조는 아래와 같다.


디렉토리 변경 과정
확장성을 고려해서 디렉토리 구조를 변경해나갔다.
- 도메인을 언제든 원하는 서버에 확장 가능할 수 있는 구조를 중점으로 생각했다

처음엔 위와 같이
- 도메인 단위로 나누고
- 도메인의 집합은 각 실행 가능한 서버 단위가 되고
- 서버는 모듈이 되는 구조를 생각했다.
그리고 이 개념을 프로젝트 구조에 적용했다.
변경 후 디렉토리 구조
.png?table=block&id=3ef4b44b-ec34-4221-a909-60d375315d02&cache=v2)
Module이라는 개념을 도입했다.
모듈은 n개의 도메인이 묶인 구조라고 생각하면된다. 도메인안에는 또 여러 도메인이 존재할 수 있다.
결론적으로 큰 도메인을 각각의 서버로 분리할 수 있고, 서버의 분리는 확장을 의미한다고 생각했다.
서버의 모음이 모듈이 되어 언제든 원하는대로 확장하고 축소 할 수 있는 구조를 만들었다.
그렇다면 정말 서버가 별도 분리되었을 때,
다른 서버, 다른 도메인에 있는 entity, method 를 어떻게 참조할 수 있을까?
현재 프로젝트에는 Series, Write Domain이 존재한다.
SeriesService에서 WriteService를 주입받는 상황이라면 아래와 같은 구조도 충분할 것 이다.
@Service public class SeriesService { private final SeriesRepository seriesRepository; private final WriteService writeService; public SeriesService( SeriesRepository seriesRepository, WriteService writeService ) { this.seriesRepository = seriesRepository; this.writeService = writeService; } @Transactional public SeriesSubscribePost.Response createSeries( Long userId, MultipartFile thumbnail, SeriesSubscribePost.Request request ) { Writer writer = this.writeService.findByUserId(userId); //Do something ... } }
하지만 서버가 분리되었다고 생각하면 위와 같은 코드로는 대응할 수 없다.
이 부분을 해결하기 위해 interface 기반 java method call을 이용했다.
interface는 provider라는 네이밍을 적용했고, 코드는 다음과 같이 적용했다.
public interface WriterProvider { Writer findByUserId(Long userId); }
@Service public class WriterService implements WriterProvider { private final WriterRepository writerRepository; public WriterService( WriterRepository writerRepository, ) { this.writerRepository = writerRepository; } @Override public Writer findByUserId(Long userId) { return this.writerRepository .findByUserId(userId) .orElseThrow(() -> new UserNotFound("userId=" + userId)); }
@Service public class SeriesService { private final SeriesRepository seriesRepository; private final WriterProvider writerProvider; public SeriesService( SeriesRepository seriesRepository, WriterProvider writerProvider ) { this.seriesRepository = seriesRepository; this.writerProvider = writerProvider; } @Transactional public SeriesSubscribePost.Response createSeries( Long userId, MultipartFile thumbnail, SeriesSubscribePost.Request request ) { Writer writer = this.writerProvider.findByUserId(userId); //Do something ... } }
현재는 하나의 서버에 모든 도메인이 있기때문에 interface 기반 java method call을 이용하지 않아도 된다.
하지만 서버가 물리적으로 분리되었을 경우를 생각한다면 대응할 수 없다. 하여 이를 확장가능한 코드로 녹여내기위해 Provider라는 개념을 도입하여 이 부분을 해결할 수 있었다.