[ 티스토리 ]

새벽의 공부 이야기

home

tags

태그

guestbook

방명록

manage

관리

profile

프로필

1. 객체 지향 5 원칙 : SRP, 단일 책임의 원칙

2023. 12. 15.

프로그래밍 패러다임/객체 지향 프로그래밍

객체 지향의 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핀, 라이트닝 충전구가 모두 있는 휴대폰은 없다.

이것이 가장 중요한 차이점이고, 그렇기에 삼색 볼펜은 단일 책임이라 정의되어 마땅하다.

 

만약 그 기능들이 같이 쓰인다면 그것은 단일 책임이고,

그 기능을 쓰는 주체가 다르다면 그것은 다중 책임이다.

나는 단일 책임의 범위란 이렇다고 생각하고, 지금껏 이렇게 지켜왔다.

 

최소한 는 그렇게 생각한다.


글을 읽는 이들에게 도움이 되었길 바라며, 이상으로 글을 마치도록 하겠다.