Post
EN

SRP 단일책임원칙

프로그래머가 이 원칙의 이름을 듣는다면 모든 모듈이 단 하나의 일만 해야 한다는 의미로 받아들이기 쉽다. 하지만 하나의 일만 해야 한다는 원칙은 사실 따로 있다. 그것은 바로 함수는 반드시 하나의, 단 하나의 일만 해야 한다는 원칙이다.

역사적으로 기술되어왔던 SRP는 아래와 같은 정의를 갖고 있다.

단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다.

이 원칙을 다음 말로 바꿀 수도 있다.

하나의 모듈은 하나의, 오직 하나의 사용자 또는 이해관계자에 대해서만 책임져야 한다.

여기서 ‘사용자’와 ‘이해관계자’ 라는 단어를 여기에 쓰는 것은 사실 올바르지 않다. 이러한 지칭을 액터(Actor)라고 변경해보자.

하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.

그럼 ‘모듈’의 뜻은 무엇인가?

가장 단순한 정의는 바로 소스 파일이다.

‘응집된(cohesive)’이라는 단어가 SRP를 암시한다. 단일 액터를 책임지는 코드를 함께 묶어주는 힘이 바로 (cohension) 이다.

SRP 를 개선 하는 방법에 대해 확인해보자.

징후 1: 우발적 중복

![](/assets/images/posts/222621602109/c73fcc505897.png?type=w580)

위 그림에서 Employee 클래스는 SRP를 위반하는데, 이들 세 가지 메서드가 서로 다른 매우 다른 세 명의 액터를 책임지기 때문이다.

calculatePay() 메서드는 회계팀에서 기능을 정의하며, CFO 보고를 위해 사용한다.

reportHours() 메서드는 인사팀에서 기능을 정의하고 사용하며, COO 보고를 위해 사용한다.

save() 메서드는 데이터베이스 관리자 DBA가 기능을 정의하고, CTO 보고를 위해 사용한다.

이 클래스의 문제는 서로 다른 액터가 의존하는 코드를 너무 가까이 배치했기 때문에 발생한다.

징후 2: 병합

많은 사람이 서로 다른 목적으로 동일한 소스 파일을 변경하는 경우에 해당한다. 다시 한번 말하지만, 이 문제를 벗어나는 방법은 서로 다른 액터를 뒷받침하는 코드를 서로 분리하는 것이다.

해결책

이 문제의 해결책은 다양한데, 그 모두가 메서드를 각기 다른 클래스로 이동시키는 방식이다.

![](/assets/images/posts/222621602109/da0e4179d602.png?type=w580)

위와 같은 해결책은 개발자가 세 가지 클래스를 인스턴스화하고 추적해야 한다는게 단점이다. 이런 난관에서 빠져나올 때 흔히 쓰는 기법으로 퍼사드(Facade) 패턴이 있다.

![](/assets/images/posts/222621602109/e5182ab2df39.png?type=w580)

EmployeeFacade에 코드는 거의 없다. 이 클래스는 세 클래스의 객체를 생성하고, 요청된 메서드를 가지는 객체로 위임하는 일을 책임진다.

![](/assets/images/posts/222621602109/5264ac2a9074.png?type=w580)

모든 클래스는 반드시 단 하나의 메서드를 가져야 한다는 주장에 근거하여 앞의 해결책에 반대할 수도 있다. 하지만 이 주장은 현실과는 전혀 다르다. 각 클래스에서 지불, 보고서 생성, 데이터 저장 기능을 구현하는 데 필요한 메서드의 개수는 실제로 훨씬 더 많을 것이다. 이들 클래스는 모두 다수의 private 메서드를 포함할 것이다.

이처럼 여러 메서드가 하나의 가족을 이루고, 메서드의 가족을 포함하는 각 클래스는 하나의 유효범위가 된다.

결론

단일 책임 원칙은 메서드와 클래스 수준의 원칙이다. 컴포넌트 수준에서는 공통 폐쇄 원칙 (Common Closure Principle)이 된다.

아키텍처 수준에서는 아키텍처 경계(architectural Boundary)의 생성을 책임지는 변경의 축 (Axis of Change)이 된다.

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