숫자 야구 과제 중 트러블슈팅

권승용(Eric)·2024년 11월 7일

TIL

목록 보기
7/38

트러블슈팅 방법

  • 배경 : 어떤 현상을 발견해서
  • 발단 : 이런 장애가 생길 수 있다는 것을 인지했고,
  • 전개 : 장애를 대응, 해결하던 와중에
  • 위기 : 또 다른 장애 발견 또는 간단하게 해결할 수 없다는 것을 알게되어서,
  • 절정 : 근본적인 해결을 위해 이런 방법으로 접근하였다.
  • 결말 : 따라서, 이런이런 방법을 통해 근본적으로 해결 및 앞으로 유지, 보수에 용이하게 개선하게 되었다.

배경

  • 숫자 야구 과제를 진행하던 중, Lv1~Lv6를 진행하며 최종적으로 하나의 Lv6 야구 게임을 제공하는 것이 아니라, 사용자가 Lv1부터 Lv6까지의 각 단계의 동작을 확인할 수 있도록 각각의 단계에 맞는 야구 게임을 제공하려고 한다.

발단

  • 이 때 각 레벨마다 독립적인 구현을 제공한다면 중복되는 코드가 많이 발생한다.
    • 사용자 입력 검증 / 랜덤 숫자 제공 등의 중복되는 로직들을 매번 구현해 주어야 함.
    • 각 레벨은 바로 이전 레벨에서 작성하거나 개선한 로직을 재사용하기 때문에 중복 코드 발생 가능.

전개

  • 중복 코드를 줄이고, 레벨이 높아짐에 따라 확장성 있는 코드를 구현하기 위해 BaseballGame이라는 베이스 클래스를 구현, BaseballGame -> BaseballGameLevel1 -> BaseballGameLevel2 와 같은 순서로 레벨이 증가할 때 마다 바로 아래 레벨의 야구 게임 클래스를 상속받는 방식으로 구현.
  • 각 단계별로 기능이 확장되기 때문에 수직적 확장인 상속이 적합하다고 생각

위기

  • 상속을 통한 기능 확장 과정에서 사용자 입력에 따라 다른 동작을 제공해줘야 하는 경우가 생김.
class BaseballGameLevel4: BaseballGameLevel3 {
    override func startGame(questioner: any Player, answerer: any Player) throws {
        print("환영합니다! 원하시는 번호를 입력해주세요")
        
        while true {
            print("1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기")
            
            // 게임 시작하기 / 기록 보기 / 종료하기는 하위 클래스에서 구현할 내용.
            // 지금고 같은 구조라면 하위 클래스에서 startGame을 재정의하면서 중복 코드를 작성할 수 밖에 없음
            if let input = readLine(), let num = Int(input) {
                switch num {
                case 1:
                    try super.startGame(questioner: questioner, answerer: answerer)
                    
                case 2:
                    break
                    
                case 3:
                    break
                    
                default:
                    break
                }
            }
        }
    }
}

절정

  • 이러한 중복 코드 방지를 위해 각각의 case마다 일어날 작업을 함수로 분리, 해당 함수를 통해 하위 클래스에서 필요한 기능을 재정의할 수 있도록 변경
class BaseballGameLevel4: BaseballGameLevel3 {
    override func startGame(questioner: any Player, answerer: any Player) throws {
        print("환영합니다! 원하시는 번호를 입력해주세요")
        
        outerLoop: while true {
            print("1. 게임 시작하기 2. 게임 기록 보기 3. 종료하기")
            
            if let input = readLine(), let num = Int(input) {
                switch num {
                case 1:
                    try proceedGame(questioner: questioner, answerer: answerer)
                    
                case 2:
                    showRecord()
                    
                case 3:
                    endGame()
                    break outerLoop
                    
                default:
                    break
                }
            }
        }
    }
    
    func proceedGame(questioner: Player, answerer: Player) throws {
        try super.startGame(questioner: questioner, answerer: answerer)
    }
    
    func showRecord() {}
    
    func endGame() {}
}

결말

  • 함수 분리를 통해 하위 클래스에서 재정의할 수 있는 스코프를 생성할 수 있었고, 중복 코드를 줄이며 기능을 확장할 수 있었다.
  • 동시에 상속 관계에서는 상위 클래스의 프로퍼티 / 메소드들을 모두 알기 어렵기 때문에, 상속 관계가 깊어질수록 유지보수가 어려워질 것 같다는 생각도 들었다.
  • 각 레벨별로 제공되는 기능을 더 깔끔하게 추상화해보고 싶다...
profile
ios 개발자에용

0개의 댓글