객체 지향의 5 원칙 중 제1 원칙, Single Responsibility Principle 단일 책임의 원칙이다.
1. 단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다.
- 로버트 C. 마틴, 클린 아키텍처 中
단일 책임의 원칙이란, 하나의 모듈(클래스, 인터페이스, 객체 등)이 수행하는 기능이 한 가지여야만 한다는 원칙이다.
클린 아키텍처의 저자, 로버트 C. 마틴은 이 문단의 제목처럼 "단일 모듈은 변경의 이유가 하나, 오직 하나뿐이어야 한다." 라고 말한다.
여기서 변경의 이유가 오직 하나뿐이어야 한다라는 말은,
한 가지의 기능만 수행, 즉 한 가지의 책임(단일 책임)을 가지고 있고, 이로 인해 변경될 이유가 오직 하나임을 의미한다.
2. 단 하나의 책임만을 수행하라
핸드폰 충전기의 선을 세 갈래로 나누어 C타입, 5핀, 라이트닝 세 가지 충전 단자를 합친 충전선을 본 적이 있을 것이다.
하지만 보통의 핸드폰에는 충전 단자가 하나 뿐이다.
이 충전선을 써보았다면 사용하는 건 한 개 뿐인데 쓰이지 않는 두 개의 선이 거슬렸을 것이다.
결국 나중에는 한 종류의 단자만을 가진 선을 사용하게 되었을 것이다.
내가 말하고자 하는 건, 필요하지 않은 기능은 과하다는 것이다.
3in1 충전선은 너무 과한 책임을 가지고 있다. 모든 기능을 수행할 수 있지만, 정작 사용되는 건 하나뿐이다.
이것은 결코 좋지 않다. 심지어 쓰이지 않는 다른 기능을 위해 충전 속도가 느려지는 등의 비용 낭비가 발생하기도 한다.
그렇기에 우리는 한 종류의 단자를 가진, 단일 책임을 가진 충전선을 선택했다.
3. 코드에서의 단일 책임
다음 코드를 보자.
public class ThreeHeadChargingWire implements ChargingWire {
public ChargingTerminal cTypeTerminal = CTypeChargingTerminal();
public ChargingTerminal lightningTerminal = LightningChargingTerminal();
public ChargingTerminal fivePinTerminal = FivepinChargingTerminal();
/* Constructor.. */
}
public interface CellPhone {
/* Another Functions.. */
public void charge(Charger charger, ChargingWire chargingWire, ChargingTerminal chargingTerminal)
/* Another Functions.. */
}
3in1 충전선과 핸드폰의 일부 구현부를 볼 수 있다.
3in1 충전선은 세 개의 충전 단자를 가지고 있으며,
핸드폰은 충전을 위해 충전기(Charger)와 충전선(ChargingWire), 충전 단자(ChargingTerminal)를 요구한다.
그렇다면 휴대폰을 충전하는 main 함수는 다음과 같이 동작할 것이다.
public static void main() {
CellPhone cellPhone = CTypeCellPhone();
Charger chager = Charger();
CharginngWire chargingWire = ThreeHeadChargingWire();
cellPhone.playGame();
cellPhone.charge(charger, chargingWire, chargingWire.cTypeTerminal);
return;
}
객체들을 생성하고, 핸드폰으로 게임을 조금 하다가 충전했다. 이대로 함수는 끝난다.
여기서의 문제점은, C타입 충전 단자는 사용되었지만 라이트닝, 5핀 충전 단자는 사용되지 않았다.
휴대폰을 바꾸지 않는 한 앞으로도 사용되지 않을 것이다.
하지만 이 객체는 충전선 내부에서 참조하고 있고, 언젠간 사용될 우려가 있어 GC에 의해 삭제되지도 않을 것이다. 메모리 누수와 다를 게 없다.
이 상황에서의 해결법은 main이라는 함수 이름보다도 명백하다. 책임을 분리해야 한다.
public static void main() {
CellPhone cellPhone = CTypeCellPhone();
Charger chager = Charger();
CharginngWire chargingWire = CTypeChargingWire();
cellPhone.playGame();
cellPhone.charge(charger, chargingWire, chargingWire.terminal);
return;
}
4. "단일" 책임의 범위
계속해서 단일 책임을 강조하긴 하지만, 정작 가장 중요한 단일이라는 것의 범위는 정의되어있지 않다.
단일 책임이라는 건 매우 주관적이고, 불명확하다.
삼색 볼펜을 떠올려보자. 무려 세 개의 색상, 다시 말해 세 개의 책임이나 갖고 있다.
그렇지만 우리는 3in1 충전선과 다르게 일상 속에서 거의 늘 삼색 볼펜을, 더 과하게는 8색 볼펜까지도 사용한다.
그런데, 이것은 아무리 생각해봐도 원칙 위반으로 보일 것이다.
그럼에도 삼색 볼펜의 수요는 매우 많다. 심지어 글을 읽는 당신도 옆에 하나쯤 있을 것이다.
삼색 볼펜의 세 색상은 같이 쓰인다. 검정색으로 필기를 하고, 빨간색으로 별을 그리고, 파란색으로 밑줄을 그어 마무리한다. 늘 같이, 함께이다.
하지만 3in1 충전선은 같이 쓰일 수 없다. 세상에 C타입, 5핀, 라이트닝 충전구가 모두 있는 휴대폰은 없다.
이것이 가장 중요한 차이점이고, 그렇기에 삼색 볼펜은 단일 책임이라 정의되어 마땅하다.
만약 그 기능들이 같이 쓰인다면 그것은 단일 책임이고,
그 기능을 쓰는 주체가 다르다면 그것은 다중 책임이다.
나는 단일 책임의 범위란 이렇다고 생각하고, 지금껏 이렇게 지켜왔다.
최소한 나는 그렇게 생각한다.
글을 읽는 이들에게 도움이 되었길 바라며, 이상으로 글을 마치도록 하겠다.