###### tags: `project`
# ๐ฆ๐ฐ๊ณ์ฐ๊ธฐ _ ํ๋ฏผํธ

## Ground Rules
### ๊ท์น
- TIL, ์ผ์ผ ํ๊ณ ์์ฑ ์๊ฐ(๋งค์ผ 23์๋ถํฐ 1์๊ฐ ์์ฑ ์งํ)
- ์, ๋ชฉ 12 - 2์๋ ํ๋ํ์ต ์์ต ์๊ฐ
### ์คํฌ๋ผ
- ์ค์ 10์ ๋์ค์ฝ๋์์ ์งํ
- ๊ธ์ผ ์งํ ์ฌํญ ๊ณต์ ํ๊ธฐ(์ค๋์ ํ ์ผ)
### ํ๋ก์ ํธ ๊ท์น
- ๋ค์ด๋ฐ ์ค์ํ๊ธฐ(๊ฐ์ด๋ ๋ผ์ธ)
- ์ปค๋ฐ ๋ฉ์์ง ๊ท์น ์งํ
- ์ฝ๋์ ๋ํ ๊ธฐ๋ก ๊ทธ๋๊ทธ๋ ํ๊ธฐ
### ํ ๊ท์น
- ์ปจ๋์
์ด ์ข์ง ์์ ๋๋ ๊ผญ ๋งํด์ฃผ๊ธฐ!!
## ์ผ์ผ ์คํฌ๋ผ
### ๐ 05/29
- ์ค๋์ ์ปจ๋์
- MINT: ์์ด ์ธ๋ ์ธ๋
- hoon: ํ๋ณตํฉ๋๋ค.๐
- ํน์ด์ฌํญ
- MINT: ํ๊ณผ ํจ๊ปํด์ ๋๋ฌด๋๋ฌด ํ๋ณตํ ๋ฏผํธ๐
- hoon: 2์ฃผ๊ฐ ์ ๋ถํ๋๋ฆฝ๋๋ค.๐
- ์ค๋ ํ ์ผ: MINT
- [x] Unit Test ์์ฑํ๊ธฐ(์ผ๊ณฐ๋ท๋ท) ๊ณต๋ถ
- [x] TIL
- [ ] protocol ๊ณต๋ถ
- [ ] step 1 ์๋๋ ํด๋ณด๋ฉด์ ๋ชจ๋ฅด๋ ๊ฒ๋ค ์ ๋ฆฌ
- ์ค๋ ํ ์ผ: hoon
- [x] Unit Test ์์ฑํ๊ธฐ(์ผ๊ณฐ๋ท๋ท) ๊ณต๋ถ
- [ ] Queue์ List ๊ตฌํ
- [ ] protocol ๊ณต๋ถ
- [x] TIL
### ๐ 05/30
- ์ค๋์ ์ปจ๋์
- MINT: ์ ์ ํน ์์ ํผ๋ถ๊ฐ ๋ฐ์ง๋ฐ์ง!
- hoon: ๋ฒ์จ ํผ๊ณคํด์. ใ
ใ
ใ
ใ
ใ
- ํน์ด์ฌํญ
- MINT: ์ด์ ํ ์ผ์ ๋ค ๋ฐ๋ ธ์ด์. 12์ ์ฏค ์ ์ฌ~
- hoon: ๋ฏผํธ ์ํ ํ์ธํ๊ธฐ๐
- ์ค๋ ํ ์ผ: MINT
- [ ] TIL
- [ ] protocol, Extentions ๊ณต๋ถ
- [x] Queue์ List ๊ตฌํ
- [x] ์ฌ๋ฏธ๋ ์ปดํจํฐ ์ด์ผ๊ธฐ PART 2 - ์๋ฃ๊ตฌ์กฐ
- [x] ๊ฐ๋ฅํ๋ฉด PR ๋ณด๋ด๊ธฐ
- ์ค๋ ํ ์ผ: hoon
- [x] ์ฌ๋ฏธ๋ ์ปดํจํฐ ์ด์ผ๊ธฐ PART 2 - ์๋ฃ๊ตฌ์กฐ
- [ ] Queue์ List ๊ตฌํ
- [x] protocol ๊ณต๋ถ
- [ ] TIL
### ๐ 05/31
- ์ค๋์ ์ปจ๋์
- MINT: ์ ์ด ๊ณ์ ๊นผ์ด์. ์ค๊ฐ์ ๋ฎ์ ์ ์์ผ๊ฒ ์ด์.
- hoon: ํผ๊ณคํด์...๐ญ, ์ค๋์ ํ ์ ์๊ฒ ์ฃ ?
- ํน์ด์ฌํญ
- MINT: ์ ๋ ๊ฐ๋ฅํ๋ฉด ์ ๋
์ ์ด๋์ ๋ค๋
์ค๋ ค๊ตฌ์!
- hoon: ๊ฐ๋ฅํ๋ค๋ฉด ์ ๋
์ ์ด๋์ ๋ค๋
์ค๊ฒ ์ต๋๋ค๐คฃ
- ์ค๋ ํ ์ผ: MINT
- [x] ๋ฐ๋ฆฐ TIL
- [x] STEP 1 ์์ ํ ๋ค์ PR
- [ ] SOLID ํ๋ ํ์ต ์์ต
- [X] test Double ๊ณต๋ถ
- ์ค๋ ํ ์ผ: hoon
- [ ] ๋ฐ๋ฆฐ TIL
- [x] Queue, List ๊ตฌํ
- [x] STEP 1 PR ๋ณด๋ด๊ธฐ
- [x] SOLID ํ๋ ํ์ต ์์ต
### ๐ 06/01
- ์ค๋์ ์ปจ๋์
- MINT: ์กฐ๊ธ๋ง ๋ ์๊ณ ์ถ์ด์๐ต
- hoon: ์ด์ ์ ์ํฅ์ธ์ง ๊ฐ์ดํฉ๋๋ค ใ
ใ
ใ
ใ
- ํน์ด์ฌํญ
- MINT: ์ค๋ ๋ฐค์ ์์ธ์ ๊ฐ์๐ ๊ณผ์ฐ ์ค๋ ๊ตฌ๋๊ฐ ์ฌ๊น์?? ์ ๊ฐ ์ถ๋ฐ ์ ๊น์ง ์ค๋ฉด ์ข๊ฒ์จ์๐ฅฒ
- hoon: ๋ฏผํธ ์์ ์๊ธฐ
- ์ค๋ ํ ์ผ: MINT
- [x] ํ๋ํ์ต ์์ต
- [ ] ์คํธ๋ ์นญ
- [ ] extension ๊ณต๋ถ
- [ ] STEP 2 ๊ตฌ์ํ๊ธฐ
- [x] TIL
- ์ค๋ ํ ์ผ: hoon
- [x] ํ๋ํ์ต ์์ต
- [ ] STEP 2 ๊ตฌ์ํ๊ธฐ
- [x] Generic ๊ณต๋ถ
- [x] ๋ฐ๋ฆฐ TIL๐ญ
### ๐ 06/02
- ์ค๋์ ์ปจ๋์
- MINT: ์กธ ์์ ์ด์์๐ซ
- hoon: ์กฐ๋ ๋ฏผํธ ๊ตฌ๊ฒฝํ ์์ ใ
- ํน์ด์ฌํญ
- MINT: ํด๋ผ์ด๋ฐ ์์ ํ์ด๋ฐ์~! ์คํ๋ผ์ธ ๋ชจ๊ฐ์ฝ with hoon!!!!
- hoon: ์คํ๋ผ์ธ ๋ชจ๊ฐ์ฝ๐ with MINT๐, ๋ฏผํธ๋ ํจ๊ป ํด์ ๋๋ฌด ์ฆ๊ฑฐ์ ์ต๋๋ค.๐
- ์ค๋ ํ ์ผ: MINT
- [x] README ์์ฑ
- [ ] STEP 2 ์๊ฐํด๋ณด๊ธฐ -> ๊ณต๋ถํ ๊ฒ ์ ๋ฆฌ
- [x] UML ๊ณต๋ถ
- [x] ์คํฐ๋ ๊ณผ์
- ์ค๋ ํ ์ผ: hoon
- [x] README ์์ฑ
- [ ] STEP 1 generic constant ์ ์ฉํด๋ณด๊ธฐ
- [x] ํ ์์คํฐ๋ ์์ต
--
### ๐ 06/05
- ์ค๋์ ์ปจ๋์
- MINT: ์ ์ ๋ ฅ์ผ๋ก ๋ฉ์ฉก(?)ํฉ๋๋ค๐คฉ
- hoon: ์์ง๊น์ง ๋ฉ์ฉกํฉ๋๋ค๐คฃ
- ํน์ด์ฌํญ
- MINT: ์ ๋ ๋ฎ์ ์๋์~!
- hoon: ์ค๊ฐ์ ํผ๊ณคํ๋ฉด ์๊ณ ์ค๊ฒ ์ต๋๋ค.
- ์ค๋ ํ ์ผ: MINT
- [x] STEP 2 ๊ตฌํ 1์ฐจ ์๋ฃ ํด๋ณด๊ธฐ
- [ ] TIL
- [ ] lldb ์์ต
- [ ] ๊ณ ์ฐจํจ์ ๊ณต๋ถ
- ์ค๋ ํ ์ผ: hoon
- [x] STEP 1 ๋ง๋ฌด๋ฆฌ
- [ ] STEP 2 ๊ตฌ์ํ๊ธฐ
- [ ] TIL
- [ ] Generic WWDC ์์ ๋ณด๊ธฐ -> ํ ๋ณผ ๋ ์์งฑ์์งฑ
### ๐ 06/06
- ์ค๋์ ์ปจ๋์
- MINT: ์ง๊ธ ๊ฒจ์ธ์ธ๊ฐ์๐ฅถ
- hoon: ์์พํฉ๋๋ค๐คญ
- ํน์ด์ฌํญ
- MINT: ์ด๋ถ ์์๋ง ์์ ์์
- hoon: ๋ฐค์ ์ฐ์ฑ
?
- ์ค๋ ํ ์ผ: MINT
- [x] ๋ฐ๋ฆฐ TIL
- [x] STEP 2 PR ๋ณด๋ด๋ณด๊ธฐ
- [ ] ๊ณ ์ฐจํจ์ ๊ณต๋ถ
- ์ค๋ ํ ์ผ: hoon
- [ ] ๋ฐ๋ฆฐ TIL
- [x] STEP 2 ๊ตฌํ
### ๐ 06/07
- ์ค๋์ ์ปจ๋์
- MINT: ํํ ๋ถ์ ๋ฏผํธ
- hoon: ์ฝ๊ฐ ๋งํ์โ๏ธ
- ํน์ด์ฌํญ
- MINT: ํ ๊ธฐ์ ์ํค๊ธฐ!
- hoon: ๋ฏผํธ๊ฐ ์ค ์ด์ฝ๋ฆฟ์ ๋จน์ด๋ณด๊ฒ ์ต๋๋ค๐
- ์ค๋ ํ ์ผ: MINT
- [ ] STEP 3 ์ฝ์ด๋ณด๊ณ ์๊ฐํด๋ณด๊ธฐ~
- [ ] ํ๋ํ์ต ์์ต
- [X] STEP 2๊ฐ ๋จธ์ง๋๋ ๊ทธ๋ ๊น์ง~
- ์ค๋ ํ ์ผ: hoon
- [x] STEP 2 PR ๋ณด๋ด๊ธฐ
- [x] STEP 3 ์ฝ์ด๋ณด๊ณ ์๊ฐํด๋ณด๊ธฐ~
- [x] ํ๋ํ์ต ์์ต
- [ ] ๋ฐ๋ฆฐ TIL.....๐ต
### ๐ 06/08
- ์ค๋์ ์ปจ๋์
- MINT: ํน์์ ์ข์์~!
- hoon: ์ ๋ ๋ง์ด ์ค์ต๋๋ค.๐
- ํน์ด์ฌํญ
- MINT: ๋ฎ์ ์ ์๊ฑฐ์์ ํ๋ณตํ ๋ฎ์ ๐คธโโ๏ธ
- hoon: ๋ฏผํธ ์ํ ํ์ธํ๊ธฐ๐ง
- ์ค๋ ํ ์ผ: MINT
- [ ] STEP 3 ๊ตฌํ
- [x] ํ๋ํ์ต ์์ต
- [x] TIL
- ์ค๋ ํ ์ผ: hoon
- [ ] TIL
- [x] STEP 2 ๋ง๋ฌด๋ฆฌ
- [ ] STEP 3 ๊ตฌํ
### ๐ 06/09
- ์ค๋์ ์ปจ๋์
- MINT: ํ
์ํ
์ ๋ฒ ์คํ
3 ๋ตํน ์์๋
- hoon: ์ด์ง ํผ๊ณคํฉ๋๋ค ใ
ใ
- ํน์ด์ฌํญ
- MINT: ํ ์คํธ๋ ์นญ ์ํค๊ธฐ
- hoon: ๋ง์ง๋ง ๋ ๋ถํ์ฐ๊ณ ์ฃฝ์ ์์ ....
- ์ค๋ ํ ์ผ: MINT
- [ ] TIL
- [ ] STEP 3 PR ๋ณด๋ด๊ธฐ
- [ ] README ์์ฑ
- [ ] ํ ์์คํฐ๋ ์์ต
- ์ค๋ ํ ์ผ: hoon
- [x] STEP 3 PR ๋ณด๋ด๊ธฐ
- [ ] README ์์ฑ
- [x] ํ ์์คํฐ๋ ์์ต
- [ ] TIL
# hoon
# STEP 1
## UML Class Diagram

## ๊ณ ๋ฏผํ๋ ์
### `linked list` ์ฌ์ฉ
- `queue`๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ด๋ ํ ์๋ฃ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผํ์ต๋๋ค. ์ฒ์ ๊ธฐ๋ณธ์ ์ธ ํ์ ๊ตฌ์ฑํ ๋๋ ๊ฐ์ฅ ์ฌ์ด `array` ํ์
์ ์๊ฐํ์์ต๋๋ค. ๋ด๋ถ์ ์ผ๋ก ๊ตฌํ๋์ด ์๋ ๋ฉ์๋๋ฅผ ํตํด `queue`์ `list`๋ฅผ ๊ตฌ์ฑํ ์ ์์์ต๋๋ค. ์ด ์ธ์ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ์ฐพ์ ์๋ฃ ๊ตฌ์กฐ๊ฐ `linked list`์์ต๋๋ค. `linked list`๊ฐ `array`์ ๋ณด๋ค ์ข์ ์ ์ ์ฒ์ ์
๋ ฅ๋ฐ์ ๊ฐ์ `dequeue`ํ๋ ๊ณผ์ ์์ ๋งจ ์์ `node`์ ๋ํ ์ฐ๊ฒฐ๋ง ๋์ด์ฃผ๋ฉด ๋๋ค๋ ์ ์ด์์ต๋๋ค. `head`๋ฅผ ์ฌ์ฉํ์ฌ `linked list`์ ์ฒซ ๋
ธ๋์ ๋ํด ์๊ณ ์๋ค๊ฐ `dequeue`๊ฐ ์ผ์ด๋๋ ๊ณผ์ ์์ `head`๋ฅผ ๋ค์ `node`๋ก ์ฎ๊ธฐ๊ณ ์ด์ `node`๋ฅผ ํด์ ํด ์ค์ผ๋ก์จ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ์ ์ฅ์ ์ด ์๋ค๊ณ ์๊ฐํ์์ต๋๋ค.
```swift
mutating func append(_ data: T) {
guard head != nil
else {
head = Node(data: data)
tail = head
return
}
tail?.updateNext(Node(data: data))
tail = tail?.fetchNext()
}
```
### `Generic type` ์ฌ์ฉ
- ๊ณ์ฐ๊ธฐ๋ผ๋ ํ๋ก์ ํธ์ ๋ง์ถฐ ์ฒ์์๋ `Int` ํ์
์ ๊ฐ์ด `queue`์ ๋ค์ด๊ฐ๋ค๋ ๊ฐ์ ํ์ `Unit Test`๋ฅผ ์งํํ์์ต๋๋ค. ๋ค์ ํ
์คํธ ์ผ์ด์ค์์๋ `Int`๋ง์ด ์๋ ์ฌ์น์ฐ์ฐ(`String`) ๋ํ `queue`์ ๋ด์ ์ ์๋๋ก ์ฝ๋๋ฅผ ํ์ฅํ์์ต๋๋ค. ์ด ๊ณผ์ ์์ ํ๋์ ์ง์ ๋ ํ์
์ด ์๋ ์ผ๋ฐํํ์ฌ ๋ค์ํ ํ์
์ ๋ํด ์
๋ ฅ์ ๋ฐ๊ธฐ ์ํด `Generic` ํ์
์ ํ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์์ต๋๋ค.
## ํด๊ฒฐํ์ง ๋ชปํ ์
### `private Unit Test`
- `Unit Test`๋ฅผ ์งํํ๋ฉฐ `private` ์ ๊ทผ ์ ์ด์ ๊ด๋ จํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ต๋๋ค. ํ
์คํธ ์ผ์ด์ค์์ `private`์ผ๋ก ์ ์ธํ ํ๋กํผํฐ๋ ๋ฉ์๋์ ์ ๊ทผํ ์ ์๋ค๋ ๋ฌธ์ ์์ต๋๋ค. ์ฒ์์๋ ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ ๊ทผ ์ ์ด๋ฅผ ์ฌ์ฉํ์ง ์๊ณ `Unit Test`๋ฅผ ์งํํ์์ง๋ง ํ์ ์ฝ๋๋ฅผ ๋ฆฌํฉํ ๋งํ๋ ๊ณผ์ ์์ ๋ ์ด์ ํ
์คํธ ์ผ์ด์ค๊ฐ ์ ํจํ์ง ์๋ค๋ ๋ฌธ์ ์ ์ด ๋ฐ์ํ์์ต๋๋ค.
๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ฐพ์ ๋ฐฉ๋ฒ ์ค ํ๋๋ Test Double์ธ `Mock`๊ณผ ๊ฐ์ ํ์
์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ด์์ต๋๋ค. ์ฌ๋ฌ ์๋ฃ๋ค์ ์ฐพ์๋ณด๋ฉฐ [Testing private methods and variables in Swift](https://www.avanderlee.com/swift/testing-private-methods-variables/)๋ผ๋ ๊ธ์ ๋ณด๊ฒ ๋์์ต๋๋ค. ์ฌ๊ธฐ์ ์ค๋ช
ํ๋ ๋ด์ฉ ๋ํ `protocol`์ ์์ฑํ๊ณ ์ด๋ฅผ ์ฑํํ ๊ฐ์ฒด๋ฅผ ํ์ฉํ์ฌ ํ
์คํธ ์ผ์ด์ค์์ ์ฌ์ฉํ๋ ๊ฐ์ฒด๋ฅผ `Mock` ๊ฐ์ฒด๋ก ๋ณ๊ฒฝํ์ฌ ์คํํ ์ ์๋ค๊ณ ์ดํดํ์ต๋๋ค. ์ด ๋ด์ฉ์ ์ ์ฉํด ๋ณด๋ ๊ณผ์ ์์ `LinkedList`์ `protocol`์ ํ์ฉํ์ต๋๋ค.
```swift
// LinkedList.swift
protocol Listable {
associatedtype T
init(head: Node<T>?)
mutating func append(_ data: T)
mutating func removeFirst() -> T?
}
struct LinkedList<T>: Listable {
private var head: Node<T>?
private var tail: Node<T>?
init(head: Node<T>?) {
self.head = head
}
mutating func append(_ data: T) { ... }
mutating func removeFirst() -> T? { ... }
}
```
์์ฒ๋ผ LinkedList.swift ํ์ผ์ ์์ ํ์ต๋๋ค. ์ด๋ ๊ฒ ์์ ํ ๋ด์ฉ์ ๋ฐํ์ผ๋ก `Unit Test`์์ ์ฌ์ฉํ๋ LinkedListTests.swift์ ๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ์ ์ฉํด ๋ณด๋ ค ํ์ต๋๋ค.
```swift
final class LinkedListTests: XCTestCase {
var sut: Listable! // LinkedList<Int>!์์ protocol๋ก ๋ณ๊ฒฝ
...
}
```
๊ธฐ์กด LinkedListTests.swift๋ฅผ ์์ ํ๋ ๊ฒฝ์ฐ ์๋์ ๊ฐ์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋ฐ์ํ์์ต๋๋ค.
```swift
Use of protocol 'Listable' as a type must be written 'any Listable'
```
- [๐ Stackoverflow](https://stackoverflow.com/questions/76136642/understanding-equatable-and-any-swift-use-of-protocol-foo-as-a-type-must-be-w)
- [๐ Stackoverflow](https://stackoverflow.com/questions/75178234/use-of-protocol-yourprotocol-as-a-type-must-be-written-any-yourprotocol-erro)
์๋ฌ์ ๊ด๋ จํ์ฌ ์ฐพ์๋ณธ ๋ด์ฉ์ด์ง๋ง ์ค์ง์ ์ผ๋ก ์ ๊ฐ ์์ ํ ์ฝ๋์๋ ๋ค๋ฅธ ๋ต๋ณ์ด๋ผ๊ณ ์๊ฐํ์์ต๋๋ค. ์ฌ๊ธฐ์๋ถํฐ ์ด๋ค ๋ฐฉํฅ์ผ๋ก `private`์ ๋ํ ํ
์คํธ๋ฅผ ์์ฑํด ๋ณผ ์ ์์์ง ๊ถ๊ธํ์ฌ ์ง๋ฌธ๋๋ฆฝ๋๋ค.
### `Node` ๊ฐ์ฒด `deinit`
- `LinkedList` ๊ตฌ์กฐ์ฒด์ `removeFirst` ๋ฉ์๋์ ์ฝ๋์์ ๋ง์ง๋ง `Node`๋ฅผ ๊ฐ๋ฆฌํค๋ `tail` ํ๋กํผํฐ๋ฅผ ๋ฆฌํฉํ ๋งํ๊ธฐ ์ ์ ์ฝ๋์
๋๋ค.
```swift
// LinkedList.swift
mutating func removeFirst() -> T? {
guard head != nil else { return nil }
let data = head?.fetchData()
head = head?.fetchNext()
return data
}
```
์ ์ฝ๋์์๋ `head`๊ฐ ๋ค์ `Node`๋ก ๋์ด๊ฐ๋ฉด์ ์ด์ ์ ์ฌ์ฉํ `Node`๋ ๋ ์ด์ ์ฌ์ฉํ์ง ์์ผ๋ `deinit` ๋ ๊ฒ์ด๋ผ๋ ์์์ผ๋ก ํ
์คํธ๋ฅผ ์งํํ์์ต๋๋ค. ์ด๋ฅผ ์ํด `Node`์๋ `deinit` ๋ฉ์๋์ ์ถ๋ ฅํ๋ ๋ถ๋ถ์ ์ถ๊ฐํ์์ต๋๋ค.
```swift
// Node.swift
final class Node<T>: NodeType {
...
deinit {
print("Node deinit")
}
...
}
```
ํ
์คํธ ์ผ์ด์ค๋ฅผ ์คํํ๋ฉด์ `removeFirst` ๋ฉ์๋๋ฅผ ํธ์ถํ ํ์๋งํผ `deinit`์ ์ถ๋ ฅ์ด ๋ฐ์ํ์ฌ ์์ํ ๋ด์ฉ๊ณผ ๊ฐ์ด ๋์ํ๋ค๊ณ ์๊ฐํ์์ต๋๋ค. ํ์ง๋ง ์ดํ `tail`์ ์ฌ์ฉํ๋ฉด์ ์์ฌ์ด ๋ค๊ธฐ ์์ํ์์ต๋๋ค. `tail`์ ๋ง์ง๋ง `Node`์ ๋ํด ์ฐธ์กฐ๋ฅผ ํ๊ณ ์์ด ์์ฒ๋ผ `tail`์ `nil`๋ก ๋ณ๊ฒฝํ์ง ์๋๋ค๋ฉด ๋ง์ง๋ง `Node`์ ๋ํด ์ฐธ์กฐ๋ฅผ ๋์ด์ฃผ์ง ์์ `deinit`์ด `removeFirst`๋ฅผ ํธ์ถํ ํ์๋ณด๋ค ํ๋ฒ ์ ๊ฒ ์ถ๋ ฅํด์ผ ํ๋ค๊ณ ์๊ฐํ์ต๋๋ค. ํ์ง๋ง ์คํ ๊ฒฐ๊ณผ๋ ์ ๊ฐ ์๊ฐํ๋ ๊ฒ๊ณผ ๋ฌ๋ฆฌ `removeFirst`์ ๊ฐ์ ํ์๋ก ํธ์ถ๋์์ต๋๋ค. ์ด๋ค ๋ถ๋ถ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํด์ ์์๊ณผ๋ ๋ค๋ฅธ ๋์์ด ์ผ์ด๋ฌ๋์ง ํด๊ฒฐํ์ง ๋ชปํ์ต๋๋ค.
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ์
### `Unit Test`์ ํ
์คํธ๊ฐ ๋์ด๋ ๋๋ง๋ค ์ด์ ํ
์คํธ์ ๋ณ๊ฒฝ
- TDD๋ฅผ ์งํํ๋ฉด์ ์ ๋ง ๋ค์ํ ๊ฒฝ์ฐ๋ก ์ด์ ์์ฑํ ํ
์คํธ ์ผ์ด์ค์ ๋ณ๊ฒฝ์ด ์๊ตฌ๋๋ ์ ์ด ๋ง์์ต๋๋ค. ๋ง์ํด ์ฃผ์ ๋ด์ฉ์ฒ๋ผ UML์ ์์ฑํ๊ณ ํ
์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ๋ ๋ฐฉํฅ์ ํตํด ์ด๋ฐ ๋ฌธ์ ๊ฐ ๋ง์ด ์ค์์ง๋ง ์ฌ์ ํ ์ฌ๋ฐ๋ฅธ TDD์ ํ์ฉ์ ๋ํด์๋ ์๋ฌธ์ด ๋จ์ต๋๋ค. ํนํ ์์ง ํด๊ฒฐํ์ง ๋ชปํ `Mock`๊ณผ ๊ฐ์ ๊ฒฝ์ฐ "์ ์ฒด ์ฝ๋๊ฐ ์์ฑ๋์ด์ผ ์ฌ์ฉํด ๋ณผ ์ ์๋ ๋ฐฉ๋ฒ์ด์ง ์์๊น?"๋ผ๋ ์๊ฐ์ด ๋ญ๋๋ค. ๋งค๋ฒ ๋ชจ๋ ๊ฒฝ์ฐ์ ์ ์ฉํ ์๋ ์๊ฒ ์ง๋ง ์ด๋ฐ TDD ๋ฐฉ์์ ๊ฐ๋ฐ๋ก ์ ๋ํด ์ด๋จ ๋ ์ฌ์ฉํ ์ ์์์ง ์กฐ์ธ์ ์ป๊ณ ์ถ์ต๋๋ค.
### ํ์ ์ฃผ๋ ์ค๊ณ ๋ฐฉ์
- ๊ฐ์ฒด์งํฅ์ ๊ด์ ์์ ๊ฐ์ฒด๋ฅผ ์ค๊ณํ ๋ ํ์ ์ฃผ๋ ์ค๊ณ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์ ์๋ค๋ ๋ด์ฉ์ ๊ณต๋ถํ์์ต๋๋ค. ์ด๋ฒ STEP 1์ ์งํํ๋ฉฐ `Node` ํด๋์ค์์ ์ฌ์ฉํ๋ `data`์ `next` ํ๋กํผํฐ์ ๋ํด `private` ์ ๊ทผ ์ ์ด๋ฅผ ์ฌ์ฉํ์์ต๋๋ค.
```swift
final class Node<T>: NodeType {
private let data: T
private var next: Node<T>?
init(data: T, next: Node? = nil) {
self.data = data
self.next = next
}
deinit {
print("Node deinit")
}
func fetchData() -> T {
return data
}
func fetchNext() -> Node<T>? {
return next
}
func updateNext(_ next: Node<T>) {
self.next = next
}
}
```
์์ฒ๋ผ `private`์ผ๋ก ์ ์ธํ ํ๋กํผํฐ๋ฅผ ์ธ๋ถ์์ ์ ๊ทผํ๊ธฐ ์ํด ๋ช ๊ฐ์ง ๋ฉ์๋๋ฅผ ํตํด ์บก์ํ๋ฅผ ํด์ฃผ์์ต๋๋ค.
ํ์ ์ฃผ๋ ์ค๊ณ์ ๊ด์ ์์๋ ์ด๋ ๊ฒ ์ฌ์ฉํด์ผ ํ๋ค๊ณ ์๊ฐํ์ฌ ์์ ๊ฐ์ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์์ง๋ง ๋๋๋ก ๊ด์ฉ์ ์ผ๋ก ์ฌ์ฉํ๋ ํ๋กํผํฐ์ ๋ํด์๋ ์ธ๋ถ์ ์ง์ ๋
ธ์ถํ์ฌ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ค์ด ์์์ต๋๋ค. ์ด๋ฒ์ ์ฌ์ฉํ๋ `Node`์ ๊ฐ์ ๊ฒฝ์ฐ์๋ ๋๋ค์์ ๋ง์ ์ฝ๋ ์์์์ ์ง์ ์ ๊ทผํ์ฌ ํ๋กํผํฐ๋ฅผ ์ฝ๊ณ ์ฐ๋ ๋ฐฉ์๋ค์ด ๋ง์์ต๋๋ค. ์ด๋ฐ ๋ถ๋ถ์์ ์ด๋ป๊ฒ ์ ๊ทผ ์ ์ด๋ฅผ ํ์ฉํ๊ณ ์บก์ํ๋ฅผ ํ ์ ์์์ง ๊ถ๊ธํฉ๋๋ค.
# STEP 2
## ๊ณ ๋ฏผ๋์๋ ์
### ์์์ ๋นผ๊ธฐ ์ฐ์ฐ์ ๊ตฌ๋ถํ๊ธฐ
- ์์์ด "1+2/-3--6"๊ณผ ๊ฐ์ด ์
๋ ฅ์ผ๋ก ์ฃผ์ด์ง๋ฉด 3๊ณผ 6์ ๊ฐ๊ฐ ์์์ธ -3๊ณผ -6์ ๋ํ๋
๋๋ค. "-" ๋ถํธ์ ๋ํด ํผ์ฐ์ฐ์(`operand`)์ ์ฐ์ฐ์(`operator`)๋ฅผ ๊ตฌ๋ถํด ์ฃผ์ด์ผ ํ์ต๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ฑํ์์ต๋๋ค.
```swift
enum ExpressionParser {
static func parse(from input: String) -> Formula {
...
let operands = componentsByOperators(from: input).compactMap { Double($0) }
let operators = input
.replacingOccurrences(of: "+-", with: "+")
.replacingOccurrences(of: "--", with: "-")
.replacingOccurrences(of: "/-", with: "/")
.replacingOccurrences(of: "*-", with: "*")
.compactMap { Operator(rawValue: $0) }
...
}
static private func componentsByOperators(from input: String) -> [String] {
var operands: [String] = Operator.allCases.reduce([input]) { splitInput, operatorCase in
splitInput.map { $0.split(with: operatorCase.rawValue) }.flatMap { $0 }
}
for index in 0..<operands.count - 1 {
if operands[index].isEmpty {
operands[index + 1] = "-\(operands[index + 1])"
}
}
return operands
}
}
```
๋จผ์ ์์ ์์ ๊ฐ ์ ์์ ์ผ๋ก ๋์ํ๊ธฐ ์ํด์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฐ์ ์ด ํ์ํฉ๋๋ค.
1. ์ฌ๋ฐ๋ฅธ ์์๋ง์ด ์
๋ ฅ๋ฉ๋๋ค.
2. ๋ถํธ๋ ์์(-)๋ง ์ฌ์ฉํฉ๋๋ค.
๋ ๊ฐ์ ์ ํตํด ์์์์ ์ฐ์์ ์ผ๋ก ๋ํ๋๋ ์ฐ์ฐ์๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฝ์ฐ๋ง ์๋ค๊ณ ์ ์ํ์์ต๋๋ค.
1. "+\-" : ๋ง์
์ฐ์ฐ์์ ๋ค์์ ์ฌ ํผ์ฐ์ฐ์์ ์์ ๋ถํธ
2. "-\-" : ๋บ์
์ฐ์ฐ์์ ๋ค์์ ์ฌ ํผ์ฐ์ฐ์์ ์์ ๋ถํธ
3. "/\-" : ๋๋์
์ฐ์ฐ์์ ๋ค์์ ์ฌ ํผ์ฐ์ฐ์์ ์์ ๋ถํธ
4. "\*-" : ๊ณฑ์
์ฐ์ฐ์์ ๋ค์์ ์ฌ ํผ์ฐ์ฐ์์ ์์ ๋ถํธ
์ด๋ ๊ฒ ๊ฐ์ ์ ํ๊ณ ๋์ ๋ค์ ์ฐ์ฐ์๋ง์ ๋ชจ์ ๋๋ ๋ค์ ์์ ๋ถํธ๋ฅผ ๋ฌด์ํ์ฌ ์ฐ์ฐ์๋ฅผ ์ ํํ ๋ ๊ฑฐ๋ฅด๋๋ก ํ์์ต๋๋ค. ๋ํ, ํผ์ฐ์ฐ์๋ ์์์ ์ฐ์ฐ์๋ฅผ ๊ธฐ์ค์ผ๋ก ๋๋๋ฉด ๋ ๊ฐ์ ์ฐ์ฐ์๊ฐ ์ฐ์์ผ๋ก ์ค๋ ๊ฒฝ์ฐ์ ๋น ๋ฌธ์์ด("")์ด ๋ฐ์ํฉ๋๋ค. ์ด์ ๊ฐ์ ์ ํตํด ์ฐ์์ผ๋ก ์ฐ์ฐ์๊ฐ ๋ํ๋๋ ๊ฒฝ์ฐ๋ ๋ค์ ์์ ๋ถํธ๋ง์ด ์กด์ฌํ๋ค๊ณ ํ๊ธฐ ๋๋ฌธ์ ๋น ๋ฌธ์์ด์ ๋ค์ ๋ฌธ์์ด์ ์์ ๋ถํธ๋ฅผ ์ถ๊ฐํจ์ผ๋ก์จ ์ง์ ์ ์ผ๋ก ์์์ธ ํผ์ฐ์ฐ์๋ฅผ ๋ง๋ค์์ต๋๋ค.
### ์์์ ์ฒ์์ด ์์์ผ ๋
- ์ ๊ฐ์ ์ ๋ฐํ์ผ๋ก ์์์ด ์์๋ก ์์ํ๋ ๊ฒฝ์ฐ ์์ ๋ถํธ ์์ ๋ค๋ฅธ ์ฐ์ฐ์๊ฐ ์กด์ฌํ์ง ์๊ธฐ ๋๋ฌธ์ ํผ์ฐ์ฐ์์ ์์ ๋ถํธ ๋์ ์ฐ์ฐ์๋ก ํ๋ณํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ต๋๋ค. ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์์์์ ์ฐ์ฐ์๋ง์ ๋ชจ์ผ๋ ๋ก์ง์ ์คํํ๊ธฐ ์ ์ ์
๋ ฅ๋ฐ์ ์์์ ์์ ํ์์ต๋๋ค.
```swift
let operatorCandidates: String = input.hasPrefix("-") ? String(input.suffix(input.count - 1)) : input
```
์์์ ์ฒ์์ด "-"์ธ์ง๋ฅผ ํ์ธํ์ฌ "-"๊ฐ ์๋ค๋ฉด ์
๋ ฅ๋ฐ์ ์์์ ๋ณํ ์์ด ์ฌ์ฉํ๊ณ "-"๊ฐ ์๋ค๋ฉด "-" ๋ถํธ๋ฅผ ์ ์ธํ ๋จ์ ์์๋ง์ ์ฌ์ฉํ์ฌ ์ฐ์ฐ์๋ฅผ ์ฐพ๋ ๋ก์ง์ ์ํํฉ๋๋ค.
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ๋ถ๋ถ
### UML dependancy ๊ด๊ณ
- `ExpressionParser`๋ `Formula`์๋ง ์์กด ๊ด๊ณ๋ก UML์ ๋ํ๋์์ต๋๋ค.
```swift
enum ExpressionParser {
static func parse(from input: String) -> Formula {
var formula: Formula = Formula(operands: CalculatorItemQueue<Double>(),
operators: CalculatorItemQueue<Operator>())
...
}
}
```
์ฝ๋๋ก ์์ฑํ๋ฉด ์์ ๊ฐ์ด `Formula`๋ฅผ ์ด๊ธฐํํ ๋ ์ ๋ฌ์ธ์ ํ์
์ผ๋ก `CalculatorItemQueue`๋ฅผ ์ฌ์ฉํ๊ฒ ๋ฉ๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ์๋ UML ์์์ `ExpressionParsar`๊ฐ `CalculatorItemQueue`์ ์์กดํ๋ค๊ณ ๋ด์ผ ํ ๊น์?
### `ExpressionParsar` Unit Test
- `enum` ํ์
์ธ `ExpressionParsar`๋ฅผ Unit Test ํ๊ธฐ ์ํด ํ
์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ ๋ `static`์ผ๋ก ์ ์ธํ ํ์
ํ๋กํผํฐ๊ฐ ๋ฌธ์ ์์ต๋๋ค. ํ์
ํ๋กํผํฐ์ด๊ธฐ ๋๋ฌธ์ ์๋ก์ด ์ธ์คํด์ค๋ฅผ ์์ฑํ์ง ์๋๋ค๋ ์ ์์ ๋ฉ์๋ ๋ด๋ถ์ ์ง์ญ๋ณ์๋ก ์ฌ์ฉํด๋ ๊ด์ฐฎ์๊น์?
# STEP 3
## ๊ณ ๋ฏผ๋์๋ ์
### ๊ณ์ฐ๊ธฐ ๋์์ ์์ธ ์ฒ๋ฆฌ
- ๊ณ์ฐ๊ธฐ๊ฐ ๋์ํ ๋ ์๊ฐํด์ผ ํ๋ ๋ง์ ์์ธ๋ค์ด ์์์ต๋๋ค. 0์ ์
๋ ฅํ์์ ๋๋ 0๋ ์ฐ์ฐ์ ํฌํจํด์ผ ํ๋ฉฐ ๋ค๋ฅธ ์กฐ๊ฑด๋ค์ ๊ธฐ์ตํ๊ธฐ ์ํด `isResult`๊ณผ `isInputZero` flag๋ฅผ ์ฌ์ฉํ์ฌ ์กฐ๊ฑด์ ์ฒ๋ฆฌํ๋๋ก ํ์์ต๋๋ค. ํนํ ๊ณ์ฐ๊ธฐ ์๊ตฌ ์ฌํญ์ ์ค๋ช
๋์ง ์์๋ ์์ธ์ ๊ฒฝ์ฐ์๋ ์ค์ ๊ณ์ฐ๊ธฐ ์ฑ์ ๊ธฐ์ค์ผ๋ก ์์ธ ์ฒ๋ฆฌ๋ฅผ ์งํํ๋ ค๊ณ ํ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ์์์ ๋ค์ ์ซ์๊ฐ ์๋ ๊ฒฝ์ฐ์๋ ์์์ ์ ๋ฒ๋ฆฐ ์ค์๋ถ๋ง์ ๊ฐ์ง๊ณ ์ฐ์ฐ์ ํ๋๋ก ํ์์ต๋๋ค.
## ํด๊ฒฐ์ด ๋์ง ์์ ์
### NumberFormatter
- `NumberFormatter`๋ฅผ ์ฌ์ฉํ์ฌ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ก ๋ฐ์์จ `Double` ํ์
์ ๊ฐ์ `String` ํ์
์ผ๋ก ๋ณํํ์ฌ `UILabel`์ ํํํ์์ต๋๋ค. ์ด๋ ์ซ์๋ ์ต๋ 20์๋ฆฌ๊น์ง ํํํ๋ค๋ ์กฐ๊ฑด์ด ์์์ต๋๋ค. `NumberFormatter`์ ์๋ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํ์ฌ ์ต๋ 20์๋ฆฌ์ ํํ์ ํ์ฉํด ์ฃผ์์ต๋๋ค.
```swift
let numberFormat = NumberFormatter()
numberFormat.usesSignificantDigits = true
numberFormat.maximumSignificantDigits = 20
```
์์ ์ฝ๋์์ `usesSignificantDigits`๋ฅผ ํ์ฑํํด์ผ `maximumSignificantDigits`๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ดํ ์ต๋ ํํ ๊ฐ๋ฅํ ์ซ์๋ฅผ 20์ผ๋ก ์ค์ ํ์์ต๋๋ค. ํ์ง๋ง ์ฌ๊ธฐ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ต๋๋ค. `Double` ํ์
์ ์ต๋ ํํ ์๋ฆฟ์๊ฐ ๋ฌธ์ ์์ต๋๋ค. `Double`์ 64bit๋ก ์์์ ์ดํ ์ต๋ 16์๋ฆฌ๊น์ง๋ง ์ ์ฅ์ด ๊ฐ๋ฅํ์์ต๋๋ค. ์ด์ฒ๋ผ ์ต๋ 20์๋ฆฌ๊น์ง ํํ์ ํ์ง ๋ชปํ๋ ํ์
์ ์ฌ์ฉํ์์ ๋ ์์ ๊ฐ์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์์ต๋๋ค. `Double` ํ์
์ ๋์ฒดํ๋ ๋ค๋ฅธ ํ์
์ ์ฌ์ฉํ์ฌ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ผ ํ์๊น์?
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ๋ถ๋ถ
### ์กฐ๊ฑด๋ฌธ ์ฌ์ฉ
- ์ฌ๋ฌ ์์ธ ์ฒ๋ฆฌ๋ฅผ ํ๋ ค๊ณ ํ๋ค ๋ณด๋ ์ ๋ฆฌ๊ฐ ๋์ง ์์ ์ํฉ์์ ํ๋์ฉ ์์ธ ์ฒ๋ฆฌ์ ๋ง๊ฒ ์กฐ๊ฑด๋ฌธ์ ์ถ๊ฐํ์์ต๋๋ค. ์ด๋ ๊ฒ ์ฝ๋๋ฅผ ์์ฑํ๋ค ๋ณด๋ ์ค๋ณต์ด ๋๋ ์กฐ๊ฑด๋ ์์๊ณ ๊ณ์ํด์ ์กฐ๊ฑด๋ฌธ์ด ์ฐจ์งํ๋ ๋ถ๋ถ๋ค์ด ๋์ด๋ง ๊ฐ์ต๋๋ค. ์กฐ๊ฑด๋ฌธ์ด ๋ง์์ง๋ ์ฝ๋์์ ์ด๋ ํ ์์น์ ํ์ํ ์กฐ๊ฑด์ด ๋ฌด์์ธ์ง ๋๋ ์ด๋์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์๋์ง๋ฅผ ํ์ธํ๊ธฐ๊ฐ ์ด๋ ค์ ์ต๋๋ค. ์ด์ฒ๋ผ ์ฌ๋ฌ ์์ธ ์ผ์ด์ค๊ฐ ๋ฐ์ํ๋ ๋ถ๋ถ์ ๋ํด ์ฒ์๋ถํฐ ๋ชจ๋ ์ฃ์ง ์ผ์ด์ค๋ฅผ ๊ฐ์ ํ๊ณ ์ฝ๋ฉ์ ํ ์๋ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ์ด๋ ํ ๋ฐฉ์์ผ๋ก ์ ๊ทผ์ ํด์ผ ์ฝ๋๋ฅผ ์์ฑํ ๋ ์กฐ๊ธ ๋ ์ ํจํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์์์๊น์?
# MINT
# STEP 1
## ๊ณ ๋ฏผํ๋ ์
### Queue์ ๊ฐ๋
์ ์
์ ์ถ! ์ ๊ฐ๋
์ ์ฒ์์ ๋จ์ ์ญ์ ๋ก ์๋ชป ์ดํดํ์ต๋๋ค. ๋๋ฌธ์ `dequeue`๋ฅผ ํ๋ฉด ๋งจ ์ฒ์์ ์๋ `element`๊ฐ ์ญ์ ๋๋ ๊ฒ๋ง์ ์๊ฐํด์ ์ ๋๋ก ๋ ๊ฒฐ๊ณผ๋ฌผ์ด ๋์ค์ง ์๋ ์ผ์ด ์์์ต๋๋ค. `T?`๋ฅผ ๋ฐํ๊ฐ์ผ๋ก ์ฃผ์ด ์ ์ด์ `enqueue`๋ ๊ฒ์ด ์๊ฑฐ๋ ์ด๋ฏธ ์์๋ค์ด ์ ๋ถ `dequeue`๋์ด ๋๊ฐ ๊ฒฝ์ฐ `nil`์ ๋ฐํํ ์ ์๊ฒ ๋ณ๊ฒฝํ์์ต๋๋ค. ์ดํ `Queue`์ ๊ฐ๋
์ ๋ํด ๋ ์์๋ณด๋ค๊ฐ ๋ณดํต `count`๋ผ๋ ๊ฐ์๋ฅผ ์ธ์ด์ฃผ๋ ๊ธฐ๋ฅ์ด ์๊ธธ๋ ์ฐ์ฐ ํ๋กํผํฐ๋ฅผ ์ฌ์ฉํด์ ์ถ๊ฐํ์์ต๋๋ค. `subscript`๋ฅผ ์ฌ์ฉํด๋ณด๊ณ ์ถ์๋๋ฐ ๊ทธ๋ ๊ฒ ํ๋ฉด `CalculatorItemQueue.count` ๋ก ์ฌ์ฉํ ์ ์๊ณ `CalculatorItemQueue[1]`๋ก ์ฌ์ฉํด์ผ ํ๊ธฐ์ ๋ณ๊ฒฝํ์์ต๋๋ค.
### generic type์ ์ฌ์ฉ
๊ณ์ฐ๊ธฐ ํ๋ก์ ํธ์์ ์ด `queue`๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์
๋ ฅ๋ฐ๋ ์ซ์๋ค๊ณผ ์ฌ์น์ฐ์ฐ ๊ธฐํธ๋ฅผ ๋ฃ๊ณ ์์๋๋ก ๋ง์ถฐ์ ์ ์
์ ์ถํ๋ฉฐ ๊ณ์ฐํด์ฃผ๋ ๊ฒ์ ์ฌ์ฉํ ๊ฒ์ด๋ผ๊ณ ์๊ฐํ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ๊ณ์ฐ๊ธฐ์์๋ ๋จ์ํ `Int` ํ์
๋ฟ๋ง ์๋๋ผ 10.1๊ณผ ๊ฐ์ `Double` ํ์
๋ ์ฌ์ฉํ๊ณ , ์ฌ์น์ฐ์ฐ ๊ธฐํธ ๊ฐ์ ๊ฒฝ์ฐ๋ `String` ํ์
์ ์ฌ์ฉํ ๊ฒ์ด๊ธฐ์ `Queue`์ ๊ตฌํ์์ ์ฌ๋ฌ๊ฐ์ง ํ์
๋ค ์ค ์ ํํ ์ ์๋, ๋ฒ์ฉ์ ์ธ ํ์
์ด ํ์ํ๋ค๊ณ ์๊ฐํ์ต๋๋ค. ๋๋ฌธ์ `Generic type`์ ์ฌ์ฉํ์ฌ `Queue`๋ฅผ ๊ตฌํํ์์ต๋๋ค.
## ํด๊ฒฐํ์ง ๋ชปํ ์
### list ๊ตฌํ์ ์๋ฏธ
ํ๋ก์ ํธ ์คํ
์๋ด์ ๋์์๋ `list ์๋ฃ๊ตฌ์กฐ ๊ตฌํ`์ ์๋ฏธ๋ฅผ ์ ํํ๊ฒ ์ดํดํ์ง ๋ชปํ๊ณ ์์ต๋๋ค. ๊ธฐ์กด ์ค์ํํธ์ `array`์์ ์ ๊ณตํ๋ `removeFirst()` ์์ ์๊ฐ๋ณต์ก๋๋ฅผ ๋ ๋ฎ์ถ ๊ฒฝ์ฐ๋ค์ ๊ตฌํํด๋ณด๋ ๊ฒ์ ๋งํ๋ ๊ฑธ๊น์? ex) `linked-list`, `stack`
### test์ private ์ฌ์ฉ
`private`์ ๊ฑธ์ด์ฃผ๋ฉด `test`์์๋ ๊ทธ ํจ์๋ฅผ ์ฌ์ฉํ ์๊ฐ ์์์ต๋๋ค. ๊ณ ๋ฏผํ๋ค ๊ฒฐ๊ตญ `test`๋ฅผ ์ ๋ถ ๋ค ํ ๋๊น์ง๋ `private` ํค์๋ ์์ด ์งํํ์๊ณ ๋ง์ง๋ง์ `private`์ด ํ์ํ๋ค๊ณ ์๊ฐ๋๋ ๊ฒ๋ค์๋ง ๋ถ์ฌ์ฃผ์์ต๋๋ค. `count`, `enqueue`, `dequeue`๋ ์ด `CalculatorItemQueue`๋ฅผ ์ธ์คํด์คํด์ ์ฌ์ฉํ ๋ ๋ถ๋ฌ์ผ ํ๋ ๊ธฐ๋ฅ๋ค์ด๋ผ๊ณ ์๊ฐํด `private` ํค์๋๋ฅผ ๋ฌ์ง ์์์ต๋๋ค.
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ์
### TDD์ ํ์ฉ
ํ๋ํ์ต์์ ๋ดค๋ ๋ฐฉ๋ฒ์ ๋ฐ๋ผํ๋๋ฐ ์ ๋๋ก ๋ ๋ฐฉ๋ฒ์ด์๋์ง๋ ์ ๋ชจ๋ฅด๊ฒ ์ต๋๋ค.๐ต
1. ๋จผ์ ์ ์ธ๋ง ํ ํ ํ
์คํธ ํจ์๋ฅผ ์์ฑํฉ๋๋ค.
-> ์ด๋ฅผ ๋๋ฆฌ๋ฉด `fail`์ด ๋น๋๋ค. ์คํจํ ์ผ์ด์ค.
2. ๊ตฌํํ๊ณ ์ ํ๋ ํจ์ ๋ด๋ถ๋ฅผ ์์ฑํฉ๋๋ค.
-> `refactor`
3. ๋ค์ ํ
์คํธ๋ฅผ ๋๋ฆฝ๋๋ค.
-> ์ฑ๊ณต ์ ๋ค์ ํจ์๋ก, ์คํจ ์ ๋ค์ ๋ฆฌํํ ๋ง
### Queue ๊ตฌํ ๋ฐฉ๋ฒ๋ค ์ค ์ ํ์ฌํญ: Double stack
queue๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๋ค์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์์ต๋๋ค.
1. ๊ธฐ๋ณธ์ ์ธ array
_ `removeFirst()``
2. linked list
_ ๋ณธ์ธ ์ด์ ์ ์ ๋ณด์ ๋ค์์ ์ ๋ณด๋ฅผ ์๊ณ ์๋ `linked list`๋ก ๋งจ ์ฒ์์ `linked list`๋ฅผ ํด์ ํ๋ฉด ๋ฉ๋๋ค.
3. Double Stack
_ `stack` 2๊ฐ๋ฅผ ์ฌ์ฉํด ๊ตฌํํฉ๋๋ค. ๋ ๊ฐ์ ์คํ์ฉ ๋ฐฐ์ด์ ๋ง๋ค์ด์ 1๋ฒ ์คํ์ `enqueue`์ ๊ฐ๋ค์ ์์๋๋ก ์ถ๊ฐํฉ๋๋ค. 1๋ฒ ์คํ์ ์์๋ค์ ๋ค์์๋ถํฐ ๋นผ๋ฉด์ 2๋ฒ ์คํ์ ๋ฃ์ต๋๋ค. 2๋ฒ ์คํ์ 1๋ฒ ์คํ์ ๊ฑฐ๊พธ๋ก ๋ค์ง์ ๊ฒ ๊ฐ์ ๋ชจ์์ ํ๊ฒ ๋ฉ๋๋ค. 2๋ฒ ์คํ์ ์ ์ผ ์์ ์๋ ์์๋ฅผ ๋นผ๋
๋๋ค. ๋ค์ 2๋ฒ ์คํ์ ๋ค์์๋ถํฐ ๋นผ๋ฉด์ 1๋ฒ ์คํ์ ๋ฃ์ผ๋ฉด 1๋ฒ ์คํ์ ๊ธฐ์กด์์ ์ฒซ๋ฒ์งธ ์์๋ฅผ ์ ์ธํ๊ณ ๋๋จธ์ง ์์๋ค์ด ์๋น๊ฒจ์ง ๋ชจ์์ด ๋ฉ๋๋ค.
=> ์ ๋ ์ด ์ค์์ `Double Stack`์ ์ฌ์ฉํ์ต๋๋ค. 1๋ฒ ๋ฐฉ๋ฒ์ ๊ฐํธํ์ง๋ง ๋งจ ์ฒ์ ์์๋ฅผ ์ญ์ ํ ํ ๊ทธ ๋ค์ ๊ฒ๋ค์ ํ๋์ฉ ๋์ด์์ผํด์ ์๊ฐ๋ณต์ก๋์ ๊ดํ ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฒ ๋ฉ๋๋ค. `linked list`๋ `Double Stack`์ ๋ ๋ค ์๊ฐ ๋ณต์ก๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ฃผ์ง๋ง ์ ๊ฐ ๋จผ์ ์๊ฐ์ด ๋ ๊ฒ์ `Double Stack`์ด์๊ธฐ์ ์ด๊ฒ์ผ๋ก ๊ตฌํํ์์ต๋๋ค. ์ด๋ ๊ฒ ์๊ฐ๋ณต์ก๋๊ฐ ๊ฐ์ ๋๋ ๋ ๊ฐ์ง ์ค์์ ์ด๋ค ๊ธฐ์ค์ผ๋ก ์ ํํ๋ ๊ฒ์ด ์ข์๊น์?
### reversed ๊ธฐ๋ฅ์ ๊ฐ์ง ํจ์
`Double Stack`์ ๊ตฌํํ๊ธฐ ์ํด `reversed()`๋ฅผ ๋๋ฒ ํด์ฃผ์ด์ผ ํฉ๋๋ค. ์ด `reversed()` ๊ธฐ๋ฅ์ `dequeue`์์ ๋ฐ๋ก ํด์ค๋ ๋์ง๋ง, `test`๋ฅผ ํ ๋ ๊ฑฐ๊พธ๋ก ์ ๋ฐ๋๋์ง๋ ํ์ธํด๋ณด๊ณ ์ถ์ด์ ๋ฐ๋ก ๋นผ์ฃผ์์ต๋๋ค. ์ด๋ ๊ฒ ๋นผ๋ ๊ฒ์ด ์คํ๋ ค ๊ตฌํ ์ ๋ณต์กํ๊ฒ ๋ง๋๋ ๊ฑธ๊น์? -> reversed()๋ฅผ ๋ฐฐ์ด๋ก ์ ์ธํ๋ ์๊ฐ ์๊ฐ๋ณต์ก๋๊ฐ O(n)์ด๋ผ๊ณ ํฉ๋๋ค.
# STEP 2
## ๊ณ ๋ฏผํ๋ ์
### ๊ณ ์ฐจํจ์์ ์ฌ์ฉ_ compactMap
ํ๋ก์ ํธ์ ์ค๋ช
์ค ๊ณ ์ฐจํจ์๋ฅผ ์ต๋ํ ์ฌ์ฉํด๋ณด๋ผ๋ ์๋ด์ ๋ฐ๋ผ `parse`ํจ์ ๋ด์์ for ๋ฌธ ๋์ `forEach`๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ๊ทธ๋ฌ๊ธฐ ์ํด์ ์ต์
๋ ๋ฐ์ธ๋ฉ์ด ํ์ํ ๋ถ๋ถ์ ๊ณ ๋ฏผํ๊ฒ ๋์๋๋ฐ ์ ์ ์ต์
๋ ์คํฐ๋์์ ํ๋ ๊ฒ์ด ์๊ฐ๋ `compactMap`์ผ๋ก ๋ฐ์ธ๋ฉ ํด ์ฃผ์์ต๋๋ค. ๊ฒฐ๋ก ์ ์ผ๋ก ๋ณ์ ์ ์ธํ๋ ๋ถ๋ถ์ ์ค์ผ ์ ์์์ต๋๋ค.
### UML์ ํด์_ split, componentsByOperators
์ฒ์ ์ฃผ์ด์ง UML์ ์จ์ ํ๊ฒ ์ดํดํ๋ ๊ฒ์ ์ค๋ ์๊ฐ์ด ๊ฑธ๋ ธ์ต๋๋ค. ํนํ split๊ณผ componentsByOperators ํจ์๋ฅผ ์ดํดํ๊ธฐ๊ฐ ์ฝ์ง ์์๋๋ฐ split์ด ์๋๋ฐ ๊ตณ์ด componentsByOperators๊ฐ ์์ด์ผ ํ๋๋ ์๊ฐ์ ํ์ต๋๋ค. ์จ์ ํ ์ ๋ง์ ์๊ฐ์ ์๋์ง๋ง componentsByOperators๋ฅผ ๊ตฌํํจ์ ์์ด split์ ๊ธฐ์ค์ " " ๊ณต๋ฐฑ์ผ๋ก ๋์์ต๋๋ค. ์ด ๋๋ฌธ์ ์์ ๊ฐ์ ์๊ฐ์ด ๋ ์ปค์ก๋๋ฐ, ์ฝ๋๋ฅผ ์ฝ์๋ ์กฐ๊ธ ๋ ์ฝ๊ฒ ์ฝ๊ธฐ ์ํจ์ผ๋ก ์ดํดํ๊ณ ๋์ด๊ฐ์ต๋๋ค.
## ํด๊ฒฐํ์ง ๋ชปํ ์
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ์
### enum Test
unit Test๋ฅผ ํ๋ ๊ฒ์ ์์ด์ enum ํ์
์ธ ExpressionParser๋ Operator๋ฅผ ๋ฐ๋ก test ํ ์๊ฐ ์๋๋ฐ ์ด ๊ฒฝ์ฐ๋ ๋ค๋ฅธ FormulaTests์์ ๊ฐ์ด ํด๋ ๋๋์ง ๊ถ๊ธํฉ๋๋ค. sut๋ก ๋ถ๋ฅด์ง ์์๋ ์ฌ์ฉํ ์ ์๊ธฐ์ formula์ given ํ์์ผ๋ก๋ง ์ผ๋จ test๋ฅผ ์์ฑํด ๋์์ต๋๋ค.
### unit Test
์ด์ ์คํ
์์๋ TDD๋ก ์งํํ์๊ธฐ์ unit Test๋ฅผ ์ต๋ํ ์์ธํ๊ฒ ์์ฑํ์์ต๋๋ค. ์ด๋ฒ ์คํ
์ ๊ฒฝ์ฐ๋ TDD๋ก ์งํํ ๊ฒ์ด ์๋๋ผ ๋จ์ํ unit Test์ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ณ ์ถ์๋ ๊ฑด๋ฐ ๋ฐ์ ์ด ๊ฒฝ์ฐ์๋ ์ต๋ํ ์์ธํ๊ฒ ์์ฑํ์๋์ง ๊ถ๊ธํฉ๋๋ค. test๋ฅผ ์ด๋ ์ ๋๊น์ง ์งํํด์ผ ํ๋ ๊ฒ์ธ์ง ์์ง ๊ฐ์ด ์ ์ ์ค๋ ๊ฒ ๊ฐ์์. ์ ๋ ์ด๋ฒ ์คํ
์์๋ ๊ตฌํ์ ํ ํ unit Test๋ก ์๊ฐ์ ๊ฒ์ฆ๋ง ํ๊ณ ์๊ธฐ์ ์ด๋์ ๋ ๊ฐ๋ตํ๊ฒ ์์ฑํ์์ต๋๋ค.
# STEP 3
## ๊ณ ๋ฏผ๋์๋ ์
### scroll view, stack view
scroll View ์์ ์๋ Stack View์ ๋งค๋ฒ ๊ณ์ฐ๊ธฐ์ ์์์ ์ถ๊ฐํ ๋๋ง๋ค sub Stack View๋ฅผ ์๊ฒ ๋๋๋ฐ ๊ธฐ์กด scroll view์ stack view๋ ๊ทธ๋๋ก ์คํ ๋ฆฌ๋ณด๋์ ์๋ ๊ฒ์ ๋์ด์ ํ์ฉ๋งํ๋ฉด ๋ ๊ฒ ๊ฐ์ ๋์์ต๋๋ค. subStackView๋ง ๋งค๋ฒ ์์์ ์ถ๊ฐํ ๋๋ง๋ค ๋ง๋ค์ด ๋ฃ์ด์ ์ฌ๋ฆฌ๋ ๋ฐฉ์์ผ๋ก ๊ตฌํํ์ฌ subStackView๋ง ์ฝ๋๋ก ์์ฑํ์์ต๋๋ค.
### autolayout
scrollView์ StackView ์์ subStackView๋ค์ ์ง์ ํ์ํ ๋ ์ฝ๋๋ฅผ ํตํด ๊ตฌํํ์ฌ ์ถ๊ฐํด์ฃผ์๊ธฐ์ ์คํ ๋ฆฌ๋ณด๋์์๋ ์ง์์ฃผ์์ต๋๋ค. ๊ทธ๋ฌ๋๋ scrollView์ height๊ฐ ์๋ค๋ autolayout error๊ฐ ๋ด์ต๋๋ค. top์ผ๋ก ๋ถํฐ์ ๊ฑฐ๋ฆฌ๋ฅผ 20๋ณด๋ค ๊ฐ๊ฑฐ๋ ํฌ๋ค๋ก๋ง ์ค์ ํด์ฃผ์ด์ ๊ธฐ๋ณธ์ ์ธ ๊ฐ์ด ์๊ธฐ์ ๋ํ๋๋ ๋ฌธ์ ์์ต๋๋ค. scrollView์ ๊ธฐ๋ณธ์ ์ธ height๋ฅผ ์ฃผ๊ณ , ๊ทธ๋ ๊ฒ ๋๋ฉด subStackView๊ฐ ๋ค์ด๊ฐ ๋ scrollView์ ๊ฐ์ด๋ฐ ๋ถํฐ ํ์๋๋ ๊ฒ์ด ๋ฌธ์ ์๊ธฐ์ alignment๋ฅผ .bottom์ผ๋ก ์ฃผ์ด ํด๊ฒฐํ์ต๋๋ค.
### isInputZero, isResultValue flag ์ฌ์ฉ
์
๋ ฅ๋ฐ์ 0์ธ์ง, ๊ธฐ๋ณธ์ ์ผ๋ก ํ์๋์ด ์๋ 0์ธ์ง์ ๋ฐ๋ผ ์์์ ๋ค์ด๊ฐ๊ณ ๋ค์ด๊ฐ์ง ์๊ณ ์ ๋ํ ์ฌ๋ถ๊ฐ ๋ฌ๋์ต๋๋ค. ์ด๋ฅผ ์ํด isInputZero๋ผ๋ bool type ํ๋ผ๋ฏธํฐ๋ฅผ ๋ง๋ค์ด ๊ตฌ๋ณํ์์ต๋๋ค. ์ด์ ๋น์ทํ๊ฒ = ๋ฅผ ๋๋ฌ ๊ฒฐ๊ณผ๊ฐ์ด ๋์จ ๊ฒฝ์ฐ ๊ทธ ๊ฒฐ๊ณผ๊ฐ์ ์๋ก์ด ํผ์ฐ์ฐ์๋ฅผ ๋ง๋ถ์ผ ์ ์๊ณ +- ๋ถํธ ์ ํ์ ํ ์ ์๊ธฐ์ ์ด ์ญ์ Bool type ํ๋ผ๋ฏธํฐ๋ก ๊ตฌ๋ณํ์์ต๋๋ค.
### settingFormula(isEndByPoint: Bool = false, isResultComma: Bool = false) ๋ถ๊ธฐ์ฒ๋ฆฌ
์
๋ ฅ๋๋ ๋ถ๋ถ์์ .์ผ๋ก ๋๋๊ฑฐ๋ ๊ธด ๊ฒฐ๊ณผ๊ฐ์ด๋ผ ,๋ก ๊ตฌ๋ถ๋ ๊ฒฝ์ฐ ๊ทธ๋๋ก [String]์ ์์ด๋ฉด ๊ทธ ํ parse ํจ์์์ ์๋ฌ๊ฐ ๋๋ ์ผ์ด ์์์ต๋๋ค. ๋๋ฌธ์ ์ด๋ฌํ ๊ฒฝ์ฐ๋ค์ ๋ฐ๋ก ๋นผ์ ๊ฐ๊ฐ filter๋ฅผ ์ฌ์ฉํด .๊ณผ ,๋ฅผ ์ญ์ ํด ์ฃผ์์ต๋๋ค.
-
## ํด๊ฒฐ์ด ๋์ง ์์ ์
### numberFormatter
๋ถ๋์์์ ์ค๋ฅ๋ก ์ธํด ์๋ํ ๊ฐ์ด ์ ๋๋ก ๊ณ์ฐ๋์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์์์ต๋๋ค. Double์ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ธ ๊ฒ ๊ฐ์๋ฐ numberFormatter๋ก Decimal๋ก ๋ฐ๊พธ์์ง๋ง ์ฌ์ ํ ์จ์ ํ ๋ชปํ ๊ฐ๋ค์ ๊ณ์ฐ์ด ๋์์ต๋๋ค. ๋ํ 20์๋ฆฌ์๋ก ์ค์ ํ๋ ๊ฒ์ ์์ด์๋ maximumSignificantDigits๋ก ์ ํจ์ซ์๊ฐ 20์๋ฆฌ์ผ ์ ์๊ฒ ์ค์ ํ์์ง๋ง 20์๋ฆฌ๊น์ง ๊ฐ์๋๋ ํญ์ ๊ฐ๋ค์ด ๋ณํ๋ ์ผ์ด ์์ต๋๋ค.. ๐ฅ
### layoutIfNeeded
scrollView์์ ์๋ก์ด ๋ผ๋ฒจ์ด ๋ค์ด์ค๋ฉด ํญ์ ์ตํ๋จ์ผ๋ก ์๋ ์คํฌ๋กค์ ํ ์ ์๊ฒ ๋ก์ง์ ์ง๋ ๊ณผ์ ์์ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. ํญ์ ํ๋ ์์ ๊ฐ์ด ๋ณด์ฌ์ ์ฐพ๋ค๊ฐ layoutIfNeeded()๋ผ๋ ๊ฒ์ ์๊ฒ ๋์์ต๋๋ค. ์
๋ฐ์ดํธ ์ฃผ๊ธฐ๋ฅผ ๋น๊ฒจ์ฃผ์ด ์จ์ ํ๊ฒ ํฌ๊ธฐ๋ฅผ ์ฒ๋ฆฌํ ์ ์๊ฒ ํด์ฃผ๋ ๊ฒ์ผ๋ก ์ดํดํ๋๋ฐ ๊ทธ๋ ๋ค๋ฉด ์ด๊ฒ์ ์ฌ์ฉํ์ง ์์ ๊ฒฝ์ฐ์๋ subStackView๊ฐ CGpoint๋ฅผ ์ก์ผ๋ผ๊ณ ๋์ด ์๋ ํ์์ผ ์ฌ๋ผ๊ฐ๊ฒ ๋๋์ง ๊ถ๊ธํฉ๋๋ค... ๐ฅ
-
## ์กฐ์ธ์ ์ป๊ณ ์ถ์ ๋ถ๋ถ
### ์๋ง์ ์กฐ๊ฑด๋ฌธ๋ค
์์ธ์ ์ธ ์ฌํญ๋ค์ ์ฒ๋ฆฌํ๋ค ๋ณด๋ ํ ๋ฒํผ ์ก์
๋ค์ ๊ต์ฅํ ๋ง์ ์กฐ๊ฑด๋ฌธ์ ๋ด๊ฒ ๋์์ต๋๋ค. ์ด๋ ๊ฒ ๊ต์ฅํ ๋ง์ ์กฐ๊ฑด๋ฌธ์ ๋๊ฒ ๋ ๊ฒ์ ๊ตฌ์กฐ์ ์ธ ๋ฌธ์ ๋ก ์ธํด ์๊ฒจ๋ ๊ฒ์ผ๊น์? ์ก์
์ด ์์ ๋ ์ฒ๋ฆฌํด์ผํ๋ ์ผ๋ค์ด ๋ง๋ค๋ณด๋ ์ผ์ด๋ ์ผ ๊ฐ์๋ฐ ์ง๊ธ ์ ์ฝ๋์ ๊ฒฝ์ฐ์๋ ๋ฒํผ ์ก์
๋ค์ด ํ๋์ ์ญํ ์ ํ๋ ํจ์๋ผ๊ณ ๋ณผ ์ ์๋์ง ์์ํฉ๋๋ค. ํจ์ ์์ ๋ด์ฉ๋ค์ ์กฐ๊ธ ๋ ๋ถ๋ฆฌํ์ฌ ์ฒ๋ฆฌํด์ผํ ๊น์? ๐ฅ
-
---
# ๋ฆฌ๋๋ฏธ ์์ฑ: hoon
# ๐ฆ๊ณ์ฐ๊ธฐ
## ๐ ๋ชฉ์ฐจ
1. [์๊ฐ](#-์๊ฐ)
2. [ํ์](#-ํ์)
3. [ํ์๋ผ์ธ](#-ํ์๋ผ์ธ)
4. [์๊ฐํ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ](#-์๊ฐํ๋-ํ๋ก์ ํธ-๊ตฌ์กฐ)
5. [์คํ ํ๋ฉด](#-์คํ-ํ๋ฉด)
6. [ํธ๋ฌ๋ธ ์ํ
](#-ํธ๋ฌ๋ธ-์ํ
)
7. [์ฐธ๊ณ ๋งํฌ](#-์ฐธ๊ณ -๋งํฌ)
8. [ํ ํ๊ณ ](#-ํ-ํ๊ณ )
</br>
## ๐ ์๊ฐ
์ฌ์ฉ์์ ์
๋ ฅ์ ๋ฐ์ ๊ธฐ๋ณธ ์ฐ์ฐ์ ์ํํ๋ ๊ณ์ฐ๊ธฐ์
๋๋ค.
* ์ฃผ์ ๊ฐ๋
: `Protocols`, `Extensions`, `Generic`, `Type Casting`, `Unit Test`, `Queue`, `Scroll View`
</br>
## ๐จโ๐ป ํ์
| hoon |
| :--------: |
| <Img src = "https://hackmd.io/_uploads/HylLMDsN2.jpg" width="200" height="200"> |
|[Github Profile](https://github.com/Hoon94) |
</br>
## โฐ ํ์๋ผ์ธ
|๋ ์ง|๋ด์ฉ|
|:--:|--|
|2023.05.29.| - Unit Test ์คํ|
|2023.05.30.| - Node, Linked List ํ์
์์ฑ ๋ฐ Unit Test ์งํ |
|2023.05.31.| - CalculatorItemQueue ํ์
์์ฑ ๋ฐ Unit Test ์งํ </br> - UML ์์ฑ |
|2023.06.01.| - Generic ํ์
์์ |
|2023.06.02.| - README ์์ฑ|
|2023.06.03.| - |
|2023.06.04.| - |
|2023.06.05.| - |
|2023.06.06.| - |
|2023.06.07.| - |
|2023.06.08.| - |
</br>
## ๐ ์๊ฐํ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ
### Diagram
<p align="center">
<img width="800" src= "https://hackmd.io/_uploads/BJR4n6lw2.png" >
</p>
</br>
## ๐ป ์คํ ํ๋ฉด - ์ถํ ์์ฑ ์์
| ํ๋ฉด |
|:--------:|
|<img src="" width="800">|
| ํ๋ฉด | ํ๋ฉด | ํ๋ฉด |
|:--------:|:--------:|:--------:|
|<img src="" width="250">|<img src="" width="250">|<img src="" width="250">|
</br>
## ๐งจ ํธ๋ฌ๋ธ ์ํ
1๏ธโฃ `Linked List` ์ฌ์ฉ <br>
-
๐ **๋ฌธ์ ์ ** <br>
- `CalculatorItemQueue`๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ด๋ ํ ์๋ฃ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ ์ง ๊ณ ๋ฏผํ์ต๋๋ค. ์ฒ์ ๊ธฐ๋ณธ์ ์ธ ํ์ ๊ตฌ์ฑํ ๋๋ ๊ฐ์ฅ ์ฌ์ด `Array` ํ์
์ ์๊ฐํ์์ต๋๋ค. ๋ด๋ถ์ ์ผ๋ก ๊ตฌํ๋์ด ์๋ `Array`์ ๋ฉ์๋๋ฅผ ํตํด `CalculatorItemQueue`์ `list`๋ฅผ ๊ตฌ์ฑํ ์ ์์์ต๋๋ค. ํ์ง๋ง `CalculatorItemQueue`์์ `dequeue`๋ฅผ ์คํํ ๋ `Array` ์๋ฃ๊ตฌ์กฐ์ ๋ฌธ์ ์ ์ด ๋๋ฌ๋ฌ์ต๋๋ค. `Array`์์ ๋ง์ง๋ง์ด ์๋ ์์๋ฅผ ์ ๊ฑฐํ ๋ ๋จ์ ์์๋ค์ ์์ผ๋ก ์ฎ๊ธฐ๋ฉฐ ๋น ๋ฉ๋ชจ๋ฆฌ ๊ณต๊ฐ์ ์ฑ์๋๋ค. ์ด๋ฐ ๋์์ ์ํํ๊ธฐ๋๋ฌธ์ `dequeue` ๋ฉ์๋๋ฅผ ์คํํ ๋ ์๊ฐ ๋ณต์ก๋๋ O(n)์ด๋ผ๊ณ ํฉ๋๋ค.
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
- `Linked List`๋ฅผ ์ฌ์ฉํ์ฌ `dequeue`์ ๋ฌธ์ ์ ์ ํด๊ฒฐํ ์ ์์์ต๋๋ค. ์ฒ์ ์
๋ ฅ๋ฐ์ `node`๋ฅผ `dequeue`ํ๋ ๊ณผ์ ์์ ๋งจ ์์ `node`์ ๋ํ ์ฐ๊ฒฐ์ ๋์ด์ฃผ์์ต๋๋ค. `head`๋ฅผ ์ฌ์ฉํ์ฌ `Linked List`์ ์ฒซ ๋
ธ๋์ ๋ํด ์๊ณ ์๋ค๊ฐ `dequeue`๊ฐ ์ผ์ด๋๋ ๊ณผ์ ์์ `head`๋ฅผ ๋ค์ `node`๋ก ์ฎ๊ธฐ๊ณ ์ด์ `node`๋ฅผ ํด์ ํ์ต๋๋ค. `head`๋ ํญ์ ์ฒซ `node`๋ฅผ ์ฐธ์กฐํ๊ณ ์๊ธฐ ๋๋ฌธ์ ์๊ฐ ๋ณต์ก๋๊ฐ O(1)์ธ ๋งํผ ๋ ๋น ๋ฅธ ๋์์ด ๊ฐ๋ฅํ์ต๋๋ค.
```swift
mutating func append(_ data: T) {
guard head != nil
else {
head = Node(data: data)
tail = head
return
}
tail?.updateNext(Node(data: data))
tail = tail?.fetchNext()
}
```
<br>
2๏ธโฃ **ํ์ฅ์ฑ** <br>
-
๐ **๋ฌธ์ ์ ** <br>
-
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
-
<br>
## ๐ ์ฐธ๊ณ ๋งํฌ
- [๐Apple Docs: Generics](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/generics)
- [๐Apple Docs: Protocols](https://docs.swift.org/swift-book/documentation/the-swift-programming-language/protocols)
- [๐Apple Docs: ]()
- [๐Apple Docs: ]()
- [๐blog: Generic](https://babbab2.tistory.com/136)
</br>
## ๐ฅ ํ๊ณ
- [ํ๊ณ ๋งํฌ]()
# ๋ฆฌ๋๋ฏธ ์์ฑ: MINT
# ๐ฆ๊ณ์ฐ๊ธฐ
## ๐ ๋ชฉ์ฐจ
1. [๐ ์๊ฐ](#-์๊ฐ)
2. [๐จโ๐ป ํ์](#-ํ์)
3. [โฐ ํ์๋ผ์ธ](#-ํ์๋ผ์ธ)
4. [๐ ์๊ฐํ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ](#-์๊ฐํ๋-ํ๋ก์ ํธ-๊ตฌ์กฐ)
5. [๐ป ์คํ ํ๋ฉด](#-์คํ-ํ๋ฉด)
6. [๐งจ ํธ๋ฌ๋ธ ์ํ
](#-ํธ๋ฌ๋ธ-์ํ
)
7. [๐ ์ฐธ๊ณ ๋งํฌ](#-์ฐธ๊ณ -๋งํฌ)
8. [๐ฅ ํ๊ณ ](#-ํ๊ณ )
</br>
## ๐ ์๊ฐ
๋ฏผํธ๊ฐ ๋ง๋ ๊ณ์ฐ๊ธฐ. <br>
์ฌ์ฉ์๋ ์ซ์ํจ๋์ ๊ธฐํธ๋ฅผ ๋๋ฌ ์ ์์ ์ค์์ ์ฌ์น์ฐ์ฐ์ ํ ์ ์์ต๋๋ค.
</br>
## ๐จโ๐ป ํ์
| MINT |
| :--------: |
| <Img src = "https://hackmd.io/_uploads/SyW7zfDUn.jpg" width="200" height="200"> |
|[Github Profile](https://github.com/mint3382) |
</br>
## โฐ ํ์๋ผ์ธ
|๋ ์ง|๋ด์ฉ|
|:--:|--|
|2023.05.29.| - `Unit Test` ๊ณต๋ถ |
|2023.05.30.| - `enqueue`, `dequeue`, `popLastStack` ํจ์ ๊ตฌํ <br> - TDD ์ฌ์ฉ |
|2023.05.31.| - `count`, `isEmpty`, `first`, `last` ์ฐ์ฐ ํ๋กํผํฐ ๊ตฌํ <br> - `enqueue`, `dequeue` ํจ์ ๋ฆฌํํ ๋ง <br> - `popLastStack` ํจ์ ์ญ์ <br> - `test` ๋ฆฌํํ ๋ง |
|2023.06.01.| - `enqueue`, `dequeue` ํจ์ ๋ฆฌํํ ๋ง <br> - `test` ๋ฆฌํํ ๋ง <br> - `first`, `last` ์ฐ์ฐ ํ๋กํผํฐ ๋ฆฌํํ ๋ง |
|2023.06.02.| - `static`, `UML`๊ณต๋ถ |
|2023.06.04.| - `UML` ์ดํด ํ ์ ๋ฆฌ <br> - ์๋์ฝ๋ ์์ฑ |
|2023.06.05.| - `ExpressionParser`, `Operator`, `Formula` ๊ตฌํ |
|2023.06.06.| - `Formulatests`, `ExpressionParserTests`, `CalculatorErrors` ๊ตฌํ |
|2023.06.07.| - ์ปจ๋ฒค์
๋ฐ ๋ค์ด๋ฐ ์์ |
|2023.06.08.| - `NumberFormatter` ๊ณต๋ถ, ๊ตฌํ <br> - `Scroll View` ๊ณต๋ถ, ๊ตฌํ |
|2023.06.09.| - `IBAction` ๊ตฌํ <br> - ์๋ ์คํฌ๋กค ๊ธฐ๋ฅ ๊ตฌํ |
|2023.06.10.| - ์์ธ์ฌํญ ์์ <br> - `NumberFormatter` ํ๋ผ๋ฏธํฐ ํ์
์์ |
|2023.06.11.| - ์์ธ์ฌํญ ์์ <br> - ๋ค์ด๋ฐ ๋ฐ ์ปจ๋ฒค์
์์ <br> - `Operator` ๊ณ์ฐ ํ์
์์ |
</br>
## ๐ ์๊ฐํ๋ ํ๋ก์ ํธ ๊ตฌ์กฐ
### File Tree
````
Calculator
โโโ Extension
โ โโโ String+
โ โโโ Double+
โโโ Model
โ โโโ CalculatorItemQueue
โ โโโ CalculateItem
โ โโโ Formula
โ โโโ Operator
โ โโโ ExpressionParser
โโโ View
โ โโโ LaunchScreen
โ โโโ Main
โโโ Controller
โ โโโ AppDelegate
โ โโโ SceneDelegate
โ โโโ CalculateViewController
โโโ Resource
โ โโโ Assets
โ โโโ Info
โโโ CalculatorTests
โโโ TestPlan
โโโ ExpressionParserTests
โโโ FormulaTests
โโโ CalculatorItemQueueTests
````
### Class Diagram
<img width="800" src= "https://hackmd.io/_uploads/rJApOw7v2.jpg" >
</p>
</br>
## ๐ป ์คํ ํ๋ฉด
| AC ๋ฒํผ | CE ๋ฒํผ | +/- ๋ฒํผ |
|:--------:|:--------:|:--------:|
|<img src="https://hackmd.io/_uploads/ByiQ3SmPh.gif" width="250">|<img src="https://hackmd.io/_uploads/Hy6UnBmPn.gif" width="250">|<img src="https://hackmd.io/_uploads/BJyO3Hmwh.gif" width="250">|
| ์ ์ ์ฐ์ฐ | ์์ ์ฐ์ฐ | ์ค์ ์ฐ์ฐ |
|:--------:|:--------:|:--------:|
|<img src="https://hackmd.io/_uploads/ryu8ArmD2.gif" width="250">|<img src="https://hackmd.io/_uploads/HJFH0HmP2.gif" width="250">|<img src="https://hackmd.io/_uploads/SkPV0HXPn.gif" width="250">|
| รท 0 | 10 รท 3 | 5 รท 3 |
|:--------:|:--------:|:--------:|
|<img src="https://hackmd.io/_uploads/Hy090Smv3.gif" width="250">|<img src="https://hackmd.io/_uploads/rJkh0BXvn.gif" width="250">|<img src="https://hackmd.io/_uploads/B1i3CHXDn.gif" width="250">|
| 0๋ฒํผ ์์ธ์ฒ๋ฆฌ | 20์๋ฆฟ์ ์์ธ์ฒ๋ฆฌ | ๊ฒฐ๊ณผ๊ฐ ์์ธ์ฒ๋ฆฌ |
|:--------:|:--------:|:--------:|
|<img src="https://hackmd.io/_uploads/B1RXkUXwh.gif" width="250">|<img src="https://hackmd.io/_uploads/SJJr1L7w2.gif" width="250">|<img src="https://hackmd.io/_uploads/ByJ8yLQwn.gif" width="250">|
| ์ฐ์ฐ์ด ๊ธธ์ด์ง ๊ฒฝ์ฐ ์๋ ์คํฌ๋กค | ํผ์ฐ์ฐ์ ๋ผ๋ฒจ ์ซ์๊ฐ ์ปค์ง ๊ฒฝ์ฐ decimal ์์ | dot์ผ๋ก ๋๋ ๊ฒฝ์ฐ ์์ ํํ |
|:--------:|:--------:|:--------:|
|<img src="https://hackmd.io/_uploads/SkbbxLXP3.gif" width="250">|<img src="https://hackmd.io/_uploads/SJxll87wn.gif" width="250">|<img src="https://hackmd.io/_uploads/Syb1g8QP2.gif" width="250">|
</br>
## ๐งจ ํธ๋ฌ๋ธ ์ํ
1๏ธโฃ **Queue ๊ตฌํ ์๋ฃ๊ตฌ์กฐ ์ ํ: Double Stack vs Linked_List** <br>
-
๐ **๋ฌธ์ ์ ** <br>
`Queue`๋ฅผ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๋ค์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ต๋๋ค.
๋ณธ์ธ ์ด์ ์ ์ ๋ณด์ ๋ค์์ ์ ๋ณด๋ฅผ ์๊ณ ์๋ `linked list`๋ผ๋ ๊ตฌ์กฐ์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค. `enqueue`์ ๋ง์ง๋ง `node`์ธ `TAIL`์ ์๋ก ์ถ๊ฐ๋ `node`๋ฅผ ์๊ณ , `dequeue`์ ๋งจ ์ฒ์์ `node`์ธ `HEAD`์ ์ ๋ณด๋ฅผ ๋ฐํํ๋ฉด์ `HEAD`์ ์์น๋ฅผ ๋ค์ `node`๋ก ์ ํํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํฉ๋๋ค.
`stack` 2๊ฐ๋ฅผ ์ฌ์ฉํด ๊ตฌํํ๋ `Double Stack`์ด๋ผ๋ ๊ตฌ์กฐ์ ๋ฐฉ๋ฒ ๋ํ ์์ต๋๋ค. ๋ ๊ฐ์ ์คํ์ฉ ๋ฐฐ์ด์ ๋ง๋ค์ด์ `enqueueStack`์์๋ ์์์ ์ถ๊ฐ(`enqueue`์ ๊ธฐ๋ฅ)๋ง, `dequeueStack`์์๋ ์ ์
์ ์ถ์ ๋ง์ถฐ ์์ ๋ฐํ(`dequeue`์ ๊ธฐ๋ฅ)๋ง์ ๋ด๋นํ๊ฒ ํ์ฌ ์ฌ์ฉํฉ๋๋ค.
์ด ์ค ๊ณ์ฐ๊ธฐ์ ๊ธฐ๋ฅ์ ์ํด `Queue`๋ฅผ ๊ตฌํํ ๋, ์ด๋ค ๋ฐฉ๋ฒ์ ์ ํํ ์ง์ ๋ํ ๊ณ ๋ฏผ์ด ์์์ต๋๋ค.
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
๊ณ์ฐ๊ธฐ์ ๊ธฐ๋ฅ์ ์ํจ์๋ `Double Stack`์ด ๋ ๋ง๋ ๊ฒ ๊ฐ์ `Double Stack`์ผ๋ก ๊ตฌํํ์์ต๋๋ค.
`linked list`๋ `node`๋ผ๋ ๊ณณ์ ๋จ์ํ ๋ณธ์ธ์ `data` ๋ฟ๋ง ์๋๋ผ ๋ค์ ์ฐจ๋ก์ `node`์ ์ฃผ์๊ฐ์ ์๊ณ ์๋ ๊ตฌ์กฐ์
๋๋ค. ๋์์์ด ์ฐ๊ฒฐ๋์ด ์๋ ๊ตฌ์กฐ์ด๊ณ `HEAD`์ `TAIL`์ ์ค์ ํด์ฃผ๋ฉด ์์ฝ๊ฒ ์ฒ์๊ณผ ๋์ ์ ์ ์๊ณ , ๋ด์ฉ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๋๋ฌธ์ `array`์์ ๊ตฌํ๋๋ `removeFirst()`์๋ ๋ค๋ฅด๊ฒ `HEAD`๋ง ์ฎ๊ฒจ์ 1๋ฒ ์๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํค๋ ๊ฒ์ด ๋ฐ๋ ๋ฟ ๋ฐฐ์ด์ ๋ด์ฉ์ ์์ผ๋ก ๋น๊ธธ ํ์๊ฐ ์๊ธฐ์ ์๊ฐ๋ณต์ก๋๊ฐ O(n)์ด ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ด์ ๋น ๋ฆ
๋๋ค. ๋ํ ์ค๊ฐ์ ๋ฐ์ดํฐA๋ฅผ ๋ฃ๊ณ ์ถ์ ๋ ๋ฃ๊ณ ์ถ์ ๋ถ๋ถ์ ์์ ๋
ธ๋์ ๋ค์ ๋
ธ๋์ ๋ํ ์ ๋ณด๋ฅผ A์ ๋ํ ๋
ธ๋๋ก ๋ฐ๊พธ๊ณ , A ๋
ธ๋์์ ๋ค์ ๋
ธ๋์ ๋ํ ์ ๋ณด๋ฅผ ๊ธฐ์กด์ ๋ฃ๊ณ ์ถ์๋ ๋ถ๋ถ์ ๋ค์ ๋
ธ๋๋ก ๋ณ๊ฒฝํด์ฃผ๋ฉด ๋ฉ๋๋ค. ์ด์ฒ๋ผ ๋ฐ์ดํฐ๋ฅผ ์ค๊ฐ์ ์ฝ์
ํ๋ ๊ฒ์ ํฐ ์ฅ์ ์ด ์์ต๋๋ค.
`Double stack`์ `dequeueStack`์ด ๋น์ด์๋ ๊ฒฝ์ฐ `enqueueStack`์ ๋ค์ง์ด์ฃผ์ด์ผ ํ๋ ์ผ์ด ์์ด์ ์๊ฐ ๋ณต์ก๋๋ ์กฐ๊ธ ๋ ๋์ ์ ์์ง๋ง ๋ฐฐ์ด์ ์ด์ฉํ ๊ตฌํ์ด๊ธฐ์ ์ํ๋ค๋ฉด ์ธ๋ฑ์ค๋ฅผ ํตํ ์ ๊ทผ์ ๋น ๋ฅด๊ฒ ํ ์ ์์ต๋๋ค.
๊ณ์ฐ๊ธฐ์ ๊ฒฝ์ฐ ํ์ ๊ตฌํ์ด๊ธฐ์ ์ค๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ถ๊ฐํด ์ค ํ์๊ฐ ์์ต๋๋ค. `linked-list`๋ฅผ ์ฌ์ฉํ๋ค๋ฉด `enqueue`๋ฅผ ํ ๋๋ง๋ค ๋งค๋ฒ `node`๋ฅผ ์์ฑํ๊ณ ํ ๋นํ์ฌ `TAIL`๊ณผ ์ฐ๊ฒฐ์ง๋ ์์
์ ํด์ฃผ์ด์ผ ํ๋๋ฐ `double stack`์ ๋จ์ํ `enqueueStack`์ `append`๋ง ํด์ฃผ๋ฉด ๋๊ณ , `dequeue`๋ฅผ ํ ๋๋ `linked-list`๋ ๊ธฐ์กด HEAD์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ์ฌ ๋ฐํํ ํ `HEAD`๊ฐ ๊ฐ๋ฆฌํค๊ณ ์๋ `node`๋ฅผ ๋ค์ `node`๋ก ๋ณ๊ฒฝํ๋ ์์
์ ํด์ฃผ์ด์ผ ํ๋๋ฐ `double stack`์์๋ ์ด๋ฏธ `dequeueStack`์ ์๋ค๋ฉด ๋จ์ํ ๋ฐฐ์ด์ ๋ง์ง๋ง ์์๋ฅผ ๊บผ๋ด๊ธฐ๋ง ํ๋ ๊ฒ์ด๊ธฐ์ ํด์ผํ๋ ์์
์ด ๋ ์ ๊ณ ๊ตฌ์กฐ๊ฐ ๊ฐ๋จํ๋ค๋ ์๊ฐ์ด ๋ค์ด `double stack`์ผ๋ก ๊ตฌํํ ๊ฒ์ ๋จ๊ฒผ์ต๋๋ค.
<br>
2๏ธโฃ **Double Stack: enqueue์ dequeue์ ์๊ฐ ๋ณต์ก๋** <br>
-
๐ **๋ฌธ์ ์ ** <br>
์ด๋ฐ `dequeue`๋ฅผ ํ ๋ ํญ์ `enqueueStack`์ `dequeueStack`์ `reversed()` ํด์ค ํ `popLast()`๋ฅผ ํ๊ณ ๋ค์ `enqueueStack`์ `reversed()` ํด์ฃผ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ต๋๋ค. ๊ทธ๋ฌ์ ๋งค๋ฒ ์๊ฐ๋ณต์ก๋๊ฐ O(n)์ผ๋ก `array`์ `removeFirst()`๋ฅผ ์ฌ์ฉํด์ฃผ๋ ๊ฒ๊ณผ ๋ค๋ฅผ ๋ฐ ์๋ ๊ฒฐ๊ณผ๊ฐ ๋์์ต๋๋ค.
```swift
dequeueStack = reversedStack(enqueueStack)
let output = backwardStack.popLast()
enqueueStack = reversedStack(dequeueStack)
```
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
ํ๋ฒ `enqueueStack`์ `reversed()`ํ์ฌ `dequeueStack`์ ๋ฃ๊ฒ ๋๋ฉด ๊ธฐ์กด์ `enqueueStack`์ ๋ด์ฉ์ ์ง์ฐ๊ณ `dequeueStack`์๋ง ๋จ๊ฒจ, `dequeueStack`์ด ๋น์ด์ ๊บผ๋ผ ์์๊ฐ ์์ ๋๊น์ง `reversed()`ํ ํ์ ์์ด ๋ง์ง๋ง ์์๋ฅผ ๊บผ๋ด๋ ์์
๋ง ํ ์ ์๋๋ก ๋ณ๊ฒฝํ์์ต๋๋ค. ๋งค๋ฒ `reversed()` ํด์ฃผ๋ ๊ฒ์ด ์๋๋ผ ํ์ํ ์๊ฐ์๋ง, ํ๋ฒ์ฉ ํด์ฃผ๊ธฐ์ ์๊ฐ ๋ณต์ก๋๋ฅผ ์ค์ผ ์ ์์์ต๋๋ค.
```swift
mutating func dequeue() -> T? {
guard isEmpty == false else {
return nil
}
if dequeueStack.isEmpty {
dequeueStack = enqueueStack.reversed()
enqueueStack.removeAll()
}
return dequeueStack.removeLast()
}
```
<br>
3๏ธโฃ **TDD_private** <br>
-
๐ **๋ฌธ์ ์ ** <br>
`private` ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด `Unit Test`์์๋ ํด๋น ํ๋กํผํฐ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋๋ฌธ์ ํ
์คํธ๋ฅผ ํ ๋๋ `private`๋ฅผ ์ ๊ฑฐํ๊ณ , ํ
์คํธ๊ฐ ๋๋ ํ์ ๋ค์ `private`์ ๋ถ์ฌ์ฃผ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ต์ข
์ ์ธ `test๋ฌธ`๋ค์ ๋นจ๊ฐ ์๋ฌ๊ฐ ๋จ๋ ์ผ๋ค์ด ๋ฐ์ํ์๋๋ฐ ํนํ `enqueue` ๋ฉ์๋๊ฐ ์ ๋๋ก ๋์ํ์๋์ง๋ฅผ ์์๋ณด๊ธฐ ์ํด `private enqueueStack`์ ๋ด์ฉ์ ๋น๊ตํ๋ ๊ณผ์ ์์ ๋ฌธ์ ๋ค์ด ์๊ฒผ์ต๋๋ค.
```swift
XCTAssertEqual(sut.enqueueStack, [10, 20])
```
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
ํ
์คํธ๋ ์๋ํ๋ฅผ ํ์์์๋ ์ค๋ฅ ์์ด ์ ๋์๊ฐ์ผํฉ๋๋ค. ๋๋ฌธ์ `private` ํค์๋๋ฅผ ๋ถ์ด๋๋ผ๋ ํด๋น ํ๋กํผํฐ๋ ๋ฉ์๋๋ฅผ ํ์ธํ ์ ์๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ ์๊ฐํด์ผ ํ์ต๋๋ค. `count` ํ๋กํผํฐ๋ฅผ ํ์ฉํ์ฌ `enqueue` ๋ฉ์๋๊ฐ ๋์ํ์์ ๋ `count`์ ๊ฐ์ด ์ฌ๋ผ๊ฐ๋์ง ํ์ธํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ณ๊ฒฝํ์ฌ ํด๊ฒฐํ์์ต๋๋ค.
```swift
//when
let result = sut.count
//then
XCTAssertEqual(result, 2)
```
<br>
4๏ธโฃ **Scroll View ๊ตฌํ** <br>
-
๐ **๋ฌธ์ ์ ** <br>
`ScrollView`๋ ์คํฌ๋กค๋ทฐ ์์ `StackView`๊ฐ ์๊ณ ๊ทธ ์คํ๋ทฐ ์์ `SubStackView`๊ฐ ์๋ ํ์์
๋๋ค. ๊ณ์ฐ๊ธฐ์ ์์์ด ์๋ธ ์คํ๋ทฐ์ ๋ผ๋ฒจ๋ก ํ์๋๋ฉด์ ์คํ๋ทฐ๋ก ๋ค์ด๊ฐ๊ณ , ์คํ๋ทฐ๋ ์คํฌ๋กค๋ทฐ์ ์์ ์๊ธฐ์ ๋์์์ด ๋์ด๋๋๋ผ๋ ์คํฌ๋กค์ ํตํด ๋ด์ฉ๋ค์ ์ ๋ถ ํ์ธํ ์ ์์ต๋๋ค. ์ฒ์ ์คํฌ๋กค๋ทฐ๋ฅผ ๋ณธ ์๊ฐ ๋งค๋ฒ ์๋กญ๊ฒ ์์ ๋ผ๋ฒจ์ด ์ถ๊ฐ๋์ด์ผ ํ๋๋ฐ ์คํ ๋ฆฌ๋ณด๋๋ง์ผ๋ก๋ ๊ตฌํํ๊ธฐ ํ๋ค์ง ์์๊น, ๋ผ๋ ์๊ฐ์ ํ์ต๋๋ค. ๋๋ฌธ์ ์คํฌ๋กค๋ทฐ์ ์คํ๋ทฐ์ ๊ตฌํ๋ถํฐ ์ฝ๋๋ก ํด์ผํ๋ ํ๋ ๊ณ ๋ฏผ์ ํ์ต๋๋ค. ๋ํ ์คํฌ๋กค๋ทฐ์ ์๋ก์ด ์์์ด ์ถ๊ฐ๋ ๋๋ง๋ค ํด๋น ์์์ ํ์ธํ ์ ์๊ฒ ์๋์คํฌ๋กค์ด ๋์ด์ผ ํ๋๋ฐ ๊ธฐ์กด ์ฝ๋์์๋ ์ต์ ๊ฒ ์ง์ ์ ์์๊น์ง๋ง ๋ณด์ด๋๋ก ํ์นธ ๋ ๋ด๋ ค๊ฐ๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
```swift
private func setCurrentFormulaViewOnScroll(_ `operator`: String, _ operand: String) {
currentFormulaStackView.addArrangedSubview(makeCurrentFormulaLabelStackView(`operator`, operand))
currentFormulaScrollView.setContentOffset(CGPoint(x: 0, y: currentFormulaScrollView.contentSize.height - currentFormulaScrollView.bounds.height), animated: true)
}
```
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
์๋ธ ์คํ๋ทฐ๋ง ์ฝ๋๋ก ๋งค๋ฒ ์์ฑํ์ฌ `IBOutlet`์ผ๋ก ์ฐ๊ฒฐํ ์คํ๋ทฐ ์์ ๋ฃ์ด์ฃผ๋ ๋ฐฉ๋ฒ์ผ๋ก ํด๊ฒฐํ์์ต๋๋ค.
```swift
private func makeCurrentFormulaLabelStackView(_ `operator`: String, _ operand: String) -> UIStackView {
let operatorLabel: UILabel = {
let label = UILabel()
label.text = `operator`
label.font = .preferredFont(forTextStyle: .title2)
label.textColor = .white
return label
}()
let operandLabel: UILabel = {
let label = UILabel()
label.text = operand.replacingOccurrences(of: ",", with: "")
label.font = .preferredFont(forTextStyle: .title2)
label.textColor = .white
return label
}()
let subStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [operatorLabel,operandLabel])
stackView.spacing = 8
stackView.alignment = .bottom
return stackView
}()
return subStackView
}
```
์๋ ์คํฌ๋กค์ ๊ฒฝ์ฐ๋ ์๋ธ ์คํ๋ทฐ๋ฅผ ์คํ๋ทฐ์ ์ถ๊ฐํ ํ์ ๊ธฐ์ค์ด ์๋๋ผ ์ถ๊ฐํ๊ธฐ ์ ์ ๊ธฐ์ค์ผ๋ก `CGPoint`๋ฅผ ์ก์์, `layoutIfNeeded()`๋ฅผ ํตํด ๊ฐ์ ์ ์ผ๋ก ์ถ๊ฐํ ํ์ ๊ธฐ์ค์ ๋ถ๋ฌ์ ์์น๋ฅผ ์ก๊ฒ ํ์ฌ ํด๊ฒฐํ์ต๋๋ค.
```swift
private func setCurrentFormulaViewOnScroll(_ `operator`: String, _ operand: String) {
currentFormulaStackView.addArrangedSubview(makeCurrentFormulaLabelStackView(`operator`, operand))
currentFormulaScrollView.layoutIfNeeded()
currentFormulaScrollView.setContentOffset(CGPoint(x: 0, y: currentFormulaScrollView.contentSize.height - currentFormulaScrollView.bounds.height), animated: true)
}
```
<br>
5๏ธโฃ **NumberFormatter ๊ตฌํ** <br>
-
๐ **๋ฌธ์ ์ ** <br>
`Double`์ `String`์ผ๋ก ๋ฐ๊พธ๋ ํ์์ผ๋ก ์์ฑํ์๋๋ ํผ์ฐ์ฐ์๋ฅผ ๋๋ฌ์ ๋ผ๋ฒจ์ ์ถ๊ฐํ ๋๋ง๋ค `decimal` ์์์ ๋ง์ถฐ 3์๋ฆฌ์ ๋ง๋ค `comma`๊ฐ ์ฐํ์ผ ํ๋๋ฐ ์ด ๊ฒฝ์ฐ `String -> Double -> String`์ผ๋ก ๋งค๋ฒ ๋ฐ๊พธ์ด์ผ ํ๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
๊ธฐ์กด์ `Double`์ `extension`์ผ๋ก ๋์๋ `NumberFormatter`๋ฅผ `ViewController` ๋ด๋ถ์ ํจ์๋ก ๊ตฌํํ์ฌ `String -> String` ํ์์ผ๋ก ์ ํํ์์ต๋๋ค.
> _์กฐ๊ธ ๋ ์ข์ ๋ฐฉ๋ฒ์ด ์์ ๊ฒ ๊ฐ๊ธฐ์ ์ถํ์ ๋ค์ ๋ฆฌํํ ๋ง ํ ์์ ์
๋๋ค._
```swift
private func formattingNumber(_ input: String) -> String {
let formatter = NumberFormatter()
let number = NSDecimalNumber.init(string: input)
formatter.maximumSignificantDigits = 15
formatter.numberStyle = .decimal
formatter.roundingMode = .halfUp
formatter.usesSignificantDigits = true
return formatter.string(from: number) ?? "NaN"
}
```
<br>
6๏ธโฃ **๋ถ๋์์์ ์ค๋ฅ** <br>
-
๐ **๋ฌธ์ ์ ** <br>
`Double`์ ์ต๋ 16์๋ฆฌ๊น์ง๋ง ์ ํํ ์๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์ฃผ์ด์ง ๊ณผ์ ์ ํํ ๊ฐ๋ฅํ ์๋ฆฟ์๋ 20์ด๊ธฐ์ `maximumSignificantDigits`๋ฅผ 20์ผ๋ก ์ฃผ์๋๋ ์จ์ ํ ๊ณ์ฐ์ ํ์ง ๋ชปํ์์ต๋๋ค. ๋ํ `Double`๊ณผ `Double`์ ๊ณ์ฐ์ ํ๊ณ ์์๊ธฐ์ ์์์ ์๋ฆฌ ๊ณ์ฐ ์ญ์ ๊ทผ์ฌ๊ฐ๋ผ๋ฆฌ์ ๊ณ์ฐ ๋๋ฌธ์ ์ ํํ ๊ฒฐ๊ณผ๊ฐ ๋์ค์ง ์์์ต๋๋ค.
````
10 รท 3 = 3.333333333334528
0.1 + 0.2 = 0.3000000000512
````
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
๋ฌธ์ ์ ํด์์ ๋ค๋ฅด๊ฒ ํด๋ณด์์ต๋๋ค. ๊ฒฐ๊ณผ๊ฐ์ผ๋ก ํํ๋ ์ ์๊ฑฐ๋ ์
๋ ฅ๊ฐ์ผ๋ก ๋ฃ์ ์ ์๋ ์๋ฆฟ์๋ 20์ผ๋ก ํด์ํด์ฌ `maximumSignificantDigits`์ 15๋ก ์ ํํ์๊ณ ๊ธฐ์กด `Operator`์์ `Double`๋ผ๋ฆฌ์ ์ฐ์ฐ ๋ถ๋ถ์ `NSDecimalNumber`์์์ `Decimal`๋ผ๋ฆฌ์ ์ฐ์ฐ์ผ๋ก ๋ณ๊ฒฝํ์ฌ ํด๊ฒฐํ์์ต๋๋ค.
```swift
private func add(lhs: Double, rhs: Double) -> Double {
return NSDecimalNumber(decimal: Decimal(lhs) + Decimal(rhs)).doubleValue
}
private func subtract(lhs: Double, rhs: Double) -> Double {
return NSDecimalNumber(decimal: Decimal(lhs) - Decimal(rhs)).doubleValue
}
private func divide(lhs: Double, rhs: Double) -> Double {
guard rhs != 0 else {
return .nan
}
return NSDecimalNumber(decimal: Decimal(lhs) / Decimal(rhs)).doubleValue
}
private func multiply(lhs: Double, rhs: Double) -> Double {
return NSDecimalNumber(decimal: Decimal(lhs) * Decimal(rhs)).doubleValue
}
```
<br>
7๏ธโฃ **๊น๋ํ ๋ถ๊ธฐ์ฒ๋ฆฌ** <br>
-
๐ **๋ฌธ์ ์ ** <br>
์ฌ๋ฌ๊ฐ์ง ์์ธ๋ค์ ์ฒ๋ฆฌํ๋๋ผ ํ ํจ์์ ๊ต์ฅํ ๋ง์ ์กฐ๊ฑด๋ฌธ์ ์์ฑํ๊ฒ ๋์์ต๋๋ค. `flag`๋ 4,5๊ฐ ์ ๋๋ก ๊ณผํ๊ฒ ์์ด์ ์ฝ๋๋ฅผ ํ์ธ์ด ์ฝ๊ณ ํด์ํ๊ธฐ๊ฐ ๋งค์ฐ ์ด๋ ค์ ์ต๋๋ค. ์์ธ์ฌํญ๋ค์ ๋ํ ๋ถ๊ธฐ ์ฒ๋ฆฌ์ ๋ํ ๋ฌธ์ ์์ต๋๋ค.
๐ **ํด๊ฒฐ๋ฐฉ๋ฒ** <br>
ํ๊ฐ์ง ๋ฒํผ์ ๋ฐ์ด๋ฃ์ง ์๊ณ ์์ธ์ ์ด๊ฒ ๋ ์ ์๋ ๋ฒํผ ๋ง๋ค ๋ฐ๋ก `IBAction` ํจ์๋ฅผ ์ ์ธํ์ฌ ํด๊ฒฐํ์์ต๋๋ค. `0, 00, . `์ ์ซ์์ ๋ถ๋ฆฌํ์๋๋ ๊ณผํ ์กฐ๊ฑด๋ฌธ๋ค๊ณผ `flag`๋ฅผ ์ค์ผ ์ ์์์ต๋๋ค. ๋ํ `flag`๋ฅผ ๋์ด `property Observer`๋ฅผ ์ฌ์ฉํ๋ ๋ถ๋ถ์ ํจ์๋ก ๋นผ์ ์ ์ธ๋ง ํ๋ฉด ๋๋๋ก ์์ ํ์์ต๋๋ค. ํ๊ฒฐ ๊ฐ๋
์ฑ์ ๋์ผ ์ ์์์ต๋๋ค.
```swift
@IBAction func tappedDotButton(_ sender: UIButton) {
guard let operandLabelText = currentOperandLabel.text,
operandLabelText.contains(".") == false,
isCalculated == false else {
return
}
currentOperandLabel.text = operandLabelText + "."
}
```
<br>
## ๐ ์ฐธ๊ณ ๋งํฌ
- [๐Apple Docs: reversed](https://developer.apple.com/documentation/swift/array/reversed())
- [๐Apple Docs: popLast](https://developer.apple.com/documentation/swift/array/poplast())
- [๐Apple Docs: removeLast](https://developer.apple.com/documentation/swift/array/removelast())
- [๐Apple Docs: NSDecimalNumber](https://developer.apple.com/documentation/foundation/nsdecimalnumber)
- [๐Apple Docs: CustomStringConvertible](https://developer.apple.com/documentation/swift/customstringconvertible)
- [๐Apple Docs: Data Formatting](https://developer.apple.com/documentation/foundation/data_formatting)
- [๐Apple Docs: ScrollView](https://developer.apple.com/documentation/uikit/uiscrollview)
- [๐Apple Docs: StackView](https://developer.apple.com/documentation/uikit/uistackview)
- [๐Apple Docs: replacingOccurrences(of:with:)](https://developer.apple.com/documentation/foundation/nsstring/1412937-replacingoccurrences)
- [๐Apple Docs_Archive: NSFormatter](https://developer.apple.com/library/archive/documentation/LegacyTechnologies/WebObjects/WebObjects_3.5/Reference/Frameworks/ObjC/Foundation/Classes/NSFormatter/Description.html#//apple_ref/occ/instm/NSFormatter/stringForObjectValue:)
- [๐blog: NumberFormatting](https://www.swiftbysundell.com/articles/formatting-numbers-in-swift/)
- [๐blog: layoutIfNeeded](https://zeddios.tistory.com/359)
</br>
## ๐ฅ ํ๊ณ
- [ํ๊ณ ๋งํฌ](https://github.com/mint3382/ios-calculator-app/wiki/%F0%9F%8F%A6%EA%B3%84%EC%82%B0%EA%B8%B0%F0%9F%92%B0)
# ํ ํ๊ณ
## ์๋ก์๊ฒ ํ๊ณ ์ถ์ ๋ง
- to.MINT
์ค๋๋ง์ ๋ฏผํธ๋ ํจ๊ป ํ๋ก์ ํธ๋ฅผ ํด์ ๋๋ฌด ์ข์์ต๋๋ค.๐ ๊ฐ์ด ๊ณต๋ถํ๊ณ ์ง๋ฌธ๋ ํ๊ณ ํญ์ ์์ด๋์ด ๋์น๋ ๋ฏผํธ๋ผ์ ๋ํํ๋ ๋ด๋ด ๋ง์ด ๋ฐฐ์ธ ์ ์๋ ๊ธฐํ์์ต๋๋ค. ํญ์ ์ด์ฌํ ํ๋ ๋ฏผํธ๋ผ ์ ๋ ๋ฉ๋ฌ์ ๊ฐ์ด ํ๊ฒ ๋๋ ๊ฒ ๊ฐ์์. ๊ทธ๋๋ ๊ผญ ๋ฏผํธ ์ค์ค๋ก ๊ฑด๊ฐ์ ์ฑ๊ธฐ๋ฉด์ ํ๋ฉด ์ข๊ฒ ์ต๋๋ค.๐ญ ์์ผ๋ก ๋จ์ 4๊ฐ์ ์ ๋์ ์๊ฐ ๋์ ๋ค๋ฅธ ์ธ๋ถ์ ์ธ ์คํธ๋ ์ค ์์ด ๊ณต๋ถํ ์ ์๊ธฐ๋ฅผ ๋น๋ฉฐ ์ปค๋ฆฌ์ด ์บ ํ๊ฐ ๋๋ ๋์๋ ๋ฏผํธ๋ ์์ฒญ๋๊ฒ ์ฑ์ฅํ ๊ฑฐ๋ผ๊ณ ํ์ ํฉ๋๋ค.๐๐ ํ์ํ์๋ค๋ฉด ์ธ์ ๋ ๋ฏผํธ์ ๋ํ ์๋๊ฐ ๋์ด๋๋ฆฌ๊ฒ ์ต๋๋ค.โบ๏ธ 2์ฃผ๊ฐ ํจ๊ป ๊ณต๋ถํ ์ ์์ด์ ์ ๋ง ์ฆ๊ฑฐ์ด ์๊ฐ์ด์์ด์. ๋จ์ ๊ณ์ฐ๊ธฐ ํ๋ก์ ํธ๋ ํ์ดํ
์
๋๋ค.๐ฅ
- to.hoon
ํ! ์ ๋ป ์ ์ ๊ฐ์ด ์ด๋ฒ ๊ฐ์ธ ํ๋ก์ ํธ์ ์คํฌ๋ผ์ ํจ๊ป ํด์ฃผ์ด์ ๊ณ ๋ง์์.โบ๏ธ ํ๊ณผ ํ๋ฃจ์ข
์ผ ์์ผ๋ฉด์ ์๊ฒฌ ๊ต๋ฅ๋ฅผ ํ ์ ์๋ค๋ ๊ฒ์ ์์ผ์ค๋ฝ์ง๋ง ์ ๋ง ํ๋ณตํ ์ผ์ด๋๊ตฐ์.๐ ์ฒซ ๋ฒ์งธ ๊ณ ๋น๋ผ๊ณ ๋ ๋ถ๋ฆฌ๋ ๊ณ์ฐ๊ธฐ๋ฅผ ๋๋ฌด๋ ์ํ๊ณ ์ถ์ ๋ง์๊ณผ ๋ฐ๋ผ์ฃผ์ง ์๋ ๋ชธ์ ๋๋์ฑ ๋ฌด๋ฆฌ๋ฅผ ํ๋๋ฐ ํ์ด ์๋์์ผ๋ฉด ์ ๊ฐ ์ด ๋ง์ง๋ง ์ฃผ ํํ์ ์ฐธ์ฌํ ์๋ ์์๊ฒ ๋ค๋ ์๊ฐ์ด ๋ค๋๋ผ๊ตฌ์. ํญ์ ๋๋ฌด ๊ฑฑ์ ์์ผ์ ์ฃ์กํ๊ณ ๋ ๊ทธ๋งํผ ๊ฐ์ฌํ์ด์.๐ ํ์ ๋ํด ์๊ฒ๋๋ฉด ์๊ฒ ๋ ์๋ก ์กด๊ฒฝํ๊ฒ ๋๋ ๊ฒ ๊ฐ์์. ์ ์ฐก์ฐก๋ ๋ค์ด์ฃผ์
์ ์ ๋ง ๊ฐ์ฌํฉ๋๋ค.๐คฃ ํ๋ ์ธ์ ๋ ์ง ๋ํ์๋๊ฐ ํ์ํ์๋ค๋ฉด(์ฌ์ฌํด์๋ผ๋) ์ ๋ฅผ ๋ถ๋ฌ์ฃผ์ธ์!๐ ๋จ์ ๊ธฐ๊ฐ๋ ํ์ดํ
! ์ ๋ถํ๋๋ ค์~๐ค