이 원칙은 어떤 클래스가 자신에게 필요하지 않은 인터페이스의 메서드를 구현하거나 의존하지 않아야 한다는 말을 한다. 이는 개발자들이 하나의 인터페이스로 모든 것을 해결하려고 할 때 위배되며 단일 책임 원칙과 밀접한 관련이 있다.
class LifecycleBean implements
BeanNameAware,
BeanFactoryAware,
InitializeBean,
DisposableBean{
...
}
이는 스프링 프레임워크의 LifecycleBean이라는 클래스의 코드 일부이며 총 4개의 인터페이스를 구현하고 있다. BeanNameAware와 BeanFactoryAware 인터페이스는 BeanAware 인터페이스 하나로 통합할 수 있을 것 같은데 왜 굳이 분리 해놓은것일까?
public aspect AnnotationConfigurerAspect
extends AbstractInterfaceDrivenDependencyInjectionAspect
implements BeanFactoryAware, InitializingBean, DisposableBean{
// ...
}
이 또한 스프링 프레임워크에 있는 코드인데 AnnotationConfigurerAspect는 BeanNameAware와 BeanFactoryAware 인터페이스 둘 중에 BeanFactoryAware 인터페이스만 구현한다. 이 이유는 간단하다 실제로 구현해야 하는 기능이 BeanFactoryAware 인터페이스로 충분했기 때문이다. 그런데 만약 두 인터페이스를 BeanAware 인터페이스로 통합했다면 필요없는 인터페이스를 추가적으로 구현했어야 할 것이다.
따라서 범용성을 갖추도록 통합 인터페이스를 만들기보다 다수의 특화된 인터페이스를 만드는 것이 낫다.
스프링에서 Aware는 타깃에 변화가 있을 때 실행되는 콜백 메서드를 구현하는데 사용된다. 예를 들어 beanNameAware로는 빈 이름과 관련된 활동이 있으 때 실행되는 콜백 메서드를 구현할 수 있다.
BeanAware는 이러한 규칙을 따라 bean과 관련한 모든 활동을 구독하는 역할을 한다. 그래서 Bean*Aware 패턴을 따르는 모든 인터페이스가 이곳으로 모이게 되고 그로 인해 변경이 어려워진다. 이는 인터페이스의 정의가 지나치게 넓어 역할이 모호해지며 여러 액터들을 상대하기 때문이다. 이로 인해 단일 책임 원칙도 위배하고 있을 확률이 높다.
그런데 비슷한 인터페이스를 하나로 통합하는 것은 오히려 응집도가 높아지는 것이 아닌가 하는 반문이 생긴다. 하지만 응집도 개념은 유사한 코드를 한곳에 모은다에서 끝나는 것이 아니라 좀 더 세분화된 개념을 가지고 있다.
모듈 내의 컴포넌트들이 같은 기능을 수행하도록 설계된 경우를 말한다. 예를 들어 모듈 구성할 대 주문이라는 모듈을 만들기 보다 주문 처리라는 모듈을 만들어 컴포넌트를 구성할 수 있을 것이다. 이는 주문이라는 범용적 도메인 보다 주문 처리에 목적을 두고 만들어진 모듈이다.
모듈 내의 컴포넌트들이 특정한 작업을 수행하기 위해 순차적으로 연결된 경우를 말한다. 예를 들어 데이터베이스에서 데이터 검색 후 검색 결과를 가공하는 모듈이 이싿
모듈 내의 컴포넌트들이 같은 데이터나 정보를 공유하고 상호작용할 때 이에 따라 모듈을 구성하는 경우를 의미한다. 예를 들어 이메일 전송 모듈을 구성할 때 이메일은 통신에 사용하는 프로토콜이 있고, 데이터 형식도 발신자, 수신자, 제목, 본문 등으로 정해져있다.
절차적 응집도는 모듈 내의 요소들이 단계적 절차를 따라 동작하도록 설계된 경우를 나타낸다. 예를 들어 계산기 모듈에서 입력을 받는 단계, 연산을 수행하는 단계, 결과를 출력하는 단계 등으로 구성하는 경우가 있다.
논리적 응집도는 모듈 내 요소들이 같은 목적을 달성하기 위해 논리적으로 연관된 경우를 말한다. 예를 들어, 회원 관리 모듈에서 회원 등록, 회원 정보 업데이트, 회원 삭제 등의 작업을 수행하는 요소들이 있다면 논리적 응집도를 추구했다고 할 수 있다.
응집도가 높은 순서대로 응집도의 종류를 소개했다. 이전에 얘기했던 유사한 코드를 한 곳에 모아 놓는 것은 논리적 응집도를 추구하는 방식이다. 그렇다면 인터페이스 분리 원칙이 추구하는 것은 무엇일까?
인터페이스는 역할이라고 불러왔다. 그러므로 이 원칙은 역할과 책임을 세세하게 나누라는 의미이다. 따라서 기능적 응집도를 추구하는 것이라 볼 수 있다.
JpaRepository 또한 인터페이스 이지만 이는 Repository 그 자체로도 너무 많은 역할을 가진다. 따라서 CRUD 또는 Reader/Writer 기준으로 분리할 수 있을 것이다. 하지만 이를 꼭 분리한다고 좋은 것은 아니다. 우리는 분리하지 않고도 Repository를 충분히 잘 써왔기 때문이다. 분리 했을 때와의 장점과 하지 않았을 때의 장점을 판단하는 것은 개발자의 몫이다