인터페이스 설계

인터페이스 의존성 테스트 경계

인터페이스를 만들었다고 자동으로 안정적인 설계가 되지는 않는다. 클래스가 구체 구현에 직접 묶이는지, mock이나 fake로 교체할 수 있는지, 의존성 방향이 상위 정책에서 하위 세부 구현으로 흐르는지 확인해야 한다.

01

호출자 요구 파악

구현체가 가진 모든 메서드가 아니라 호출자가 실제로 필요한 동작만 계약으로 뽑는다.

큰 인터페이스는 구현체를 묶어버린다
02

구체 의존 제거

상위 서비스가 특정 클래스 new에 직접 의존하지 않도록 constructor나 DI로 주입한다.

교체 가능성이 설계의 증거다
03

테스트 대역 준비

네트워크, DB, 시간, 랜덤값 의존성은 mock이나 fake로 대체 가능한지 본다.

테스트가 어려우면 경계가 흐린 것이다
04

DIP 위반 찾기

상위 정책 코드가 하위 세부 구현의 import를 직접 알고 있는지 확인한다.

의존성 방향을 뒤집는다
05

계약 최소화

읽기 전용, 쓰기 전용, 조회, 저장처럼 역할별로 인터페이스를 나눈다.

필요 없는 메서드 구현을 강요하지 않는다
DI
구현체 주입 서비스가 concrete class 대신 interface 모양의 의존성을 받게 한다.
런타임 바인딩 방식도 정한다
Mock
테스트 교체 외부 API나 DB를 빠른 테스트 대역으로 바꿀 수 있어야 한다.
타입은 mock shape도 검사한다
DIP
의존성 방향 상위 정책이 세부 구현에 끌려가지 않도록 추상 계약을 둔다.
추상화가 실제 교체를 가능하게 해야 한다
ISP
작은 계약 클라이언트가 쓰지 않는 메서드에 의존하지 않도록 인터페이스를 나눈다.
fat interface를 피한다

설계 확인

교체 테스트 구현체를 fake로 바꿔도 호출 코드가 바뀌지 않는지 확인한다.
메서드 사용량 인터페이스 메서드 중 호출자가 쓰지 않는 항목이 있는지 본다.
직접 new 상위 서비스가 concrete class를 직접 생성하지 않는지 검색한다.