- 팀 프로젝트(2인)
- 프로젝트 기간: 2021.10.11 ~ 2021.10.15
Naming
Coding Convention
switch
repeat-while
guard
if-else
struct
enum
method
default parameter
Read-Only Computed Properties
static property
CustomStringConvertible
,
&&
Optional
CaseIterable
재귀함수
LLDB
가위바위보 게임을 구현합니다.
- 순서도의 작성 기준
- 일반화, 추상화, 은닉화, 캡슐화
- 코딩 컨벤션 정하기
- commit 스타일과 커밋 단위의 기준
- 적절한 Naming
- 코드 내부 가독성을 높이기 위한 여러가지의 방법
- 메소드 순서
- 메소드를 한가지의 기능 별로 분리, 확장성 고려
- 사용자 정의 타입을 원하는 형식의 문자열로 출력하게 만들기 위한 방법
- 타입 내부 property를 외부에서 바로 사용하는 방법
-
repeat-while문
에서, 콤마
를 쓰니 에러가 났다.&&
랑,
의 정확한 쓰임새가 궁금해졌다. -
메소드명을 지을 때 파라미터명과 연결해서 지어주는 것이 나은건지? 아니면 메소드명에 한꺼번에 지어주는 것이 알맞은지 헷갈렸다. ex)
validate(userInput:) validateUserInput(_ input:)
-
조건문을 변수로 나누어서 만드는 것이 나은 방법인지, 하나로 연결해서 만드는 것이 나은 방법인지 판단이 어려웠다.
private func isVictory(_ playerNumber: String?, _ opponentNumber: String) -> Bool { let winningCaseA = playerNumber == "1" && opponentNumber == "3" let winningCaseB = playerNumber == "2" && opponentNumber == "1" let winningCaseC = playerNumber == "3" && opponentNumber == "2" return winningCaseA || winningCaseB || winningCaseC }
private func isPlayerWin(_ playerNumber: String?, _ opponentNumber: String) -> Bool { return (playerNumber == scissor && opponentNumber == paper) || (playerNumber == rock && opponentNumber == scissor) || (playerNumber == paper && opponentNumber == rock) }
-
,
는condition
을이어붙이는 용도
로 쓰는 것이고,&&
는두개의 boolean expression
을파라미터로 받는 논리 연산자
이다.while, if, guard문
에는condition-list
를 쓰지만,repeat-while문
에서는condition
만 쓸 수 있다. 즉, 콤마로 여러 condition을 이어붙이는 것이 허용된 곳과 아닌 곳이 있는 것이다. -
타입의 프로퍼티를 외부에서 바로 사용하려면
static
키워드를 추가해줌으로써 정적 프로퍼티로 만들어야 한다. -
조건문을 한 줄로 return 해주는 것 보다 switch로 조건문을 넣어주는 것이 가독성 향상에 도움이 된다.
// 이전 코드 private func isPlayerWin(_ playerNumber: String?, _ opponentNumber: String) -> Bool { return (playerNumber == scissor && opponentNumber == paper) || (playerNumber == rock && opponentNumber == scissor) || (playerNumber == paper && opponentNumber == rock) } // 변경 후 private func isPlayerWin(_ playerHand: PlayerOption?, _ opponentHand: PlayerOption) -> Bool { switch (playerHand, opponentHand) { case (.scissor, .paper), (.rock, .scissor), (.paper, .rock): return true default: return false } }
-
reset
commit한 것이 마음에 들지 않을 때 reset을 이용하여 초기화 해줄 수 있다.--hard
옵션을 사용하면 작업중인 내용을 가져오지 않고 완전히 삭제가 된다. 아직 commit을 하지 않았다면 git reset hard를 사용하는 것은 주의해야 한다. -
reflog
해당 명령어를 사용하면 reset으로 지웠던 모든 이력을 볼 수 있다.
- 순서도 작성 시 따로 분리하여 그려보는 방식
- 메소드 확장성을 고려해보는 방법
- 코드 내부 가독성을 높이기 위한 방법
- Read-Only Computed Properties
- CustomStringConvertible 프로토콜의 용도
- CaseIterable 프로토콜의 용도
- Optional과 non-Optional을 비교하기
- guard문, if-else문, switch문의 적절한 활용방법
- static property의 용도
- 가위, 바위, 보 프로퍼티를 삭제한 후
enum
으로 분리 validate
메서드를 삭제하고,recieveUserInput
내부에if문
을switch문
으로 수정isWrong
메서드명 변경 (isWrong > isWrongInput)isDraw
파라미터의 순서를isPlayerWin
의 파라미터 순서와 동일하게 수정해주었음 (player
가 앞으로 올 수 있도록 기준을 정함)RockPaperScissorsGame
내부에 승패판정 메소드를 따로 분리하여 구조체(GameJudgment
)로 생성함Message
내부desctiption
프로퍼티를 하단으로 순서를 변경함- enum
RockPaperScissor
이름을PlayerOption
으로 변경 startGame
메서드 내부에 있던 승패를 출력하는if문
을printGameResult()
메서드로 분리함RockPaperScissorsGame
내부에 있는randomHand
프로퍼티를playerOption
내부로 위치를 변경함
묵찌빠 게임을 구현합니다.
- 여러가지 문제 해결방법이 있을때, 그 중에서 한 가지를 선택하는 기준들
- 재귀함수와 반복문의 적절한 사용법
- 가위바위보에서 활용하였던 승패판정을 묵찌빠에서도 활용할 수 있는 법
- 적절한 Naming
- 들여쓰기를 최대한 줄이는 코드 작성법
- 코드의 가독성
- guard문 안에서 재귀함수를 호출하면 앞서 호출되었던 재귀함수는 종료되는 것이 아닐까?
- 반복문과 재귀함수를 선택할 때 어떤 점을 고려해야 할까?
- 코드의 가독성만을 위해서 사용자 정의 타입을 만드는 것이 과연 적절한 것일까?
-
재귀함수가 guard문 안에서 끝나는지 확인하기 위해 디버깅모드를 통해 해결하였다.
- 재귀 호출을 할 때 메모리에 어떤 변화가 있는지 확인해보았다.
디버깅모드
로 통해 확인할 수 있다.Thread
내부에 재귀함수가 들어가는데 호출된 재귀함수들이Queue
에 하나씩 쌓이다가 마지막에 호출된 재귀 함수가guard
를 모두 통과하여 함수가 종료되면 쌓였던 재귀 함수들이 차례대로return
이 되면서Queue
에서 제거되는 모습을 볼 수 있었다.
- 재귀 호출을 할 때 메모리에 어떤 변화가 있는지 확인해보았다.
-
재귀함수를 구현하고 디버깅을 하니 복잡하고 어려웠다. 메모리 측면에서도 이 프로젝트에서는 큰 차이는 없겠다만 성능적으로는 좋지 못하다는 사실을 알아냈고, 디버깅을 위해서라도 반복문으로 고쳐야겠다는 생각이 들어서 코드를 재수정 하였다.
반복문
과재귀함수
의 차이- 반복문은 속도가 상대적으로 빠르다는 장점이 있지만, 코드가 복잡해지는 단점이 있다. 재귀함수는 상대적으로 간결한 코드로 작성할 수 있다는 장점이 있지만 반복문에 비해 속도가 느리다는 단점이 있다. 재귀함수는 함수를 반복적으로 호출하기 때문에 스택 메모리를 사용한다. (스택 오버플로우가 발생할 수 있다.) 반면 반복문은 메모리 힙을 사용한다.
- 성능 측면에서만 본다면 재귀함수는 사용하지 않는 것이 맞다. 반복문으로 구현했을 때 보다 메모리나 속도 등 성능적인 측면에서 많이 뒤쳐지기 때문이다. 하지만 예전처럼 Hardware가 좋지 못해 Software의 속도를 극한까지 끌어올려야 하는 시대가 아니기 때문에 가독성도 고려하여 프로그래밍을 해야한다. 특히 여러사람이 개발에 참여한다면 가독성은 더욱 중요하다. 결국 프로그램의 목적에 맞게 판단해서 사용해야한다.
- 디버깅모드 시 콘솔창에
n
을 적고 엔터를 누르면 다음 코드로 이어진다.
repeat-while문
내부 코드를 가독성 있게 고쳐보고 싶었으나 더이상 좋은 방법이 떠오르지가 않았다.- 재귀함수로 하는 것 보다 반복문으로 재구현 하였으나 어떤 것이 적절한 방법인지 판단하는데 있어서 어려움이 있었다.
- 가독성만을 위해 사용자 정의 타입을 만드는 것이 과연 적절한 것인지에 대한 의문을 풀지 못했다.
PlayerOption
내부randomHand
하드코딩 개선- 사용자의 턴을 나타냈던
Bool
타입을Turn
타입으로 새롭게 만들어서 개선 changeTurn
내부 조건문을isWrongInput
메서드로 대체- 묵찌빠 게임 타입 내부에
startGame
메서드에서isContinued
를repeat-while문
이 아니라changeTurn
메서드 내부에서 바꿔주도록 로직 변경 Turn
타입에CustomStringConvertible
을 적용시킴으로서printGameResult
삭제가 가능해졌다.