ABOUT

성능과 운영 안정성을 함께 끌어올리는 개발자입니다.

92% Positional Error Reduction
79% p95 Latency Improvement
90%+ Long Tasks Reduction

2022.02 · 한국장학재단

우수 멘티

한국장학재단 사회 리더 대학생 멘토링 IT

2022.10 · 동작구청

우수 인재상

동작구청 우수 SW 인재

2025.05 · (주) 그랩

프로그래밍 우수상

(주) 그랩 우수 프로그램 개발

2025.05 · AWSKRUG

AWS한국사용자모임 발표

AI agent 스크립트 튜닝 관련 발표

ComputerScience

Development

Engineering

Trouble Shooting

GUESTBOOK

첫 마음부터
함께 나누는 온기

방명록 작성하러 가기

SUBSCRIBE

최신소식을
편하게 만나보세요.

SRP (Single Responsibility Principle)

정의

SRP는 객체(또는 모듈)가 하나의 책임만 가져야 한다는 원칙입니다.

흔히 “클래스는 하나의 일만 해야 한다”로 외우지만, 실무에서 더 정확한 해석은 “변경 이유(Reason to Change)가 하나여야 한다” 입니다. 즉, 한 클래스가 서로 다른 이유로 자주 변경된다면 SRP가 깨지고 있을 가능성이 큽니다.

핵심 메시지

“SRP는 ‘기능을 쪼개는 기술’이 아니라,
변경의 원인을 한 곳에 가두는 기술이다.”

- 변경이 퍼지면 비용이 폭발한다 -

핵심 개념

SRP의 핵심은 책임(Responsibility)이 아니라 변경 이유(Reason to Change)입니다.

책임을 “기능 목록”으로 나누면 과도하게 쪼개질 수 있습니다. 대신 실무에서는 누가(어떤 이해관계자) 이 코드를 바꾸게 만드는가를 기준으로 책임을 나누는 편이 더 정확합니다.

관점 질문 신호
변경 이유 이 클래스는 왜 바뀌는가? 서로 다른 이유로 자주 바뀌면 SRP 위반 가능성
이해관계자 누가 이 코드를 바꾸게 만드는가? 예: 기획 변경 vs 운영/보안 규정 vs 성능 최적화가 한곳에 섞임

판단 기준

SRP 위반을 빠르게 찾는 실무 질문

아래 질문에 “예”가 많을수록 SRP가 깨졌을 가능성이 큽니다.

  • ✔️ “정책 변경”이 오면 수정하는 코드와 “기술 변경(DB/캐시/프레임워크)”이 오면 수정하는 코드가 한 클래스에 섞여 있나?
  • ✔️ 한 메서드 수정이 다른 기능의 버그로 이어지는 일이 잦은가?
  • ✔️ 테스트가 커지고(Mock/스텁이 과도), 변경 영향 범위가 넓게 퍼지는가?
  • ✔️ 한 클래스가 “검증 + 계산 + 저장 + 포맷팅 + 로깅”까지 다 하고 있나?

예시

“주문 처리”에서 SRP가 깨지는 대표 패턴
BAD: 한 클래스가 너무 많은 변경 이유를 가짐
// 개념 예시 (BAD)
// - 할인 정책 변경
// - 재고 검증 규칙 변경
// - 결제 방식 변경
// - DB 저장 방식 변경
// - 로그/포맷 변경
// 서로 다른 이유로 계속 바뀜 → SRP 위반 신호
class OrderService {
  public int checkout(Order order) {
    validate(order);            // 검증
    int price = calcPrice(order); // 계산/정책
    saveToDb(order, price);     // 저장(인프라)
    logAsJson(order, price);    // 로깅/포맷
    return price;
  }
}
GOOD: 변경 이유별로 책임을 분리(조립은 서비스에서)
// 개념 예시 (GOOD)
interface OrderValidator { void validate(Order order); }
interface PricingPolicy { int priceOf(Order order); }
interface OrderRepository { void save(Order order, int price); }
interface OrderLogger { void log(Order order, int price); }

class CheckoutService {
  private final OrderValidator validator;
  private final PricingPolicy pricing;
  private final OrderRepository repo;
  private final OrderLogger logger;

  CheckoutService(OrderValidator v, PricingPolicy p, OrderRepository r, OrderLogger l) {
    this.validator = v; this.pricing = p; this.repo = r; this.logger = l;
  }

  public int checkout(Order order) {
    validator.validate(order);     // 검증 변경은 Validator에서
    int price = pricing.priceOf(order); // 정책 변경은 Pricing에서
    repo.save(order, price);       // 저장 변경은 Repo에서
    logger.log(order, price);      // 로깅 변경은 Logger에서
    return price;
  }
}

리팩터링

SRP를 회복하는 단계(실무 루틴)
1
변경 이유를 적는다 “정책/인프라/표현/보안/성능” 등
2
바뀌는 것끼리 묶는다 같이 바뀌는 코드를 같은 모듈로
3
조립은 상위에서 한다 DI/팩토리/서비스에서 조합

주의점

SRP는 “무조건 쪼개기”가 아니라 “적절한 경계”가 핵심입니다.

SRP를 과하게 적용하면 파일/클래스가 너무 잘게 쪼개져 흐름 파악이 어려워질 수 있습니다. 그래서 “한 번에 이해 가능한 단위”를 유지하면서, 변경 이유가 섞이는 지점만 정확히 분리하는 것이 실무적으로 가장 효율적입니다.

핵심 요약

한 번에 정리

✅ 핵심 요약

  • ✔️ SRP는 “하나의 기능”이 아니라 하나의 변경 이유(Reason to Change)를 갖게 하는 원칙이다.
  • ✔️ 서로 다른 변경 이유가 한 클래스에 섞이면 수정 범위가 커지고 버그 확률이 올라간다.
  • ✔️ 분리 후에는 상위 계층에서 조립(DI)하고, 테스트는 더 작고 명확해진다.
728x90