단일 책임 원칙: SRP

처음 SOLID 원칙을 접했을때 단일책임 원칙을 보고들었던 생각이 그렇다면, 모듈 하나는 하나의 책임, 즉 하나의 모듈은 하나의 일만 해야된다는 뜻으로 이해 했었습니다. 

그러나 단일 책임 원칙은 그게 아닙니다. 하나의 일만을 해야 하는것은 함수이며, 단일 책임 원칙의 의미는 "단일 모듈은 변경되는 이유가 하나여야 한다." ,"하나의 모듈은 하나의 액터에 대해서만 책임져야한다" 이런 뜻입니다. 여기서 말하는 액터란 해당 모듈을 특정한 목적을 의미하는듯 합니다. 또한 모듈이란 책에서는 하나의 소스코드 파일이라고 되어있지만, swift에서는 하나의 class 혹은 struct를 의미한다고 생각합니다.

 

단일 책임 원칙을 위배하는 경우

class Employee {
    
    func calculatePay() {
        //회계팀에서 기능을 정의, CFO에게 보고를 위해 사용
        regularHours()
    }
    
    func reportHours() {
        //인사팀에서 기능을 정의, COO에게 보고를 위해 사용
        regularHours()
    }
    
    func save() {
        //DB팀에서 기능을 정의, CTO에게 보고를 위해 사용
    }
    
    func regularHours() {
        //업무 시간을 계산하기위한 메소드
    }
}

Employee라는 클래스가 있습니다. calculatePay, reportHours, save라는 다른 세 액터(서로 다른 목적으로 사용)가 사용하는 메소드가 하나의 클래스에 결합되어있습니다. 이 상태로 코드를 실행시켜도 아무 문제가 없습니다. 하지만, 여기서 만약 CFO팀이 업무시간을 계산하는 방식을 변경한다고 해봅시다. 이에 regularHours의 코드가 변경이 되어버렸고, 이에 reportHours역시 영향을 받아버립니다. 이 문제는 서로 다른 액터가 의존하는 코드가 너무 가깝게(하나의 클래스에) 배치되었기 때문입니다. 단일 책임 원칙에서는 이를 분리하라고 합니다. 그럼 어떤식으로 분리 해야 할까요?

 

해결책

각 메소드를 각각의 클래스로 분리, 메소드가 없는 EmployeeData를 참조하도록 하면 공통된 코드 없이 각 메소드에서 구현

class PayCoculator {
    
    var employeeData = EmployeeData()
    
    func calculatePay() {
    }
}

class HourReporter {
    
    var employeeData = EmployeeData()
    
    func reportHours() {
    }
}

class EmployeeSaver {
    
    var employeeData = EmployeeData()
    
    func saveEmployee() {
    }
}

class EmployeeData {
    
}

다만 이런식으로 코드를 구성할 시 세가지 클래스를 인스턴스화 하고 추적해야 하기 때문에 퍼사드 패턴을 이용하여 하나의 인스턴스에 두는 방식을 사용합니다.

class EmployeeFacade {
    let payCoculator = PayCoculator()
    let hourReporter = HourReporter()
    let employeeSaver = EmployeeSaver()
    
    func calculatePay() {
        payCoculator.calculatePay()
    }
    
    func reportHours() {
        hourReporter.reportHours()
    }
    
    func save() {
        employeeSaver.saveEmployee()
    }
}

공부한 내용을 정리해 보자면 단일 책임 원칙에서 모듈은 하나의 목적을 책임을 지는 인스턴스를 의미합니다. 목적과 작업은 서로 다른 것입니다. 하나의 작업을 책임지는 것은 하나의 함수이고, 그 함수들을 가지고 특정한 목적으로만 쓰이는 인스턴스를 각각 분리하라는것 같습니다.