SRP: 단일 책임 원칙
- Single Responsibility Principle
- 이름만 보면 하나의 모듈은 하나의 일만 해야한다로 해석될 수 있지만 이는 잘못된 해석
- 단 하나의 일만 해야하는것은 함수, 이는 SOLID도 아니고 SRP도 아님
- 역사적으로 SRP는 아래와 같이 기술됨
단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다.
- 소프트웨어 시스템은 사용자와 이해관계자를 만족시키기 위해 변경됨
- SRP가 말하는 “변경의 이유”란 사용자와 이해관계자를 의미
- 위를 적용하면 SRP를 아래과 같이 표현 가능
하나의 모듈은 하나의, 오직 하나의 사용자 또는 이해관계자에 대해서만 책임저야 한다.
- 여기서 사용자와 이해관계자라는 표현을 사용하는것은 적합하지 않음
- 동일한 방식으로 변경되지를 원하는게 두 명이상 일수도 있기 때문
- 변경을 요청하는 집단을 액터라고 부름
- SRP의 최종 버전은 아래와 같음
하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.
- 모듈의 가장 단순한 정의는 소스 파일
- 모듈은 함수와 데이터구조로 구성된 응집된 집합
- 단일 액터를 책임지는 코드를 묶어주는 힘이 바로 응집성(cohesion)
징후 1: 우발적 중복
- SRP를 위반하는 Employee라는 클래스가 존재
- 세가지 메서드가 존재함
caculatePay
: 회계팀에서 기능정의, CFO 보고를 위해 사용reportHours
: 인사팀에서 기능정의, COO 보고를 위해 사용save
: DBA가 기능을 정의, CTO 보고를 위해 사용
- 예시
caculatePay(CFO)
와reportHours(COO)
가 하나의 메서드를 공유해서 사용함regularHours
: 초과 근무를 제외한 업무 시간을 계산하는 알고리즘
- CFO 팀에서 초과 근무를 제외한 업무 시간 계산 방식을 수정하기로 결정
regularHours
를 수정하면 COO팀이 사용중인reportHours
에도 영향이 발생- COO팀은 변경을 원하지 않음
- 개발자는 CFO팀이 사용중인 기능들만 테스트
- 위 예시는 서로 다른 액터가 의존하는 코드가 가까이 배치되어있기 때문에 원하지 않는 결과가 발생
- SRP는 서로 다른 액터가 의존하는 코드를 분리하라고 말함
징후 2: 병합
- 소스 파일에 다양하고 많은 메서드를 포함하면 병합이 자주 발생
- 특히 이들 메서드가 서로 다른 액터를 책임진다면 병합이 발생할 가능성이 높음
- 예시
- CTO팀에서 Employee 테이블 스키마 수정
- COO팀에서 reportHours 메서드의 보고서 포맷 변경
- 각 팀에서 같은 코드를 수정하면 충돌이 발생, 즉 병합이 발생
- 충돌이라는 표현이 있지만 같은 영역을 수정해야해서 병합이 필요한 상황을 의미
- 병합은 항상 위험이 뒤따름
- 위 상황에서는 CFO팀도 영향을 받을 수 있음
- 위 예시는 많은 사람이 서로 다른 목적으로 동일한 소스 파일 변경을 시도했기 ㄸ/ㅐ문
- 이것을 벗어나는 것이 서로 다른 액터를 뒷받침하는 코드를 분리하는것
해결책
- 데이터와 메서드를 분리하는것
- 각 팀별로 클래스를 정의, 클래스가 공통 데이터에 접근하도록 구성
- 세 가지 클래스를 인스턴스화하고 추적해야한다는 단점이 존재
- 퍼사드(Facade)패턴을 사용해 해결가능
- EmployeeFacade 클래스
- 각 팀에서 정의한 세개의 클래스의 객체를 생성
- 요청된 메서드를 객체로 위임
결론
- 단일 책임 원칙은 메서드와 클래스 수준의 원칙
- 상위 개념에서 다른 형태로 등작함
- 컴포넌트 수준: 공통 폐쇄 원칙(Common Closure Principle)
- 아키텍처 수준: 아키텍처 경계(Architecture Boundary)의 생성을 책임지는 변경의 축(Axis of Change)