###### tags: `project` # ๐Ÿฆ๐Ÿ’ฐ๊ณ„์‚ฐ๊ธฐ _ ํ›ˆ๋ฏผํŠธ ![](https://hackmd.io/_uploads/SJStjdW82.png) ## 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 ![](https://hackmd.io/_uploads/BJuRGQr82.png) ## ๊ณ ๋ฏผํ–ˆ๋˜ ์  ### `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 ํ›ˆ! ์„ ๋œป ์ €์™€ ๊ฐ™์ด ์ด๋ฒˆ ๊ฐœ์ธ ํ”„๋กœ์ ํŠธ์˜ ์Šคํฌ๋Ÿผ์„ ํ•จ๊ป˜ ํ•ด์ฃผ์–ด์„œ ๊ณ ๋งˆ์›Œ์š”.โ˜บ๏ธ ํ›ˆ๊ณผ ํ•˜๋ฃจ์ข…์ผ ์žˆ์œผ๋ฉด์„œ ์˜๊ฒฌ ๊ต๋ฅ˜๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ƒˆ์‚ผ์Šค๋Ÿฝ์ง€๋งŒ ์ •๋ง ํ–‰๋ณตํ•œ ์ผ์ด๋”๊ตฐ์š”.๐Ÿ˜Ž ์ฒซ ๋ฒˆ์งธ ๊ณ ๋น„๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋Š” ๊ณ„์‚ฐ๊ธฐ๋ฅผ ๋„ˆ๋ฌด๋‚˜ ์ž˜ํ•˜๊ณ  ์‹ถ์€ ๋งˆ์Œ๊ณผ ๋”ฐ๋ผ์ฃผ์ง€ ์•Š๋Š” ๋ชธ์— ๋”๋”์šฑ ๋ฌด๋ฆฌ๋ฅผ ํ–ˆ๋Š”๋ฐ ํ›ˆ์ด ์•„๋‹ˆ์—ˆ์œผ๋ฉด ์ œ๊ฐ€ ์ด ๋งˆ์ง€๋ง‰ ์ฃผ ํŒ€ํ”Œ์„ ์ฐธ์—ฌํ•  ์ˆ˜๋„ ์—†์—ˆ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค๋”๋ผ๊ตฌ์š”. ํ•ญ์ƒ ๋„ˆ๋ฌด ๊ฑฑ์ •์‹œ์ผœ์„œ ์ฃ„์†กํ•˜๊ณ  ๋˜ ๊ทธ๋งŒํผ ๊ฐ์‚ฌํ–ˆ์–ด์š”.๐Ÿ˜‚ ํ›ˆ์— ๋Œ€ํ•ด ์•Œ๊ฒŒ๋˜๋ฉด ์•Œ๊ฒŒ ๋  ์ˆ˜๋ก ์กด๊ฒฝํ•˜๊ฒŒ ๋˜๋Š” ๊ฒƒ ๊ฐ™์•„์š”. ์ œ ์ฐก์ฐก๋„ ๋“ค์–ด์ฃผ์…”์„œ ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.๐Ÿคฃ ํ›ˆ๋„ ์–ธ์ œ๋“ ์ง€ ๋Œ€ํ™”์ƒ๋Œ€๊ฐ€ ํ•„์š”ํ•˜์‹œ๋‹ค๋ฉด(์‹ฌ์‹ฌํ•ด์„œ๋ผ๋„) ์ €๋ฅผ ๋ถˆ๋Ÿฌ์ฃผ์„ธ์š”!๐Ÿ˜ˆ ๋‚จ์€ ๊ธฐ๊ฐ„๋„ ํŒŒ์ดํŒ…! ์ž˜ ๋ถ€ํƒ๋“œ๋ ค์š”~๐Ÿค—