Giter Club home page Giter Club logo

ios-bank-manager's Introduction

iOS 커리어 스타터 캠프

💰 은행창구 매니저

프로젝트 기간: 2023.03.06 ~ 2023.03.17

팀원: 👨🏻‍💻kaki, 👨🏻‍💻송준 | 리뷰어: 👨🏻‍💻도미닉

동시성 프로그래밍을 활용하여 은행창구 매니저 콘솔 앱 및 UI 앱 구현

목차

  1. 타임라인
  2. 프로젝트 구조
  3. 실행 화면
  4. 트러블 슈팅
  5. 참고 링크

⏰ 타임라인

타임라인 - 23.03.06 (월): Linked List Queue 구현, Unit Test 구현 (STEP1 PR)
- 23.03.07 (화): STEP1 리뷰 사항 수정 (Refactor)
- 22.03.08 (수): BankManager 구현 및 실행 (STEP2 PR)
- 22.03.09 (목): STEP2 리뷰 사항 수정 (변수명 수정, 함수 분리)
- 22.03.10 (금) : DispatchQueue로 은행업무 구현 (STEP3 PR)
- 22.03.13 (월) : STEP 3 리뷰 사항 수정 (매직넘버 처리, 함수 분리, 코드 컨벤션)
- 23.03.14 (화): STEP4 StackView를 활용한 UI 구현, 로직에 대한 비동기 처리
- 22.03.15 (수): STEP4 Timer 구현, 버튼 구현 (STEP4 PR)
- 22.03.16 (목): STEP4 리뷰 사항 수정


✍🏻 프로젝트 구조

ConsoleApp폴더구조

UIApp폴더구조


✨ 실행 화면

은행창구 ConsoleApp 실행화면

콘솔앱실행

은행창구 ConsoleApp 종료화면

콘솔앱종료

은행창구 UIApp 실행화면

고객추가 버튼 실행 실행 중 초기화 실행 종료 후 초기화

🔥 트러블 슈팅

ConsoleApp

1. 테스트 코드 작성 시 given과 when 구분

아래와 같이 테스트 코드 작성 시 givenwhen에 무엇을 적어야할지 고민했습니다. given은 어떤 상황이 주어지고, when은 어떤 코드를 실행한다고 배웠습니다. 이 부분에 있어enqueue메서드는 given인지, when인지 헷갈렸습니다.

// 1번
func test_dequeue됐을경우_처음_enqueue된_데이터가_반환된다() {
        // given
        let expectation = "hello"
        // when
        sut.enqueue("hello")
        sut.enqueue("kaki")
        sut.enqueue("songjun")
        let result = sut.dequeue()!
        // then
        XCTAssertEqual(result, expectation)
    }

// 2번
func test_dequeue됐을경우_처음_enqueue된_데이터가_반환된다() {
        // given
        let expectation = "hello"
        sut.enqueue("hello")
        sut.enqueue("kaki")
        sut.enqueue("songjun")
        // when
        let result = sut.dequeue()!
        // then
        XCTAssertEqual(result, expectation)
    }

⚒️ 해결방법

given 은 테스트 환경을 만드는 것이고 when 은 테스트하고 싶은 중요 기능을 실행한다라고 나뉘어질 수 있습니다. 위 테스트에서 중요 기능은 dequeue이고 enqueue작업은 테스트 환경을 만들어주는 것이라 생각되어 2번 방법으로 테스트 코드를 작성했습니다.


2. 프로그램 실행 시간 확인

기존엔 고객 한 명당 0.7초씩 고정적으로 시간을 소요하기 때문에 프로그램 실행 시간을 고객수 * 0.7 초로 계산해주었습니다. 하지만 Step3로 넘어오며 대출 업무 고객은 1.1초, 예금 업무 고객은 0.7초로 각기 다른 시간이 소요되어 기존의 방식을 사용할 수 없었습니다.

⚒️ 해결방법

mutating func processBusiness() {
    let startTime = CFAbsoluteTimeGetCurrent()
    
    while !waitingQueue.isEmpty {
        guard let client = waitingQueue.dequeue() else { return }
        processBankTask(client)
    }
    group.wait()
    
    let wasteTime = CFAbsoluteTimeGetCurrent() - startTime
    presentBusinessResult(time: wasteTime)
}

CFAbsoluteTimeGetCurrent()를 사용하여 시작되는 시점의 시간을 프로그램 실행이 끝났을때의 시간에서 빼주는 것으로 총 소요시간을 계산할 수 있었습니다.

3. 비동기 코드를 넘기고 바로 뒤의 코드를 실행시키는 현상

업무에 관한 코드를 전부 비동기로 설정해주었더니 비동기 코드를 바로 끝내고 아예 기다리지 않은 채 뒤의 코드를 실행시키는 문제가 발생하였습니다.

⚒️ 해결방법

mutating func processBusiness() {
    while !waitingQueue.isEmpty {
        guard let client = waitingQueue.dequeue() else { return }
        processBankTask(client)
    }
    group.wait()
    
    presentBusinessResult(time: wasteTime)
}

private func processBankTask(_ client: Client) {
    if client.requstedTask == .loan {
        DispatchQueue.global().async(group: group) {
            loanSemaphore.wait()
            loanSemaphore.signal()
        }
    } else {
        DispatchQueue.global().async(group: group) {
            depositSemaphore.wait()
            depositSemaphore.signal()
        }
    }
}

DispatchGroup을 이용하여 비동기적으로 처리되는 작업들을 그룹으로 묶어주고, group.wait()을 사용하여 DispatchGroup의 수행이 끝나는것을 기다리게 해주어 문제를 해결하였습니다.

UIApp

1. DispatchQueue -> OperationQueue

초기화 버튼 기능 구현 시, 초기화를 누르면 스레드가 하던 일도 cancel이 되어야 하는데 DispatchQueue에서 진행중인 스레드를 멈출 방법을 찾을 수 없었습니다. 또한 main 스레드에서 작업 처리 시, qos를 변경해주지 않고 dispatch_semaphore_wait 및 dispatch_group_wait을 사용하는 경우 에러가 발생하였습니다.

⚒️ 해결방법

private let loanQueue = OperationQueue()
private let depositQueue = OperationQueue()

private func processBankTask(_ client: Client) {
    if client.requstedTask == .loan {
        loanQueue.maxConcurrentOperationCount = 1
        loanQueue.addOperation {
            processPersonalBankTask(client)
        }
    } else if client.requstedTask == .deposit {
        depositQueue.maxConcurrentOperationCount = 2
        depositQueue.addOperation {
            processPersonalBankTask(client)
        }
    }
}

DispatchQueue 대신 OperationQueue를 사용하여 문제를 해결하였습니다. 또한 DispatchQueue에서 불가능했던 스레드를 멈추는 것 또한 cancelAllOperations() 메서드를 사용하여 해결할 수 있었습니다.

2. StackView Alignment 문제

스택뷰에 autoLayout값이 정확하게 들어가지 않아 생기는 문제점을 발견했습니다. alignment를 default값(fill)으로 넣으면 아래 오류 사항처럼 UI가 정상적으로 작동하지 않습니다.

⚒️ 해결방법

alignment값을 top으로 주어 문제를 해결했습니다.

오류 사항 오류 사항 해결


참고 링크

ios-bank-manager's People

Contributors

kak1x avatar kimseongj avatar yagom avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.