본문 바로가기

컴퓨터공학

[Clean Architecture] - SOLID 원칙 SRP (1)

반응형

해당 시리즈는 로버트 C.마틴의 Clean Architecture 책을 보며 공부한 내용을 정리해 놓은 글이다. 대부분의 파이썬 예제들은 ChatGPT와 함께 공부하며 정리하였다. 

 

오늘은 좋은 아키텍쳐를 정의하는 SOLID 원칙 중 SRP에 대해 다룬다. SOLID 원칙에 대한 다른 포스팅들은 아래 링크에서 확인할 수 있다. 

 

SOLID 원칙 시리즈

해당 시리즈는 로버트 C.마틴의 Clean Architecture 책을 보며 쉬운 이해를 위해 ChatGPT와 함께 공부한 내용을 정리해 놓은 글입니다.

 

SRP: 단일 책임 원칙

OCP: 개방-폐쇄 원칙

LSP: 리스코프 치환 원칙

ISP: 인터페이스 분리 원칙

DIP: 의존성 역전 원칙


 

SRP: 단일 책임 원칙

- 하나의 모듈은 반드시 하나의 액터에 대해서만 책임져야 한다.

- 클래스는 하나의 기능을 수행하고, 해당 클래스의 변경 이유는 하나여야 한다. 

 

가령 다음과 같은 Employ 클래스가 있다고 하자. 

class Employ:
    def __init__(self, name, regular_hours, hourly_rate):
        self.name = name
        self.regular_hours = regular_hours
        self.hourly_rate = hourly_rate

    def calculate_pay(self):
        pay = self.regular_hours * self.hourly_rate
        print(f"{self.name}'s pay: ${pay}")
        return pay

    def report_hours(self):
        print(f"{self.name}'s regular hours worked: {self.regular_hours} hours")
        return self.regular_hours

    def regular_hours_algorithm(self):
        if self.regular_hours > 40:
            return 40  # 초과 근무가 있으면 40시간만 정산
        return self.regular_hours

 

위의 코드는 아래와 같은 다중 액터를 지닌다.

- 회계팀: calculate_pay()

- 인사팀: report_hours()

 

이렇게 다중 액터를 가지는 모듈의 경우 여러 문제들이 생길 수 있는데, 다음 2가지가 가장 대표적이다. 

 

우발적 중복

두 매서드가 동시에 접근하고 있는 regular_hours_algorithm을 한쪽 팀의 요청으로 수정할 일이 생겼다고 하자. 다른 한쪽에서는 해당 코드가 바뀌었는지에 대한 인지조차 어려운 상황이 발생할 수 있다.

 

병합

두 팀에서 각각 기능 수정을 위해 Employee 클래스를 체크아웃받은 후 코드를 변경할때, 충돌이 날 가능성이 농후하다. 

 

위의 코드를 액터에 따라 클래스를 분리하고, 퍼사드 패턴을 사용해서 관리해보자.

퍼사드 패턴: 복잡한 서브시스템을 간단한 인터페이스로 숨기는 디자인 패턴

class PayCalculator:
    def __init__(self, regular_hours, hourly_rate):
        self.regular_hours = regular_hours
        self.hourly_rate = hourly_rate

    def calculate_pay(self):
        pay = self.regular_hours * self.hourly_rate
        print(f"Pay: ${pay}")
        return pay


class HourReporter:
    def __init__(self, regular_hours):
        self.regular_hours = regular_hours

    def report_hours(self):
        print(f"Regular hours worked: {self.regular_hours} hours")
        return self.regular_hours


class RegularHours:
    def __init__(self, regular_hours):
        self.regular_hours = regular_hours

    def regular_hours_algorithm(self):
        if self.regular_hours > 40:
            return 40  # 초과 근무가 있으면 40시간만 정산
        return self.regular_hours


class EmployeeFacade:
    def __init__(self, name, regular_hours, hourly_rate):
        self.name = name
        self.pay_calculator = PayCalculator(regular_hours, hourly_rate)
        self.hour_reporter = HourReporter(regular_hours)
        self.regular_hours = RegularHours(regular_hours)

    def calculate_pay(self):
        regular_hours = self.regular_hours.regular_hours_algorithm()  # 정상 근무 시간 계산
        return self.pay_calculator.calculate_pay()  # 급여 계산

    def report_hours(self):
        self.hour_reporter.report_hours()  # 근무 시간 보고


# 사용 예시
employee = EmployeeFacade(name="John", regular_hours=45, hourly_rate=20)
employee.calculate_pay()  # 급여 계산
employee.report_hours()   # 근무 시간 보고

 

 

 

 

 

 

 

반응형