b

Controller 에서 Service layer 없이 Repository 호출하기 본문

카테고리 없음

Controller 에서 Service layer 없이 Repository 호출하기

dev.bistro 2019. 7. 3. 23:35

 

Spring은 2007년인가 처음 가산에서 박찬욱님에게 교육을 들으면서 접하기 시작햇고, 가장 깊게 이해하며 많이 사용하는 프레임워크이다. 08년 부터 본격적으로 상용서비스에  Spring을 사용하기 시작했고 이때는  3계층 레이어가 대세였다. ( https://sites.google.com/site/telosystutorial/springmvc-jpa-springdatajpa/presentation/architecture , 특히 2.5에서 3종 annotation이 완성되면서 클래스 이름 조차, xxxController, xxxService, xxxRepository ... 으로 완전히 정형화 되었던 기억이... )

public class BrandController {
    private  BrandService brandService;
    @GetMapping("/brand/hitcount")

    public int getHitCount() {
        return brandService.getHitCount();
    }
}

public class BrandService {
    private BrandRepository repository;
    public int getHitCount() {
        return repository.getHitCount();
    }
}

이런식의 BrandService가 왜 필요로 한가? 나중에 복잡한 로직 처리를 위해서 Service 가 필요해요. 라고 말한다면 납득하기 어렵다.  그 전에 퇴사를 하던가 서비스가 접힐 수도 있다. 
그것보다... '저흰 원래 이렇게 일했어요'가 더 설득력이 있다. (즉, Service 클래스가 하는일이 쥐뿔도 없지만, 이렇게 해놓으면 다른사람이 이해하기 쉬워요. 가 훨씬 그럴싸하다)

CQRS 로 설계된 APi-server이나 특정 데이터를 제공하는데 특화된 프로젝트에서 이러한 패턴을 자주 접할 수 있다.
 CUD는 없어서 Read에만 집중하고, 그렇기 때문에  대부분의 데이터가 배치/스트림에 의해서 반정규화되어 있어서 복잡한 데이터요청도 없다. 단순히 selectById 정도에서 끝나는 Repository method의 비중이 크다 (이를 위한 spring-data-rest 도 있지만 솔직히... 얘는 너무 과하게 expose 해준다-_-ㅋ)

public class BrandController {
    private BrandService brandService;
    private BrandRepository brandRepository;
    
    @GetMapping("/brand/hitcount")
    public int getHitCount() {
        return brandService.getHitCount();
    }

    @GetMapping("/brand/soldoutcount")
    public int getSoldoutCount() {
        return brandRepository.getSoldoutCount();
    }
}


public class BrandService {
    private BrandRepository repository;
    public int getHitCount() {
        return repository.getHitCount();
    }

    public int getSoldoutCount() {
        List<Brand> brands = repository.getSoldOut();
        // TODO ::  마지막 판매 시간이 오늘이 아닌 것 제외, 주문 취소비율이 1프로가 넘고 예약이 100개가 넘어서...
        // 보오오오오오옥잡해 */
        return  filtered.size();
    }
}

이처럼 Controller 에서 Repository를 바로 사용하기도 하고 Serivce를 통해서 Repository를 사용 하는 경우도 있다면 어떨까?
나라면 Controller 에서 Repository를 호출 하는 부분을 삭제하고 Service 로 위임할 것이다.

당장 눈에 보이는 단점들?
그냥 그림만 그려봐도  Controller -> Service -> Repository의 단일 참조보다 Controller -> Service -> Repository & Controller -> Repository 의 의존 그래프가 그려져서 복잡하다. 지금은 하나의 종단(?) 관심사가 있지만 한개씩 늘어날때마다 더욱 복잡해 질 수 있다.
그리고 당장 테스트를 할때 Controller는 Repository, Service를 인젝션 해야하고,  Service역시 Repository를 인젝션 해야한다. 

이정도의 단점밖에 보이지 않는군요. 이 말은 이 정도의 단점을 없앨 수 있다면(Controller 가 Service 없이 Repositry만을 호출하고  프로젝트 자체가 트랜잭션이나 OSIV등의 이슈에 대해 자유로울때),  저는 사용해도 된다고 보고 실제로, 자주 썼습니다.

ps.
이 글을 쓰게 된 원인이 된 코드는 Controller 에서 Reposioty.incrementViewCount를 직접 호출하면 어떨까? 였다
해당 프로젝트에서는 CRUD가 존재하는 프로젝트에서 트랜잭션/AOP 이슈로 가능하면 layer간의 분리와 호출관계를  준수하면서 작업하는 좋겠다.  (최근에는 그런일이 없겟지만)  spring 3.x 이전도 dynamic proxy를 AOP가 필요한 클래스들은  interface가 강제된적이 있다. 일반적으로 Controller는  인터페이스가 없으니, 아마도 정상적인 동작이 안될듯 ...? 한데. 이렇게 해본적은 없으니 이건 그냥 ... 상상에서 나오는 우려사항 정도이다.

 

Comments