---
# System prepended metadata

title: 은행창구 매니저 PR (step 3)

---

# 은행창구 매니저 PR (step 3)

@havilog
안녕하세요 하비! 코낄이, 베토입니다.
step3 구현을 다 하고 PR 보냅니다.

## 고민했던 점 & 조언받고 싶은 점
### 1️⃣ 동시성 구현 방법 선택 이유
Swift에서 동시성을 구현하는 방법으로는 GCD, Operation 두 가지 방법을 고려했습니다. 
GCD는 Swift의 동시성 구현 방법으로 가장 먼저 등장한 기본적인 방법이고, Operation은 GCD를 기반으로 더 객체지향적으로 등장한 개념이라고 합니다.

저희는 동시성 프로그래밍의 개념을 처음 접하기 때문에, 가장 기본적인 GCD를 활용한 방법으로 구현해보았습니다.

### 2️⃣ 총 업무시간 산출 방법 변경
저희는 총 인원을 `numberOfClient`라는 변수에 `clientQueue`가 `dequeue` 될 때마다 늘려주고 최종적인 인원이 `numberOfClient`에 들어가면 `numberOfClient` 변수에 `0.7`을 곱한 숫자를 총 업무시간으로 출력하였습니다.

하지만 step3의 동시성 프로그래밍을 하면서 기존의 산출 방법으로 동시에 수행되는 작업들의 총 업무시간을 나타내기엔 힘든 부분이 있었습니다.

따라서 현재는 `Foundation` 내장 함수인 `CFAbsoluteTimeGetCurrent()`을 활용하여 작업을 수행하기 전에 시간을 구해주고 작업이 전부 끝난 뒤 시간을 구하여 그 차이를 나타내는 식으로 코드를 작성하였습니다.

```swift
private func measureProcessTime(_ process: () -> ()) -> Double {
    let startTime = CFAbsoluteTimeGetCurrent()
    process()
    let processTime = CFAbsoluteTimeGetCurrent() - startTime
        
    return processTime
}
```

### 3️⃣ Banker 타입의 인스턴스가 불필요했던 점
이번 스텝에서 3명의 은행원이 근무하고 2명은 예금업무를, 1명은 대출업무를 수행하도록 하는 요구사항이 있었습니다. 요구사항에 따라 직관적으로 `Bank` 타입 내에 `bankers: [Banker]` 프로퍼티를 구현하는 방법으로 접근하려고 했습니다. 

그런데 GCD를 활용하여 동시성을 구현하다 보니 **`businessQueue: DispatchQueue` 에 의해 관리되는 스레드 자체가 은행원의 역할을 수행**한다고 생각하게 되었습니다.
``` swift
final class Bank {
    private var clientQueue: Queue<BankClient> = .init()
    private var numberOfClient: Int = 0
    
    private let businessQueue: DispatchQueue = .init(label: "bankerDispatchQueue", attributes: .concurrent)
    private let depositSemaphore: DispatchSemaphore = .init(value: 2)
    private let loanSemaphore: DispatchSemaphore = .init(value: 1)
    
    ...
}
```
`DispatchSemaphore` 타입의 프로퍼티로 각각의 예금, 대출업무를 수행할 스레드의 수를 제한해주고 `businessQueue`에 dispatch 해주기만 하면 알아서 작업이 종료된 스레드에 적절히 분배되는것을 확인했습니다.

따라서 `Banker` 인스턴스가 더이상 필요하지 않게 되었고, 다음과 같이 인스턴스의 생성을 제한하고, 메서드는 타입 메서드로 변경했습니다.
``` swift
struct Banker {
    private init() {}
    
    static func receive(client: BankClient) {
        print("\(client.waitingNumber)번 고객 \(client.businessType.rawValue)업무 시작")
        Thread.sleep(forTimeInterval: client.businessType.time)
        print("\(client.waitingNumber)번 고객 \(client.businessType.rawValue)업무 완료")
    }
}
```