🐢 꼬부기 LV.1 | 개념•기초/💧물대포(핵심개념)

단일책임원칙(SRP)

서화 2026. 3. 14. 23:09

소프트웨어를 설계하거나 리뷰 과정에서 필수인 단일책임원칙(Single Responsibility Principle,SRP)에 대해 정리해보자

보통 SRP를 설명할때 클래스 다이어그램을 그리거나 비대한 클래스를 쪼개는 리팩토링 코드를 예시로 사용한다 오늘은 코드를 사용하지 않고 개념적으로 정리해보려고 한다 단일책임원칙은 코딩을 위한 규칙이 아니라 이세상에 존재하는 근본원리이기 때문이다

단일책임원칙

단일 책임원칙이란 하나의 존재 하나의 책임이라는 말로 모든 사물은 존재의 이유가 있다

모든사물은 크기에 상관없이 크기에 맞는 명확한 책임을 가지고 있다

예시) 가위 -> 자른다, 우산 -> 비를 막는다

만약 가위로 못질을 한다거나 우산으로 바닥의 낙엽을 치운다고 했을때 매우 비효율적일수 밖에 없다

자른다와 비를 막는다 같은 행위들을 책임이라고 하고 흔히 기능이라고 한다 책임과 기능은 어떻게 다른걸까?

책임 vs 기능 분리하기 

책임과 기능을 분리하는 과정의 핵심은 기능은 책임을 위해 존재한다는 명확한 기준이 있어야한다

예시로 심장은 태어날때부터 죽을까지 수축과 이완을 반복한다 이를 위해 전기펄스를 일으키는 발전 기능을 수행하고 혈액유입량에따라서 심장박동의 세기를 조절한다 또한 과부하 방지를위해서 뇌와 통신하고 호르몬분비에도 관여한다

이 심장의 기능을 위 기준에 대입해 본다면

  • 심박수 조절 기능은 ->혈액순환(책임)을 위해 존재한다
  • 전기 스파크 생성 기능은 -> 혈액순환(책임)을 위해 존재한다
  • 유입량조절을 위한 호르몬 분비기능 -> 혈액순환(책임)을 위해 존재한다

모든 문장에 구조적으로도 의미적으로 자연스럽게 성립된다 따라서 기능은 책임이라는 목표를 달성하는 수단일뿐이다

예시의 심장의 모든기능은 혈액순환이라는 단하나의 책임이다

SRP를 위반하는 기능은 위 기준에 맞춰봤을때 말이 되지 않는다

예시) 소화 효소 분비(기능)는 -> 혈액순환(책임)을 위해 존재한다 (X)

위의 예시처럼 논리적으로 성립하지 않기때문에 소화 효소 분비는 심장에 있어서 안되는 기능이다

이 기준에 맞게 내가 작성한 클래스나 모듈의 기능들을 대입해보고 문장이 어색하다면 그 기능은 잘못된곳에 있는것이다

왜 책임은 하나여야하는가?

예시를 하나들어보자 

만약 위 예시에 나온 심장의 심박조절기능을 폐에다 준다고 생각해보자

폐에서 하는 일은 호흡을 담당(책임) 해야하는데 여기에 심박조절기능을 추가했을때 심박조절은 혈액순환이라는 책임이 있기때문에 혈액순환이라는 기능이 추가된것과 같다

그러나 건강상의 이유로 폐기능이 나빠졌다고 하면 호흡과 동시에 심박조절까지 나빠지는 부작용이 발생한다

즉 호흡기 질환이 순환기 질환으로 전이되는 결합이 생기는것이다 

소프트웨어 개발에서 가장 두려운것이 하나를 건드렸는데 전혀 상관없어 보이는 다른곳이 터지는 현상이다

하나의 객체에 두개 이상의 책임이 부여되면 한 기능의 변경이나 손상이 다른 기능에 영향을 미칠 확률이 매우 높아진다 따라서 변경의 이유가 단하나여야한다 라고 말하는 이유이다 

SRP위반인가? 다른 예시로 이해해보기

코 -> 숨을 쉬는 통로이면서 냄새를 맡는역할을한다 -> 감기에 걸려서 코가 막히면 호흡기능저하 뿐만아니라 냄새도 못맡게된다

혀 -> 맛을 느끼는 역할을 하면서 발음을 만드는 역할도 한다 -> 염증이  생기면 맛을 못보기도 하고 말하기 불편해진다

위의  예시도 마찬가지로 책임이 섞여있어 문제가 발생한다

우리의 몸은 각자의 역할별로 책임이 나눠져있고 이것이 단하나의 책임을 갖도록 기관을 분리하는 아주중요한 이유다

그러나 자연은 공간 제약이나 생존 효율성을 위해 책임을 병합하기도한다 예를 들어 코가 막히면 숨을 못쉴수 있다는 리스크가 있을수 있으니 기도를 코와 입 양쪽으로 연결해서 위험을 줄이는 설계를 선택할수 도 있다 여기서 핵심은 Trade-off를 인지하고 있는가 이다

현실 세계의 SRP의 위반과 애매한 경계

위반사례 - 비디오 일체형 tv

비디오 재생(기능)은 -> tv화면 표시(책임)을 위해 존재한다(x)

tv와 vcr기능은 서로 다른 책임의 축을 가진다

 TV -> 방송신호를 화면으로 표시

VCR-> 테이프의 내용을 재생

이 둘을 묶어 놓았을때 생기는 문제점은 비디오가 고장나서 수리를 맡기면 티비도 못본다는 것이다 비디오 시대가 저물고 DVD 시대가 왔을때 TV는 더 쓸수 있는데 비디오가 쓸모없어졌다는 이유로 TV자체를 버려하야하는 비효율적인 일이 발생했다

소프트웨어의 개발도 똑같다 자주 바뀌는 비느니스 로직과  잘바뀌지 않는 기반 프레임워크를 한 클래스나 모듈에 섞어 놓으면 로직하나를 수정했는데 전체 시스템으 재 배포해야하거나 프레임 워크를 바꾸기 위해 비즈니스 로직을 다 뜯어 고쳐야한다 이것이 변경의 이유가 다른것들은 분리되어야한다 라고 말하는 이유다

경계 사례 -> 맥가이버 칼

와인오프너(기능)는 자르기(책임)를 위해 존재한다 (X)

요리사의 관점에서는 조리할때 맥가이버칼을 사용하지 않으니 위반이 맞다 그렇다면 등산객 기준으로 는 어떤가?

산에서 생존하는데 필요한 최소한의 도구를 휴대 가능한 무게로 제공한다는 의미에서 SRP위반이 아니게 된다

즉 컨텍스트에 따라 달라진다 여기서 SRP의 중요한 통찰을 얻을수 있다 맥가이버 칼은 편의성을 위해 유지보수성을 의도적으로 희생했다 따라서 소프트웨어 개발에서도 스타트업 mvp(시장검증을 위한 최소한의 기능만 구현한버전)을 만들때 완벽한 분리보다 빠른 출시가 더 중요할수 있다

따라서 의도적으로  책임을 변합하는것은 위반이 아니라 전략적 선택이 될수있다

중요한것은 다음과 같은 질문에 명확히 답 할수 있는가이다

  1. Trade-off를 인지하고 있는가? - SRP 위반 vs 의식적 선택
  2. 나중에 분리할 수 있도록 경계를 명확히 했는가? - Extract 가능성
  3. 컨텍스트가 바뀌면 리팩토링할 준비가 되어 있는가? – 기술부채 관리

책임의 일부 작은 조각이 전체와 비슷한 기하학적 형태

모든것은 크기에 맞는 책임이 있다 이 말은 소프트웨어 아키텍처의 핵심인 추상화 레벨과 직접적으로 연결된다 단일책임원칙은 단순히 클래스 하나에만 적용되는 규칙이 아니라 아주 작은 단위부터 거대한 시스템 단위까지 동일하게 적용된다예시세포(Function/Method)심장 근육을 이루는 세포 하나하나의 책임은 아주작고 구체적이다SW에서의 적용-> 함수나 메서드는 반복문 조건문 변수 할당 같은 가장 구체적인 책임을 진다기관(Object/Class)수많은 세포가 모여서 심장이라는 기관을 이룬다 따라서 책임의 크기도 커진다 단순 수축이 아니라 혈액을 펌프질해서 순환시킨다는 더 높은 차원의 책임이 생겼다 심장은 세포들의 구체적인 수축원리를 캡슐화하고 펌프라는 기능만제공한다SW에서의 적용->객체는 데이터를 관리하고 상태를 변경하는 비즈니스 로직단위의 책임을 진다신체 시스템(Component/Package)심장과 혈관이 모여서 순환계를 만든다 여기서 책임은 더 추상적이고 신체 전테에 산소와 영양분을 공금한다는 큰 목표를 가지고 있다 SW에서의 적용-> 패키지나 모듈은 결제시스템,회원 관리 같은 큰 기능 단위의 책임을 진다코드를 짤때 주로하는 실수는 이 책임의 크기를 혼동하는것이다 단일책임원칙의 진정한 의미는 각자가 서있는 위치(추상화레벨)에서 해야할 단 하나의 일에 집중하는 것이다 각자의 위치에서 각자의 책임이 명확할때 문제가 생겨도 원인을 빠르게 수습할수 있다SRP의 핵심은 단순히 클래스를 잘게 쪼개는게 목적이 아니라

  1. 이 기능이 이 책임을 위해 존재하는가?(책임과 기능의 구분)
  2. 이 코드가 지금 이 크기(Level)에서 다루어야 할 책임인가?(추상화 레벨의 준수)

위의 두가지 질문을 끊임없이 반복하는것이다 ㄴ