Post

[Spring] Service 인터페이스와 Impl 분리 이유, 그리고 AOP

[Spring] Service 인터페이스와 Impl 분리 이유, 그리고 AOP

백엔드 개발을 하다 보면 한 번쯤은 다음과 같은 구조를 보게 된다.

1
2
3
4
public class HelloServiceImpl implements HelloService {
    @Override
    // 무언가를 처리하는 로직
}

“Service 클래스 하나면 되지 왜 굳이 인터페이스와 Impl을 나눌까?”라는 생각이 들 수 있다. 이번 글에서는 그 관습이 생긴 이유와, 지금도 항상 필요한 구조인지 정리해보려고 한다.

Impl 클래스를 사용해온 이유

1. 객체지향 설계 원칙을 지키기 위해

핵심은 다형성개방-폐쇄 원칙(OCP)이다.

인터페이스를 사용하면 특정 기능에 대한 변경 사항이 생겨도 구현체만 교체하거나 수정하면 된다. 즉, 구현체(Impl)를 바꾸더라도 다른 코드에 미치는 영향을 줄일 수 있다.

결국 이 구조의 목적은 하나의 역할을 여러 방식으로 구현할 수 있도록 확장 가능성을 열어두는 데 있다.

2. 설계와 구현을 분리하기 위해

인터페이스를 만드는 이유는 코드의 확장성재활용성을 높이기 위해서다. 대부분의 프로젝트에서는 인터페이스와 구현체가 1:1로 만들어져 사용된다.

그렇다면 이런 구조를 항상 유지하는 것이 정답일까?

지금은 1:1 관계일지라도, 서비스가 커지거나 요구사항이 달라지면 구현체가 여러 개로 늘어날 수 있다. 그래서 객체지향적인 관점에서는 인터페이스 분리가 여전히 의미가 있다.

또 협업 환경에서는 인터페이스가 일종의 계약서 역할을 하기도 한다. 설계자가 함수명, 반환값, 파라미터를 먼저 정의해두면, 구현 담당자는 그 기준에 맞춰 병렬로 작업할 수 있다.

AOP란?

AOP는 핵심 관심사와 공통 관심사를 분리해서 관리하는 방식이다. 예를 들어 로깅, 트랜잭션, 보안처럼 여러 곳에서 반복되는 기능을 Aspect로 분리할 수 있다.

aop_ex01

Aspect란?

Aspect는 부가 기능을 담은 Advice와, 그 기능을 어디에 적용할지 결정하는 Pointcut을 합친 개념이다.

AOP 용어 정리

  • Target: 부가 기능이 적용될 실제 대상
  • Advice: 타깃에 추가되는 공통 기능
  • Join Point: Advice가 적용될 수 있는 지점
  • Pointcut: Advice를 적용할 Join Point를 선별하는 표현식
  • Aspect: Advice + Pointcut
  • Advisor: Spring AOP에서 사용하는 Advice + Pointcut 조합
  • Weaving: TargetAdvice를 연결하는 과정

지금은?

과거에는 Spring에서 AOP를 구현할 때 JDK Dynamic Proxy를 주로 사용했다. 이 방식은 인터페이스 기반 프록시에 의존하는 경우가 많아 인터페이스 - 구현체 구조가 더 중요하게 받아들여졌다.

하지만 지금은 CGLIB 기반의 클래스 프록시도 널리 사용되기 때문에, AOP만을 이유로 무조건 Impl 구조를 고집할 필요는 줄어들었다.

그럼 Impl 설계는 꼭 필요할까?

내 생각에는 “항상 필요하다”보다는 “필요할 때만 쓰는 것이 맞다”에 가깝다. 확장 가능성, 협업 구조, 테스트 전략이 분명하다면 인터페이스 분리는 충분히 가치가 있다. 반대로 구현이 하나뿐이고 확장 계획도 뚜렷하지 않다면, 관성적으로 Impl 클래스를 늘리는 것은 오히려 복잡도만 높일 수 있다.

This post is licensed under CC BY 4.0 by the author.