728x90

Service Layer

이직하고 프로젝트에 대해 구조 파악을 하면서 리팩토링을 진행중에 좀 생각하게 된게 꽤많았다.
사실 서비스 레이어라고 해서 비즈니스 로직을 다 넣는건가?
또는 비즈니스 로직이 다 들어가 있는 것이다. 라는 얘기들이 많았다.
사실 나도 그렇게 생각했었던 사람중 1명이었다.
이게 근데 잘못된 생각이었다.

결국엔 사실 소스 코드를 다 분리하고 봐도 하나로 합쳐져서 동작하게 되는건 사실 맞다고 본다.

그러니까 다시 말하면 클래스 하나의 메소드에서 엄청나게 많은 줄을 가지고 개발을 할 수도 있다는 것이다.
근데 이거는 객체 지향 설계 관점에선 너무 안좋은 것이고
각자의 책임이 있을 것인데 그걸 분리한게 객체 지향인거다.

Service Layer에 대한 오해

일단 이 서비스 레이어에서는 비즈니스 로직이 넘쳐나게 될 것이 아니라,

적어도 뭔가의 조건을 통해 돌려주고 수정하고 하는 로직들은 도메인 객체가 해야될 일이라는 것이다.

보통의 서비스 레이어 특징

  • @Service에 사용되는 서비스
  • 일반적으로는 @Controller, @Repository에 사용된다.
  • @Transactional 이 사용되는 영역

도메인 특징

  • 도메인이라고 불리는 대상이 뭘 하는 객체인지 모든 사람들이 알 수 있고 공유하게 만든 모델
    • 주문, 상품 등등.. 이 도메인이 될 수 있다.
  • JPA를 사용한다면 @Entity 모델이 될 수도 있다.
    • 그렇지만, DB의 테이블과 동일해야 한다? 에서는 NO라고 할 수 있다.

모아서 보니까 결국엔 비즈니스 로직은 도메인이 가져야 한다.

그렇다면 서비스 레이어는???

트랜잭션 관리, 도메인의 순서 대로 객체에게 할당을 하여 식만 조합해주는 느낌으로 가야한다.
그래서 나는 예시 소스로 간단하게 만들어보자면

public class ExampleService {
    private final ExampleRepository1 exampleRepository1;
    private final ExampleRepository2 exampleRepository2;
    private final ExampleRepository3 exampleRepository3;

    public ExampleService(ExampleRepository1 exampleRepository1,
     ExampleRepository2 exampleRepository2, ExampleRepository3 exampleRepository3) {
        this.exampleRepository1 = exampleRepository1;
        this.exampleRepository2 = exampleRepository2;
        this.exampleRepository3 = exampleRepository3;
    }
}

만약 이런 클래스가 있어서 각 repository별로 사용하는 트랜잭션이 다르다면 트랜잭션 처리가 애매했다.
위 구조를 아래와 같이 변경했다.

public class ExampleFacade {
    private final ExampleService1 exampleService1;
    private final ExampleService2 exampleService2;
    private final ExampleService3 exampleService3;

    public ExampleService(ExampleService1 exampleService1,
     ExampleService2 exampleService2, ExampleService3 exampleService3) {
        this.exampleService1 = exampleService1;
        this.exampleService2 = exampleService2;
        this.exampleService3 = exampleService3;
    }

}

@Transactional
public class ExampleService1 {
    private final ExampleRepository1 exampleRepository1;

    public ExampleService1(ExampleRepository1 exampleRepository1) {
        this.exampleRepository1 = exampleRepository1;
    }
}

@Transactional
public class ExampleService2 {
    private final ExampleRepository2 exampleRepository2;

    public ExampleService1(ExampleRepository2 exampleRepository2) {
        this.exampleRepository2 = exampleRepository2;
    }
}

@Transactional
public class ExampleService3 {
    private final ExampleRepository3 exampleRepository3;

    public ExampleService1(ExampleRepository3 exampleRepository3) {
        this.exampleRepository3 = exampleRepository3;
    }
}

이렇게 분리를 해서 트랜잭션 관리를 해줬었다.
이게 이제 이전에 내가 퍼사드 패턴 적용기 라고 해서 포스팅을 했었던 구조인데
거기에 +@ 로 덧붙인다면 각 도메인에 대한 로직 수행을 서비스 -> 도메인 이 과정을
넣어주어야 완성인 것 같다.
객체 설계에 대해 점차 이해가 쏙쏙 되는 중이다.

728x90

'Spring' 카테고리의 다른 글

@ExceptionHandler  (0) 2022.08.10
Spring Rest Docs 테스트로 문서화를 해보자!  (0) 2022.08.10
Validaion  (0) 2022.08.09
Filter, Interceptor 정리  (0) 2022.08.07

+ Recent posts