⚾️ 숫자야구 프로젝트
- 팀 프로젝트(3인)
- 프로젝트 기간: 2021.10.05 ~ 2021.10.08
목차
순서도
구현사항
- 함수만을 활용하여 숫자 게임의 기능을 구현
함수명 | 설명 |
---|---|
createRandomNumbers |
랜덤 숫자 생성하여 반환 |
classifyStrikeOrBall |
정답과 비교하며 스트라이크/볼 카운트 판정 |
classifyStrikesumUpScoresOrBall |
스트라이크/볼 카운트 합산하여 반환 |
sumUpScores |
두 점수를 전달하여 게임의 결과를 반환 |
printVictoryMessage |
승리 메세지를 출력하고 게임 카운트를 초기화 |
startGame |
게임 시작 |
고민되었던 점 및 해결방안
1. 순서도 작성
- 동료와의 커뮤니케이션을 위해서 순서도 작성 방법에 대해 익히고, 작성 기준에 대해 동료들과 같이 고민해보았다.
2. 커밋 컨벤션
- 첫 협업 프로젝트인 만큼 커밋 컨벤션 및 스타일을 미리 정리하여 작성 기준을 같이 맞춰보았다.
- 앞 기수 분들의 컨벤션들을 참고하여, 커밋 메세지 스타일 가이드 중 하나인
Karma Style
을 따르기로 결정했다.
3. 변수 및 함수 네이밍
- 함수 단위에 대해 고민해보았다. 한가지의 기능만 할 수 있도록 구상해보았고, 변수 또한 역할에 맞는 적절한 네이밍을 고민해보았다.
- 네이밍은 Swift API Design Guidelines 부분에 Naming 파트를 참고하여 구상했다.
Array
vs Set
4. - 랜덤한 3개의 숫자를 구하기 위해서 어떤 자료형을 사용할지 고민해보았다.
Int.random
메소드를 활용하여 랜덤한 정수를 뽑고, 중복되지 않는 3개의 숫자를 뽑아야 했는데, 반복문을 돌면서 어떤 자료형에 넣어주는 것이 더 효율적인지 고민해보았다. - 고민한 결과, Swift에는
shuffled
라는 메소드가 존재했고, 이를 활용하여 1부터 9까지의 정수를 배열로 생성한 후shuffled
메소드를 통해 배열을 섞고, 앞에 3개의 수만 반환하도록 구현하여 해결하였다.
5. 하드코딩 지양하기
- 하드코딩을 지양하기 위해서 변수의 단위 또한 고민하였다. 변수가 체이닝으로 인해 길어지는 경우, 혹은 조건문이 길어져서 한눈에 알아보기 힘든 경우 이를 쪼개서 별도의 변수로 선언해주므로써 재사용성, 가독성 향상에 힘써보았다.
- 함수 또한 하드코딩을 피하고, 재사용성을 높히기 위해 파라미터로 받을 수 있는 부분은 최대한 활용해보려고 하였다.
이외에도 여러가지 고민들을 하였다.
- 여러 함수에서 여러 번 사용되는 변수를 전역변수로 선언하는게 나을지 파라미터로 연달아서 전달하는게 나을지 고민
- 전역변수 선언 지양하기 위해 inout 키워드를 얼마나 사용할지 고민
- 한 개 이상의 값을 반환받을 때 배열을 사용할지 튜플을 사용할지 고민
- 하드코딩을 피하기 위해 변수를 따로 선언하는 방법
- 볼과 스트라이크 개수를 헤아리는 적절한 방법
- 올바른 범위의 값이 입력되었는지 검증하는 방법
코드리뷰를 통해 개선했던 것
- 들여쓰기 제한 조건 충족 위해 함수 내의 기능을 함수로 분리
- checkBallCount함수 내 if문 → classifyStrikeOrBall 함수로 분리
- startGame 함수 내 if문을 printVictoryMessage 함수로 분리
- 볼과 스트라이크 값을 반환할 때 배열 사용 → 튜플 사용
- 가독성 향상, 휴먼에러 및 하드코딩 방지
- 정수 0 → .zero 이용
- 정수 9 → victoryGoal 변수 생성
- 일일히 출력하던 부분을 reduce를 이용해 String으로 변환해 한 번에 출력하도록 수정
- guard문을 사용해 숫자를 한 번에 맞추는 경우를 제한했으나 한 번에 맞추는 경우는 드물고, 해당 부분의 가독성이 떨어져 삭제
- 함수 재사용성을 고려하여 3으로 지정했던 부분 수정
- 역할에 맞게 변수명 및 함수명 수정
- 값이 변경되지 않을 변수(var)를 상수(let)로 변경함
궁금했던 것
- refactoring의 스킬, 그리고 이러한 방법들이 왜 좋은걸까?
* 하나의 함수에서 너무 많은 일을 하고 있지 않은지 확인한다.
* 새로운 타입을 만들어 활용한다.
* 구현체를 직접적으로 의존하지말고, 추상화한 상위 클래스 또는 프로토콜을 의존하도록 설계한다.
* 객체의 내부 프로퍼티를 보호하고, 인터페이스를 추상화한다.
내가 생각했을 때는 함수의 길이가 너무 길어지는 것도 안좋지만
그렇다고 조금 길어지는 정도 가지고 분리하면 안되는 부분을 따로 분리하여
함수를 만들어도 가독성이 떨어지는 것 같다.
로직을 변경해보는 다른 방법도 한번 고려해보는 것이 좋을 것 같다는 생각이 들었다.
항상 어려운 상황이 닥치게 되면 피하려고만 했는데 그러지말고
일단 발생한 문제에 맞서서 다르게 고민해봐야겠다.
- 전역변수를 지양하는 이유는 무엇일까?
- 전역변수를 사용하면 생기는 문제
* 어디서 값이 변경되는지 추적이 어렵다.
* 프로그램 내 변수와 함수 등 여러 요소들과 간섭이 심해짐
* 전역 변수는 모든 곳에서 보이므로 네임스페임스가 오염된다.
* 전역 변수가 메모리 할당 외에 side effect가 있으면 문제 발생 소지가 크다. (상호 의존 등...)
* 전역 변수는 생명 주기가 길다. 따라서 메모리 리소스도 오랜 기간 소비한다.(메모리릭)
- 프로젝트 제약사항의 들여쓰기 기준
- 프로젝트 요구사항에 대해서 "이 부분은 고려해야하는 것이 아닌가?"하는 생각이 들 때면
요구사항을 제시한 사람에게 찾아가 물어보는 것이 가장 정확한 답이 될 수 있겠다.