들어가며
스타트업에서 3년 가량 스프링을 사용해오면서 여러 패키지 구조를 검토하고 사용해봤다. 참고로 이 글은 내가 3년차나 되니까 이렇게 설계하는게 좋으니까 그렇게 해야돼! 이런 글이 절대로 아니다. 지극히 주관적으로 생각했을때 이 구조가 좋더라는 내 생각을 작성한 글이다.
계층형 구조
스프링을 처음 접하면 일반적으로 많이 사용하게 되는 구조다. 스프링 입문 인터넷 강의, 서적 등에서 많이 언급되는 구조다. 계층형 구조의 장점은, 파악하기 쉽다는 것이다. 너무나 익숙하니까... 당연하다. 단점은 카테고리 (패키지)가 적기 때문에 클래스가 많아질 수록 개발 해야 될 클래스를 찾기 어렵다.
도메인형 구조
계층형 구조보다 더 나은 구조 없나?.. 둘러보다 사용해본 구조다. 각각의 도메인 (coupon, member, order 등)을 기준으로 패키지를 나눈다. 장점은 계층형보다 도메인을 파악하기 쉽다. 도메인 이름이 패키지 이름에 드러나기 때문이다.
협업을 할 때, 패키지 구조만 잘 나눈다면 내가 무슨 클래스를 찾아서 개발해야 할지 파악하기 쉽다. 문제는 패키지 구조를 나누는게 쉽지 않다. 예를들어 어떤 사람은 로그인 관련된 기능이 담긴 클래스를 auth 패키지로 따로 뺀다. 그런데 다시 생각해보면 서비스에 인증이라고는 member 밖에 없는데 member에 들어가는게 맞지 않나? 이런 의견들이 충돌하곤 한다.
의견을 나누는것은 물론 좋다. 그러나 필요한 아젠다로 의견을 나누지 않는다면 그것은 커뮤니케이션 비용이 높아진다는 관점으로 해석할 수 있다고 생각한다 (이런 일이 꽤 많이 발생하더라..)
제일 치명적인건 패키지가 순환 참조될 가능성이 크다.. 순환 참조가 되면, 하나의 기능을 수정하면 다른 패키지들이 연달아서 컴파일 에러가 난다. 개발 할때마다 별로더라..
두가지 구조의 장점을 결합하면 안되나?
문득 계층형 구조와 도메인 구조의 장점을 결합하면 좋지 않을까? 라는 생각을 했다. 개발할 클래스를 찾기 쉽고, 도메인을 파악하기 쉬우며 순환 참조가 적게 발생하는 구조는 없을까? 주변 지인과 여러 대화를 나누며 새로운 패키지 구조에 대해서 검토하고 적용해 보았다.
application package : 서비스 클래스들이 들어간다. 이 클래스에는 비즈니스 로직이 절대 들어가서는 안되고, 트랜잭션 흐름을 제어하는 로직만 들어간다. OrderService, CouponService 이런것들이 있다. response dto는 이 패키지에 넣는다. 왜냐면 서비스에서 response dto로 변환하는 로직을 작성할때 클래스를 생성하기 편하다. 클래스 가까이에 있으니..
common package : 어플리케이션 전체에서 사용되는 클래스들이 있다. 상수, 환경설정, 예외처리, 유틸과 같은 클래스들이 들어있다
domain package : 비즈니스 로직을 담당하는 클래스들이 있다. JPA Entity들과 enum들이 있다.
event package : 말 그대로 이벤트 담당 클래스들이 들어있다. 파일 전송이나 알림톡 전송과 같은 역할을 하는 로직들은 결합도를 줄이기 위해 이벤트 로직으로 따로 빼는게 유지보수 할때 편하다.
infrastructure package: aws, jpa와 같은 외부 연동과 관련된 클래스들이 들어있다. 여기서 주의해야할게 스프링 환경설정 (jackson, swagger, webmvc) 은 infastructure 영역이 아니다.
presenter: rest api controller 클래스들이 들어있다. request dto는 이 패키지에 넣는다. 요청과 관련된 dto는 해당 패키지에 넣는게 적절하다. controller가 요청 역할을 하니까
테스트는 어떻게 하나?
스타트업은 테스트 코드 작성 하는것이 시간 낭비 라는 말이 있다. 솔직히.. 내 생각은 다르다. 테스트 코드를 작성하면 잃는 것보다 얻는게 더 많다. 물론 테스트 커버리지 100프로 달성 하겠다고, 테스트 코드에 올인 하는것은 시간 낭비라고 생각한다. 테스트 코드를 작성하면 새로운 기능을 개발할 때 안정감을 얻는다. 개발자에게 안정감은 굉장히 중요한 것이라고 생각한다. 어딘가 찜찜한데... 이런 생각으로 개발하면 꼭 문제 생기더라.. 테스트 코드를 잘 작성하면 이런 문제를 해결할 수 있다.
나는 테스트 코드를 비즈니스 로직에만 작성한다. 그렇다고 모든 비즈니스 로직에 작성하지는 않는다. 굉장히 간단한 로직을 테스트할 필요가 있을까?.. 나는 없다고 생각한다. 그래서 요구사항이 어느정도 복잡한 곳에만 테스트 코드를 넣는다. 그리고 외부 의존성을 가지는 데이터베이스 테스트는 하지 않는다. 개인적으로 의미가 그리 많지는 않다고 생각한다. 중요한건 비즈니스 로직이다.
결론
빠르게, 그리고 안정적으로 개발하려면 설계는 필수라고 생각한다. 나는 아직 한참 좋은 설계를 하려면 멀었다. 나중에 시니어가 되었을때 이 글을 보게 되면, 이거보다 좋은 구조가 널렸는데 이런 글도 썼었네.. 라는 생각이 들었으면 좋겠다
'서버' 카테고리의 다른 글
Node.js Event Loop (0) | 2023.07.09 |
---|---|
CPU Burst, IO Burst (0) | 2023.06.29 |
linux file descriptor (0) | 2023.06.05 |
간단하고도 빠른 서버 성능 최적화 (node js를 중심으로) (0) | 2023.05.04 |
HTTP 프로토콜이 만들어진 이유 (1) | 2022.09.11 |