## 계산기 프로젝트 📱
### 0. 목차
- [1. 소개](#1-소개)
- [2. 팀원](#2-팀원)
- [3. UML](#3-uml)
- [4. 타임라인](#4-타임라인)
- [5. 실행 화면](#5-실행-화면)
- [6. 트러블 슈팅](#6-트러블-슈팅)
- [7. 팀 회고](#7-팀-회고)
### 1. 소개
- 계산기를 통해서 원하는 숫자 계산을 해보세요! 숫자 계산을 도와주는 계산기입니다.
- 사용하는 계산기 화면의 숫자패드와 기호를 통해 연산식을 작성한 후 결과를 확인할 수 있습니다.
### 2. 팀원
| [Danny](https://github.com/dannykim1215) | [Gama](https://github.com/forseaest/forseaest) |
| --- | --- |
| <img src="https://avatars.githubusercontent.com/u/154333967?v=4" width="200"> | <img src="https://avatars.githubusercontent.com/u/96014314?v=4" width="200"> |
### 3. UML
## 시퀀스 다이어그램

## 클래스다이어그램

### 4. 타임라인
| 날짜 | 제목 |
| --- | --- |
| 24.02.19(월) | 각자 작성한 계산기I 프로젝트 코드를 팀원에게 설명하는 소개하는 세션 |
| 24.02.20(화) 10:30 | CaculatorItemQueue 타입은 gama 코드 채택(Danny: 배열, gama: DoubleStack) |
| 24.02.20(화) 10:37 | Extension String 타입은 Danny 코드 채택(split 메소드 내부로직부분에서 공백을 기준으로 숫자와 연산자를 String으로 나눠 배열 요소 값으로 할당해서 String 배열로 반환) |
| 24.02.20(화) 10:50 | Operator 열거형 타입은 gama 코드 채택 |
| 24.02.20(화) 10:57 | Extension Double 타입, ExpressionParser 타입은 Danny 코드 채택 |
| 24.02.20(화) 11:04 | ExpressionParser 타입의 parse 메소드 내부의 for문 로직 변경(count-1로 반복문을 제어하는 것이 아닌 배열 데이터를 통해 반복이 되도록 변경)
| 24.02.20(화) 11:17 | Formula 타입은 Danny 코드 채택 |
| 24.02.20(화) 11:49 | CalculateError 열거형 타입 생성 및 케이스 추가, Formula 타입 내부의 result 메소드 내부 로직에 관련 에러 핸들링 진행 |
| 24.02.20(화) 11:55 | 계산기 프로젝트 Swift 파일 목적성에 맞게 폴더 정리 |
| 24.02.20(화) 12:04 | Fromula 타입 내부의 result 메소드 내부에 무한루프 while문 그리고 if문 -> while let 구문으로 변경 |
| 24.02.20(화) | CalculateError 열거형 타입의 케이스 세분화(emptyOperands, incorrectFormula), Formula 타입 내부의 result 메소드에 에러핸들링 진행 |
| 24.02.20(화) | CalculateItemQueue 유닛테스트 gama 코드로 채택 |
| 24.02.20(화) | Operator, Formula, ExpressionParser 유닛테스트 Danny 코드로 채택 |
| 24.02.20(화) | CalculaterItemQueue 내부에 큐 요소를 리턴하는 showQueue 메소드 생성, STEP1 PR 진행 |
| 24.02.21(수) | showQueue() 메소드를 저장프로퍼티로 변경후 Queue라는 네이밍으로 변경 |
| 24.02.21(수) | ExpressionParser 구조체의 parse() 함수에서 사용되는 변수명 변경 |
| 24.02.21(수) | CalculatorItemQueueTests 테스트 파일명과 클래스명 통일 |
| 24.02.21(수) | 유닛 테스트 파일에 개행 변경 및 given-when-then 패턴 주석 추가 |
| 24.02.21(수) | ViewController에 숫자, 사칙연산, 등호, AC 버튼을 눌렀을 때 호출하는 함수 구현 |
| 24.02.21(수) | Formula 유닛테스트 복잡한수식 케이스 추가 |
| 24.02.21(수) | ViewController 타입에 ceButtonTapped 메소드 기능 추가 |
| 24.02.21(수) | ViewConroller 타입에 signButtonTapped 메소드 기능 추가 |
| 24.02.21(수) | ViewController에 소수점 버튼 누를 때 호출하는 함수 dotButtonTapped() 구현 |
| 24.02.21(수) | FormulaTest 파일에 UnitTest 케이스 추가, STEP1 2차 PR 진행 |
### 5. 실행 화면
- 요구사항을 모두 충족하지는 못했으나, 리뷰어분과 상의 후 요구사항을 간략화하고 할 수 있는만큼 UI를 구현했습니다.
| <img src="https://cdn.discordapp.com/attachments/770882747580809258/1210479209986920488/Simulator_Screen_Recording_-_iPhone_15_Pro_Max_-_2024-02-23_at_15.46.57.gif?ex=65eab59d&is=65d8409d&hm=2379eb40f9ec90f7b4bd351cb697d8fb1211afd413ddaa4c464b7cf260335f3b&" width="290" height="640"> | <img src="https://cdn.discordapp.com/attachments/770882747580809258/1210482480579219487/Simulator_Screen_Recording_-_iPhone_15_Pro_Max_-_2024-02-23_at_16.04.41.gif?ex=65eab8a9&is=65d843a9&hm=799ab8172cac78934d937f51e9cd4a6269ec0aeac25165d7a9fb8e9b1c2ea89c&" width="290" height="640"> |
| --- | --- |
| 연산을 입력하고 =를 누르면 연산식이 뜹니다. | 연산을 입력하고 AC를 누르면 연산식이 모두 지워집니다. |
| <img src="https://cdn.discordapp.com/attachments/770882747580809258/1210483987835789372/Simulator_Screen_Recording_-_iPhone_15_Pro_Max_-_2024-02-23_at_16.10.48.gif?ex=65eaba10&is=65d84510&hm=3d39d54c2d41baf370bae6c15b0a21e8f0113de959d0732608200dec3c4ffa19&" width="290" height="640"> | <img src="https://cdn.discordapp.com/attachments/770882747580809258/1210486111298658324/Simulator_Screen_Recording_-_iPhone_15_Pro_Max_-_2024-02-23_at_16.19.19.gif?ex=65eabc0a&is=65d8470a&hm=e3fbe4047958beb7231a6b34c2ef3a952f7d9414308ac5b0d25e7efc4f709f23&" width="290" height="640"> |
| 소수점은 숫자당 1개씩만 쓸 수 있습니다. | +/- 버튼을 누르면 양수/음수를 설정할 수 있습니다. |
### 6. 트러블 슈팅
#### 1. Extension String 타입의 확장 메소드 로직 리팩토링 진행
- **[변경전]**
- target 매개변수 Operators 데이터가 할당될 것이라고 생각했었기에 아래와 같이 코드 작성하였습니다.
```Swift
extension String {
func split(with target: Character) -> [String] {
var splitString: [String] = []
var splitOperands: String = ""
for i in self {
if i == target {
splitString.append(String(i))
} else {
splitOperands.append(String(i))
}
}
splitString.append(splitOperands)
return splitString
}
}
```
- **[변경후]**
- target 매개변수가 " " 공백으로 정의를 하고 split 메소드 활용도를 이해하여 다음과 같이 변경하였습니다.
```Swift
func split(with target: Character) -> [String] {
var splitString: [String] = []
var splitOperandsAndOperators: String = ""
for i in self {
if i == target {
splitString.append(splitOperandsAndOperators)
splitOperandsAndOperators = ""
} else {
splitOperandsAndOperators.append(String(i))
}
}
splitString.append(splitOperandsAndOperators)
return splitString
}
```
#### 2. Formula 구조체 타입의 result 메소드 내부 로직 중 while 무한반복문과 if 조건문 사용을 while let 구문으로 대체하면서 불필요한 코드 삭제 및 코드 가독성 증가
- **[변경전]**
- Operands와 Operators 큐에 들어있는 내부 요소를 뽑아내는 로직을 무한루프 while문과 if 조건문을 사용하였습니다
```swift=
while operands.isEmpty == false {
if operators.isEmpty == false {
var elementOfOperators = operators.dequeue()
valueOfResult = elementOfOperators?.calculate(lhs: valueOfResult, rhs: operands.dequeue() ?? Constant.zero) ?? Constant.zero
} else {
throw CalculatorError.overTheOperands
guard let elementOfOperators = operators.dequeue() else {
throw CalculatorError.unExpectedError
}
try valueOfResult = elementOfOperators.calculate(lhs: valueOfResult, rhs: operands.dequeue() ?? Constant.zero)
}
}
```
- **[변경후]**
- 해당 로직을 while let 구문으로 변경하였습니다.
```swift=
while let elementOfOperators = operators.pop(), let elementOfOperands = operands.pop() {
if elementOfOperators == Operator.divide && elementOfOperands == 0 {
throw CalculatorError.divideByZero
}
valueOfResult = elementOfOperators.calculate(lhs: valueOfResult, rhs: elementOfOperands)
}
```
### 7. 팀 회고
#### 우리팀이 잘한 점 😍
- Danny
- 계산기 프로젝트 STEP PR 요청 및 개선하고자 하였습니다.
- Error Handling을 사용해보고자 시도하였습니다.
- UnitTest를 사용했습니다.
- Gama 🥷🏿
- 계산기 1에서 한 코드를 합치기 위해, 각자 코드를 리뷰하면서 코드를 작성한 타당한 이유 등에 대해 팀원이 충분히 이해되도록 자세히 설명했다. 의사소통과 논의를 세세하고 활발하게 하면서 리팩토링도 동시에 진행할 수 있었고, 보다 수월하게 합칠 수 있었다.
- 진행사항이 서로 다른만큼 코드를 각자 보완하면서 진행했다.
#### 우리팀 개선할 점 🥲
- Danny
- 고차함수 사용을 못한 점은 아쉬운 부분으로 느껴집니다. 고차함수로 변경이 가능한 부분은 변경해보는 연습이 필요할 것 같습니다.
- 각각의 Step PR 일정이 계속 미뤄지고 있는 부분을 개선해야 할 부분인 것 같습니다.
- STEP2에서 TDD 진행을 못 했던 부분은 아쉬운 부분입니다.
- CalculatorItemQueue 타입 내부의 리스트 관련 로직을 구성해보는 경험도 필요할 것 같습니다. (Double Stack, LinkedList)
- Gama 🥷🏿
- UI 작업이 미숙하여 요구사항을 모두 충족시키지 못했다. 다음 프로젝트 전까지 연마해야 하는 부분! 여러 상황에 대해서 대응하지 못하는 UI, ScrollView를 활용하지 못한 점 등이 아쉽다.
- 에러 케이스들이 부족하다.