IT/Spring Boot

서비스 클래스는 인터페이스를 상속받아야 하는가?

주현태 2023. 4. 16. 14:38

현재 회사에서 내가 관리하고 있는 코드는 만들어진지 굉장히 오래된 코드여서 레거시 코드및 사용하지 않는 코드가 많다. 현재 노력하고 있는 것은, 틈틈이 생 자바 프로젝트나, Spring 3.x 프로젝트를 스프링 부트로 전환하거나, 안쓰는 코드를 제거하는 작업이다.

 

기존 코드를 읽으면서 평소 의구심이 드는 코드가 있었는데 내용은 다음과 같다.

Service 클래스가 있는데, 이 서비스 클래스에 대한 Service인터페이스를 만들어서 관리가 되어야하나? 이런 코드가 너무많은데? Service인터페이스만 없어져도 많은 파일이 줄어들 것 같은 느낌이 들었다. 

 

만약, OrderService라는 서비스를 구현하고자 한다면 아래와 같이 OrderService관련 파일이 두개가 되는 것이다.

즉, 아래와 같다.

interface OrderService {
	void order(OrderRequest orderRequest);
}

@Service
public class OrderServiceImpl implements OrderService {
	@Override
	public void order(OrderRequest orderRequest) {
    	// 주문관련 로직
    }
}

왜 이래야 하지? 그냥 인터페이스 없이 Service 클래스를 바로 구현해버리면 되는게 아닌가? OrderService 인터페이스는 OrderServiceImpl에서만 구현하기 때문에 딱히 추상화를 함으로 인한 장점은 전혀 없어보이는데 말이다. 그냥 아래와 같이 바꾸면 안되낭?? 
@Service
public class OrderService {

	public void order(OrderRequest orderRequest) {
    	// 주문관련 로직
    }
}

 

 

 이러한 생각을 하던 도중, 내가 생각하던 바와 동일한 생각을 가진 글을 책에서 발견해서 공유 혹은 나중에 또 읽고자 포스팅 하고자 한다.

 

응용서비스의 인터페이스와 클래스
 
응용서비스를 구현할 때 논쟁이 될 만한 것이 인터페이스가 필요한지 여부이다. 인터페이스가 필요한 몇 가지 상황이 있는데 그 중 하나는 구현 클래스가 여러 개인 경우이다.
구현 클래스가 다수 존재하거나 런타임에 구현 객체를 교체해야 할 경우 인터페이스를 유용하게 사용할 수 있다. 그런데, 응용 서비스는 보통 런타임에 이를 교체하는 경우가 거의 없을 뿐만 아니라 한 응용 서비스의 구현 클래스가 두 개인 경우도 매우 드물다.
이런 이유로 인터페이스와 클래스를 따로 구현하면 소스 파일만 많아지고 구현 클래스에 대한 간접 참조가 증가해서 전체 구조만 복잡해지는 문제가 발생한다.
따라서, 인터페이스가 명확하게 필요하기 전까지는 응용서비스에 대한 인터페이스를 작성하는 것이 좋은 설계라고는 볼 수 없다.
테스트 주도 개발을 즐겨 하고 표현 영역부터 개발을 시작한다면 미리 응용 서비스를 구현할 수 없으므로 응용 서비스의 인터페이스부터 작성하게 될 것이다. 예를들어, 스프링 MVC 컨트롤러를 TDD로 개발한다면 컨트롤러에서 사용할 응용 서비스 클래스의 구현은 존재하지 않으므로 응용 서비스의 인터페이스를 이용해서 컨트롤러의 구현을 완성해 나가게 된다.
표현 영역이 아닌 도메인 영역이나 응용 영역의 개발을 먼저 시작하면 응용 서비스 클래스가 먼저 만들어진다. 이렇게 되면 표현 영역의 단위 테스트를 위해 응용 서비스 클래스의 가짜 객체가 필요한데 이를 위해 인터페이스를 추가할 수도 있다. 하지만, Mockito와 같은 테스트 도구는 클래스에 대해서도 테스트용 가짜 객체를 만들기 때문에 응용 서비스에 대한 인터페이스가 없어도 표현 영역을 테스트할 수 있다.

- DDD START! 도메인 주도 설계 구현과 핵심개념 익히기 中

 

 

결론은, 나도 위의 글에 동조하니 Service인터페이스를 지워버려야겠다. 호호호호