Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 애니메이션
- collectionview
- UITextView
- uitableview
- combine
- tableView
- clean architecture
- 클린 코드
- rxswift
- Clean Code
- SWIFT
- 스위프트
- swiftUI
- swift documentation
- 리팩토링
- ribs
- RxCocoa
- ios
- Protocol
- 리펙토링
- MVVM
- UICollectionView
- Xcode
- HIG
- Human interface guide
- Refactoring
- 리펙터링
- map
- uiscrollview
- Observable
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[Clean Architecture] 1. 코드로 알아보는 SOLID - SRP(Single Responsibility Principle) 단일 책임 원칙 본문
Clean Architecture/Clean Architecture 코드
[Clean Architecture] 1. 코드로 알아보는 SOLID - SRP(Single Responsibility Principle) 단일 책임 원칙
jake-kim 2021. 9. 17. 01:450. 코드로 알아보는 SOLID - 클래스 다이어그램 필수 표현
1. 코드로 알아보는 SOLID - SRP(Single Responsibility Principle) 단일 책임 원칙
2. 코드로 알아보는 SOLID - OCP(Open Close Principle) 개방 폐쇄 원칙
3. 코드로 알아보는 SOLID - LSP(Liskov Substitution Principle) 리스코프 치환 원칙
4. 코드로 알아보는 SOLID - ISP(Interface Segregation Principle) 인터페이스 분리 원칙
5. 코드로 알아보는 SOLID - DIP(Dependency Inversion Principle, testable) 의존성 역전 원칙
6. 코드로 알아보는 SOLID - Coordinator 패턴 화면전환
7. 코드로 알아보는 SOLID - Network, REST (URLSession, URLRequest, URLSessionDataTask)
8. 코드로 알아보는 SOLID - 캐싱 Disk Cache (UserDefeaults, CoreData)
SRP(Single Responsibility Principle) 개념
- 하나의 모듈은 오직 하나의 Actor에 대해서만 책임져야 한다는 개념
- Actor: 한 명 이상의 사람들
- 모듈: 함수와 데이터 구조로 구성된 응집된(cohesive) 집합
- 주의: `단 하나의 일만 해야 한다는 원칙`은 함수의 개념
- 큰 함수들을 작은 함수들로 리펙토링 할 때 사용되는 더 저수준에서 사용되는 개념
SRP를 지키지 않으면 발생하는 문제
- SRP를 지키지 않는 코드: 하나의 모듈에 여러개의 Actor에 대해서 책임지는 경우
class Employee {
enum WorkType {
case finance // 재무
case human // 인사
case development // 개발
}
let workType: WorkType
init(workType: WorkType) {
self.workType = workType
}
}
- 3개의 Actor에 대해서 책임지는 Calculator 모듈
- calculatePay()와 reportHours()는 우연히 calculatedHour 프로퍼티에 접근
- save()를 통해 계산된 hour를 DB에 저장하지만, 두 곳에서 변경되고 있으므로 잘못된 정보 저장할 가능성 존재
class Calculator {
static var calculatedHour: Int?
/// 업무 시간을 계산해서, 회계팀장에게 보고
static func calculatePay() {
let workTime = regularHours()
calculatedHour = workTime
let pay = workTime * 1000
print("report \(pay) to CFO")
}
/// 업무 시간을 계산해서, 인사팀장에게 보고
static func reportHours() {
let workTime = regularHours()
calculatedHour = workTime
print("report \(workTime) to COO")
}
/// 현재 계산된 업무시간을 DB에 저장
static func save() {
guard let calculatedHour = calculatedHour else { return }
print("save \(calculatedHour) to DB")
}
/// 초과 근무를 제외한 업무 시간을 계산하는 메소드 (코드의 중복을 피하기 위한 편의 함수)
static private func regularHours() -> Int {
return Int.random(in: (0...100))
}
}
해결 방법
- 서로 다른 두 Actor가 공통으로 regularHours()와 같은 메소드를 사용할 수 없도록 애초에 코드를 분리하여 사전에 방지하고 데이터도 분리되도록 설계
- 코드를 분리하면 호출할 때 세 가지를 다 알고 있어야하므로, Facade패턴으로 사용
- 사용하는 쪽 (actor)
func main() {
let data = Data()
let financer = Employee(workType: .finance, data: data)
financer.employeeFacade.calculatePay()
let `operator` = Employee(workType: .human, data: data)
`operator`.employeeFacade.reportHours()
let developer = Employee(workType: .development, data: data)
developer.employeeFacade.save()
}
* 전체 소스 코드, SRPwithFacade.swift 참고: https://github.com/JK0369/SOLID
// SRPwithFacade.swift
class Employee {
enum WorkType {
case finance // 재무
case human // 인사
case development // 개발
}
let workType: WorkType
let data: Data
let employeeFacade: EmployeeFacade
init(workType: WorkType, data: Data) {
self.workType = workType
self.data = data
self.employeeFacade = EmployeeFacade(payCalculator: PayCalculator(data: data),
hourReporter: HourReporter(data: data),
employeeSaver: EmployeeSaver(data: data))
}
}
class EmployeeFacade {
private let payCalculator: PayCalculator
private let hourReporter: HourReporter
private let employeeSaver: EmployeeSaver
init(payCalculator: PayCalculator, hourReporter: HourReporter, employeeSaver: EmployeeSaver) {
self.payCalculator = payCalculator
self.hourReporter = hourReporter
self.employeeSaver = employeeSaver
}
func calculatePay() {
payCalculator.calculatePay()
}
func reportHours() {
hourReporter.reportHours()
}
func save() {
employeeSaver.save()
}
}
class PayCalculator {
var data: Data
init(data: Data) {
self.data = data
}
/// 업무 시간을 계산해서, 회계팀장에게 보고
func calculatePay() {
let workTime = Int.random(in: (0...100))
let pay = workTime * 1000
data.calculatedHourByPay = pay
print("report \(pay) to CFO")
}
}
class HourReporter {
var data: Data
init(data: Data) {
self.data = data
}
/// 업무 시간을 계산해서, 인사팀장에게 보고
func reportHours() {
let workTime = Int.random(in: (0...100))
data.calculatedHourByHour = workTime
print("report \(workTime) to COO")
}
}
class EmployeeSaver {
var data: Data
init(data: Data) {
self.data = data
}
/// 현재 계산된 업무시간을 DB에 저장
func save() {
print("save \(data.calculatedHourByPay), \(data.calculatedHourByHour) to DB")
}
}
class Data {
var calculatedHourByPay: Int?
var calculatedHourByHour: Int?
}
func main() {
let data = Data()
let financer = Employee(workType: .finance, data: data)
financer.employeeFacade.calculatePay()
let `operator` = Employee(workType: .human, data: data)
`operator`.employeeFacade.reportHours()
let developer = Employee(workType: .development, data: data)
developer.employeeFacade.save()
}
'Clean Architecture > Clean Architecture 코드' 카테고리의 다른 글
Comments