๐Ÿ“– ์šฐํ…Œ์ฝ” 7๊ธฐ ํ”„๋ฆฌ์ฝ”์Šค 2์ฃผ์ฐจ ํšŒ๊ณ 

ByEunwoo
woowacourse

๐Ÿ“Œ ํ”„๋ฆฌ์ฝ”์Šค 2์ฃผ์ฐจ๋ฅผ ํ†ตํ•ด์„œ ๋ฐฐ์› ๋˜ ์ 

ํ”„๋ฆฌ์ฝ”์Šค๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ ์ดˆ๊ธฐ์— ์„ค์ •ํ–ˆ๋˜ ๋ชฉํ‘œ๋ฅผ ๋‹ฌ์„ฑํ•˜๊ณ , ๋” ๋‚˜์•„๊ฐ€ ์˜ˆ์ƒํ–ˆ๋˜ ๊ฒƒ๋ณด๋‹ค ๋งŽ์€ ์„ฑ์žฅ์„ ์ด๋ฃฐ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 1์ฃผ์ฐจ ๊ณผ์ œ๋ฅผ ํ†ตํ•˜์—ฌ ๋งŽ์€ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„๋“ค์„ ์ฑ„์šฐ๊ณ  ์ œ ์Šค์Šค๋กœ ๋” ํ›Œ๋ฅญํ•œ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋กœ ์„ฑ์žฅํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ํฐ ๊ฒฝํ—˜์ด ๋œ ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

1์ฃผ์ฐจ 'Calculator' ๊ณผ์ œ์—์„œ๋Š” MVC ํŒจํ„ด์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๋ถ€์กฑํ•ด View, Model, Controller๋กœ ๊ฐ ์—ญํ• ์— ๋งž์ถฐ์„œ ๋‚˜๋ˆ„์ง€ ์•Š๊ณ , ๊ฐ ์—ญํ• ๋Œ€๋กœ ์ชผ๊ฐœ๋ ค๊ณ  ๋…ธ๋ ฅ์„ ํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ์—ฌ๋Ÿฌ ์—ญํ• ์„ ์ฒ˜๋ฆฌ๋ฅผ ํ•œ ๋ถ€๋ถ„์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ 1์ฃผ์ฐจ ๊ณผ์ œ์˜ PR์— ๋Œ€ํ•œ ๋ฆฌ๋ทฐ๋ฅผ ํ†ตํ•˜์—ฌ ๋‹ค๋ฅธ ์ฐธ๊ฐ€์ž๋“ค์˜ ์ฝ”๋“œ ๋ฆฌ๋ทฐ์™€ ํ”ผ๋“œ๋ฐฑ์„ ํ†ตํ•ด ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์—ญํ• ๊ณผ ์ฑ…์ž„์— ๋Œ€ํ•ด ๊นŠ์ด ์žˆ๊ฒŒ ๊ณ ๋ฏผํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , ์ด๋ฅผ 2์ฃผ์ฐจ '์ž๋™์ฐจ ๊ฒฝ์ฃผ' ๊ฒŒ์ž„์—์„œ ๋ฐฐ์šด ์ ๊ณผ ๊นจ๋‹ฌ์€ ์ ๋“ค์„ ์ ๊ทน ๋ฐ˜์˜ํ–ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ์ฒด์ ์œผ๋กœ, Model์€ ์ž๋™์ฐจ์˜ ์ƒํƒœ์™€ ๊ฒŒ์ž„ ์ง„ํ–‰์„ ๋‹ด๋‹นํ•˜๊ณ , Controller๋Š” ์‚ฌ์šฉ์ž ์ž…๋ ฅ ๊ฒ€์ฆ๊ณผ ๊ฒŒ์ž„ ์ง„ํ–‰ ํ๋ฆ„ ์ œ์–ด, ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต์„, View๋Š” ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์ž…์ถœ๋ ฅ๋งŒ ๋‹ด๋‹นํ•˜๋„๋ก ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์šฐ์Šน์ž ๋ฐฐ์—ด์„ ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„๋œ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋กœ์ง์„ OutputView์—์„œ Controller๋กœ ์ด๋™์‹œํ‚ค๋ฉด์„œ, "์ถœ๋ ฅ์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ€๊ณต์€ Controller์˜ ์ฑ…์ž„์ด๊ณ , View๋Š” ๋‹จ์ˆœ ์ถœ๋ ฅ๋งŒ ๋‹ด๋‹นํ•œ๋‹ค"๋Š” ์›์น™์„ ๋ช…ํ™•ํžˆ ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ๊ตฌ์กฐ ๊ฐœ์„ ์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ํ…Œ์ŠคํŠธ ์šฉ์ด์„ฑ์ด ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ๊ณ , ๊ฐ ์ปดํฌ๋„ŒํŠธ์˜ ์—ญํ• ์ด ๋ช…ํ™•ํ•ด์ ธ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ธฐ๋„ ๋” ์‰ฌ์›Œ์กŒ์Šต๋‹ˆ๋‹ค.

๊ธฐ์ˆ ์ ์ธ ๋ฉด์—์„œ๋Š” JavaScript์— ๋Œ€ํ•œ ์ดํ•ด๋„๊ฐ€ ํฌ๊ฒŒ ํ–ฅ์ƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ํด๋ž˜์Šค๋ฅผ ํ™œ์šฉํ•œ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ MVC ํŒจํ„ด์„ ์‹ค์ œ๋กœ ์ ์šฉํ•˜๋ฉด์„œ, private ํ•„๋“œ๋ฅผ ํ™œ์šฉํ•œ ์บก์Аํ™”, ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹, ์ฝœ๋ฐฑ ํ•จ์ˆ˜ ๋“ฑ JavaScript์˜ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ํšจ๊ณผ์ ์œผ๋กœ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค. ์ž๋™์ฐจ ๊ฒฝ์ฃผ ๊ฒŒ์ž„์—์„œ Game ํด๋ž˜์Šค์˜ play ๋ฉ”์„œ๋“œ์— ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•˜์—ฌ ์ง„ํ–‰ ์ƒํ™ฉ์„ ์ถœ๋ ฅํ•˜๋Š” ๋ถ€๋ถ„์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์ฝœ๋ฐฑ ํ•จ์ˆ˜์— ๋Œ€ํ•ด์„œ๋„ ๊นŠ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ฃผ๋„ ๊ฐœ๋ฐœ์˜ ๊ฐ€์น˜๋„ ๊นŠ์ด ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. Jest๋ฅผ ํ™œ์šฉํ•œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ์ž‘์„ฑ์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ด๊ณ , ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฒ„๊ทธ๋ฅผ ์‚ฌ์ „์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. 2์ฃผ์ฐจ์— ์ƒˆ๋กญ๊ฒŒ ์ ์šฉํ•œ 'test.each'๋ฅผ ์‚ฌ์šฉํ•œ 'Table-driven testing'์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์—ˆ๊ณ , ์ด๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ Edgy case๋“ค๋ฅผ ํšจ๊ณผ์ ์œผ๋กœ ๊ฒ€์ฆํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

1์ฃผ์ฐจ์™€ ๋น„๊ตํ•˜์—ฌ ๊ฐ€์žฅ ํฐ ๋ณ€ํ™”๋Š” ์ฝ”๋“œ ์„ค๊ณ„ ๋Šฅ๋ ฅ์˜ ํ–ฅ์ƒ์ž…๋‹ˆ๋‹ค. ๋‹จ์ผ ์ฑ…์ž„ ์›์น™์„ ์ฒ ์ €ํžˆ ์ ์šฉํ•˜์—ฌ ํด๋ž˜์Šค์™€ ๋ฉ”์„œ๋“œ๋ฅผ ๋” ์ž‘์€ ๋‹จ์œ„๋กœ ๋ถ„๋ฆฌํ•˜์˜€๊ณ , ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ†ตํ•ด ๊ฒฐํ•ฉ๋„๋ฅผ ๋‚ฎ์ถ”์—ˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, 'Calculator' ๊ฒŒ์ž„์—์„œ ์ฒ˜์Œ์—๋Š” ํ•˜๋‚˜์˜ ํด๋ž˜์Šค์— ์—ฌ๋Ÿฌ ๋กœ์ง์„ ๋„ฃ์—ˆ์ง€๋งŒ, 2์ฃผ์ฐจ์—์„œ๋Š” testUtils, validator ๋“ฑ์œผ๋กœ ์ฑ…์ž„์„ ๋ถ„๋ฆฌํ•˜๋ฉด์„œ ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์žฌ์‚ฌ์šฉ์„ฑ์„ ํฌ๊ฒŒ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ Airbnb JavaScript Style Guide์™€ AngularJS commit convention ๋“ฑ ์‹ค๋ฌด์—์„œ ์‚ฌ์šฉ๋˜๋Š” ๋‹ค์–‘ํ•œ ์ปจ๋ฒค์…˜์„ ํ•™์Šตํ•˜๊ณ  ์ ์šฉํ•˜๋ฉด์„œ, ํ˜‘์—…๊ณผ ์ฝ”๋“œ ํ’ˆ์งˆ ๊ด€๋ฆฌ์˜ ์ค‘์š”์„ฑ์„ ๊นŠ์ด ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ "feat", "refactor", "test" ๋“ฑ์˜ ๋ช…ํ™•ํ•œ ์ปค๋ฐ‹ ์ปจ๋ฒค์…˜์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ ์ด๋ ฅ์„ ํšจ๊ณผ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐฐ์› ์Šต๋‹ˆ๋‹ค.

ํ”„๋ฆฌ์ฝ”์Šค๋ฅผ ํ†ตํ•ด ๊ฐ€์žฅ ํฌ๊ฒŒ ๊นจ๋‹ฌ์€ ์ ์€ "์ข‹์€ ์ฝ”๋“œ"๋ž€ ๋‹จ์ˆœํžˆ ๋™์ž‘ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ, ์ฝ๊ธฐ ์‰ฝ๊ณ , ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์šฉ์ดํ•˜๋ฉฐ, ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์ฝ”๋“œ๋ผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐Ÿ”ง ์ƒˆ๋กญ๊ฒŒ ๋ฐฐ์› ๊ฑฐ๋‚˜ ๋ณด์ถฉํ•œ ๊ฐœ๋…๋“ค!

static์˜ ๊ธฐ๋ณธ ๊ฐœ๋…

static์€ '์ •์ '์ด๋ผ๋Š” ์˜๋ฏธ๋กœ, ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์•„๋‹Œ ํด๋ž˜์Šค ์ž์ฒด์— ์†ํ•˜๋Š” ๋ฉค๋ฒ„๋ฅผ ์ •์˜ํ•  ๋•Œ ์‚ฌ์šฉ
ํ”„๋กœ๊ทธ๋žจ์ด ์‹œ์ž‘๋  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ํ•œ ๋ฒˆ ํ• ๋‹น๋˜์–ด ํ”„๋กœ๊ทธ๋žจ์ด ์ข…๋ฃŒ๋  ๋•Œ๊นŒ์ง€ ์œ ์ง€

์ฃผ์š” ํŠน์ง•:

๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

static ๋ฉค๋ฒ„๋Š” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ 
์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š์•„๋„ ์ ‘๊ทผ ๊ฐ€๋Šฅ
๋ฉ”๋ชจ๋ฆฌ์— ํ•œ ๋ฒˆ๋งŒ ํ• ๋‹น๋จ

์ ‘๊ทผ ๋ฐฉ๋ฒ•

static ๋ฉค๋ฒ„: ํด๋ž˜์Šค๋ช….๋ฉค๋ฒ„๋กœ ์ ‘๊ทผ
์ผ๋ฐ˜ ๋ฉค๋ฒ„: ์ธ์Šคํ„ด์Šค.๋ฉค๋ฒ„๋กœ ์ ‘๊ทผ


static์„ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ

class OutputView {
  static print(message) {
    console.log(message);
  }
}
 
// ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
OutputView.print('์•ˆ๋…•ํ•˜์„ธ์š”'); // ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ฐ”๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

static์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ

class OutputView {
  print(message) {
    console.log(message);
  }
}
 
// ์‚ฌ์šฉ ๋ฐฉ๋ฒ•
const outputView = new OutputView(); // ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ์ด ํ•„์š”
outputView.print('์•ˆ๋…•ํ•˜์„ธ์š”'); // ์ธ์Šคํ„ด์Šค๋ฅผ ํ†ตํ•ด ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ

์ฃผ์š” ์ฐจ์ด์ :

์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์—ฌ๋ถ€

static: ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ
non-static: ๋ฐ˜๋“œ์‹œ new ํ‚ค์›Œ๋“œ๋กœ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋จผ์ € ์ƒ์„ฑํ•ด์•ผ ํ•จ

๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ

static: ํด๋ž˜์Šค ๋ ˆ๋ฒจ์—์„œ ํ•œ ๋ฒˆ๋งŒ ๋ฉ”๋ชจ๋ฆฌ์— ํ• ๋‹น๋จ
non-static: ์ธ์Šคํ„ด์Šค๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ๋งˆ๋‹ค ๋ฉ”๋ชจ๋ฆฌ์— ์ƒˆ๋กœ ํ• ๋‹น๋จ

์šฉ๋„

static: ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜์ฒ˜๋Ÿผ ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ์™€ ๊ด€๊ณ„์—†์ด ๋™์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ์— ์ ํ•ฉ
non-static: ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ์— ๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•ด์•ผ ํ•˜๋Š” ๊ธฐ๋Šฅ์— ์ ํ•ฉ

์˜ˆ์ œ์˜ OutputView ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ๋‹จ์ˆœํžˆ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ฏ€๋กœ, ์ธ์Šคํ„ด์Šค์˜ ์ƒํƒœ์™€ ๊ด€๊ณ„์—†์ด ๋™์ž‘ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ static์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๋” ์ ์ ˆํ•  ์ˆ˜ ์žˆ๋‹ค.


MAGIC number ๋Œ€์‹  ์ƒ์ˆ˜๋กœ ๋ณ€๊ฒฝ!

๋งค๊ฐœ๋ณ€์ˆ˜๋ช…์„ ๋” ๋ช…๋ฃŒํ•˜๊ฒŒ ๋‚˜ํƒ€๋‚ด๊ธฐ ์œ„ํ•˜์—ฌ ์ƒ์ˆ˜๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ!

// MAGIC NUMBER ๋Œ€์‹  ์ƒ์ˆ˜๋กœ ๋ณ€๊ฒฝ
const START = 1;
const END = 45;
const NOT_DUPLICATED_NUMBER = 6;
 
class generateNumber {
  createRandomNumbers() {
    return Random.pickUniqueNumbersInRange(START, END, NOT_DUPLICATED_NUMBER);
  }
}
 
export default generateNumber;

JSdoc ์ฃผ์„

JSDoc๋Š” JavaScript ์ฝ”๋“œ์— ์ฃผ์„์„ ๋‹ฌ์•„ ์ฝ”๋“œ์— ๋Œ€ํ•œ ์„ค๋ช…์„ ์ œ๊ณตํ•˜๊ณ , ํ•จ์ˆ˜, ๋ณ€์ˆ˜, ๊ฐ์ฒด ๋“ฑ์— ๋Œ€ํ•œ ๋ฌธ์„œํ™”๋ฅผ ๋•๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ํ˜‘์—… ์‹œ ์ฝ”๋“œ์˜ ๊ฐ€๋…์„ฑ์„ ๋†’์ด๊ณ , ์ฝ”๋“œ์˜ ์˜๋„๋ฅผ ์‰ฝ๊ฒŒ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

JSDoc ์ฃผ์„์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋Š” /**๋กœ ์‹œ์ž‘ํ•˜๋ฉฐ, ๋ณดํ†ต ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ •๋ณด๋ฅผ ํฌํ•จํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค:

  • ํ•จ์ˆ˜ ์„ค๋ช…: ํ•จ์ˆ˜๊ฐ€ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.
  • ๋งค๊ฐœ๋ณ€์ˆ˜ ์„ค๋ช… (@param): ํ•จ์ˆ˜์˜ ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์ •์˜ํ•˜๊ณ , ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ํƒ€์ž…๊ณผ ์„ค๋ช…์„ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜ํ™˜๊ฐ’ ์„ค๋ช… (@returns): ํ•จ์ˆ˜์˜ ๋ฐ˜ํ™˜๊ฐ’์ด ๋ฌด์—‡์ธ์ง€ ์„ค๋ช…ํ•˜๊ณ , ๋ฐ˜ํ™˜๊ฐ’์˜ ํƒ€์ž…์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค.
  • ํƒ€์ž… ์ •์˜ (@type): ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด์˜ ํƒ€์ž…์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๊ธฐํƒ€ ํƒœ๊ทธ: @example(์‚ฌ์šฉ ์˜ˆ์‹œ), @deprecated(๋น„์ถ”์ฒœ), @async(๋น„๋™๊ธฐ ํ•จ์ˆ˜ ํ‘œ์‹œ) ๋“ฑ ๋‹ค์–‘ํ•œ ํƒœ๊ทธ๋กœ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
/**
 * ๋‘ ์ˆซ์ž๋ฅผ ๋”ํ•˜๋Š” ํ•จ์ˆ˜
 * @param {number} a - ์ฒซ ๋ฒˆ์งธ ์ˆซ์ž
 * @param {number} b - ๋‘ ๋ฒˆ์งธ ์ˆซ์ž
 * @returns {number} ๋‘ ์ˆซ์ž์˜ ํ•ฉ
 * @example
 * // ๋ฐ˜ํ™˜๊ฐ’: 3
 * add(1, 2);
 */
function add(a, b) {
  return a + b;
}

JSDoc์„ ํ†ตํ•ด ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ๊ฐ€๋…์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์–ด ๋งŽ์€ ํ”„๋กœ์ ํŠธ์—์„œ ํ™œ์šฉ๋ฉ๋‹ˆ๋‹ค.

JSDoc์€ ๋ฌธ์„œํ™”์™€ ์ฝ”๋“œ ์„ค๋ช…์—๋งŒ ์ดˆ์ ์ด ๋งž์ถฐ์ ธ ์žˆ์œผ๋ฉฐ, ์ฝ”๋“œ์˜ ๋™์ž‘์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. JSDoc์€ ์ฃผ์„ ํ˜•์‹์œผ๋กœ ์ž‘์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— JavaScript์˜ ์‹ค์ œ ์‹คํ–‰์—๋Š” ๊ฐœ์ž…ํ•˜์ง€ ์•Š๊ณ , ๋‹ค์Œ๊ณผ ๊ฐ™์€ ํŽธ๋ฆฌํ•จ์„ ์ œ๊ณตํ•˜๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ ์ž๋™ ์ƒ์„ฑ: JSDoc ์ฃผ์„์„ ๊ธฐ๋ฐ˜์œผ๋กœ HTML ๋ฌธ์„œ๋‚˜ Markdown ํ˜•์‹์˜ API ๋ฌธ์„œ๋ฅผ ์ž๋™ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ณ„๋„์˜ ์„ค๋ช… ๋ฌธ์„œ๋ฅผ ์ž‘์„ฑํ•  ํ•„์š” ์—†์ด ์ฝ”๋“œ์™€ ๋ฌธ์„œ๊ฐ€ ํ•ญ์ƒ ์ผ์น˜ํ•˜๊ฒŒ ์œ ์ง€๋ฉ๋‹ˆ๋‹ค.

์ฝ”๋“œ ํŽธ์ง‘๊ธฐ ์ง€์›: ๋งŽ์€ IDE(Visual Studio Code, WebStorm ๋“ฑ)์—์„œ JSDoc์„ ์ธ์‹ํ•˜๊ณ  ์ฝ”๋“œ ์ž๋™ ์™„์„ฑ ๊ธฐ๋Šฅ์„ ๊ฐ•ํ™”ํ•ด์ค๋‹ˆ๋‹ค. ํ•จ์ˆ˜ ์„ค๋ช…, ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…, ๋ฐ˜ํ™˜ ํƒ€์ž… ๋“ฑ์„ ์ž๋™์œผ๋กœ ํ‘œ์‹œํ•˜์—ฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์‹ค์ˆ˜๋ฅผ ์ค„์ด๊ณ  ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

ํƒ€์ž… ๊ฒ€์‚ฌ: TypeScript๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ JSDoc์„ ํ†ตํ•ด ์–ด๋А ์ •๋„ ํƒ€์ž… ์ •๋ณด๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. IDE๋‚˜ ์ผ๋ถ€ ๋นŒ๋“œ ๋„๊ตฌ์—์„œ JSDoc ํƒ€์ž… ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ธฐ๋ณธ์ ์ธ ํƒ€์ž… ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์™„์ „ํ•œ ํƒ€์ž… ๊ฒ€์‚ฌ๋Š” ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— TypeScript์™€ ๊ฐ™์€ ์ •์  ํƒ€์ž… ๊ฒ€์‚ฌ๋งŒํผ ๊ฐ•๋ ฅํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค.

์ฆ‰, JSDoc์€ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฝ”๋“œ๋ฅผ ์ดํ•ดํ•˜๊ณ  ์œ ์ง€๋ณด์ˆ˜ํ•˜๋Š” ๋ฐ ์œ ์šฉํ•œ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, ์ฝ”๋“œ์˜ ๋กœ์ง์ด๋‚˜ ์‹คํ–‰์—๋Š” ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š” ์„ค๋ช…์šฉ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.


ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ vs ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ

๋ฆฌ์•กํŠธ ์ปดํฌ๋„ŒํŠธ์˜ ์ข…๋ฅ˜์—๋Š” ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์™€ ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ES6์˜ ํด๋ž˜์Šค ๋ฌธ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉฐ, ์ƒํƒœ์™€ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ๊ฐ€์ง‘๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ์ƒ๋ช…์ฃผ๊ธฐ์™€ ๊ด€๋ จ๋œ ๋ณต์žกํ•œ ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ๋•Œ ์žฅ์ ์ด ์žˆ์ง€๋งŒ, ์ž์นซ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด์ ธ ๊ฐ€๋…์„ฑ์ด ๋–จ์–ด์ง€๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋‚ฎ์•„์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
 
  increment() {
    this.setState({ count: this.state.count + 1 });
  }
 
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.increment()}>Increment</button>
      </div>
    );
  }
}

๋ฐ˜๋ฉด, ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ๊ฐ„๋‹จํ•œ ํ•จ์ˆ˜๋กœ ์ •์˜๋ฉ๋‹ˆ๋‹ค.
๊ธฐ์กด์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ•จ์ˆ˜ ํ‘œํ˜„์‹์œผ๋กœ ์“ธ ์ˆ˜ ์žˆ๊ณ , ES6 ๋ฌธ๋ฒ•์ธ ํ™”์‚ดํ‘œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ •์˜ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ์ž์ฒด๋กœ๋Š” ์ƒํƒœ์™€ ์ƒ๋ช…์ฃผ๊ธฐ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์ง€๋งŒ, ๋ฆฌ์•กํŠธ ํ›…์„ ํ†ตํ•ด ์ƒํƒœ๋‚˜ ์ƒ๋ช…์ฃผ๊ธฐ์™€ ๊ด€๋ จ๋œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.ย 

ย 

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ

import React, { useState } from 'react';
 
const Counter = () => {
  const [count, setCount] = useState(0);
 
  const increment = () => {
    setCount((prevCount) => prevCount + 1);
  };
 
  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};
 
export default Counter;

๋‘ ์ฝ”๋“œ๋Š” ๋™์ผํ•œ ๊ธฐ๋Šฅ์„ ํ•˜์ง€๋งŒ, ์ž‘์„ฑ ๋ฐฉ์‹์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋” ํ˜„๋Œ€์ ์ธ React ๋ฐฉ์‹์ด๋ฉฐ, Hooks๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์ฝ๊ธฐ ์‰ฌ์šด ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹โ€‹

ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ž˜์Šคํ˜• ์ปดํฌ๋„ŒํŠธ์— ๋น„ํ•ด ์ฝ”๋“œ๊ฐ€ ๊ฐ„๊ฒฐํ•˜๊ณ , ํ…Œ์ŠคํŠธ์™€ ๋””๋ฒ„๊น…์ด ์šฉ์ดํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋Ÿฌํ•œ ์ด์œ ๋กœ ํ˜„์žฌ ๋ฆฌ์•กํŠธ ๊ณต์‹ ๋ฌธ์„œ์—์„œ๋Š” ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ๋Œ€์‹  ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Posted inwoowacourse
Written byEunwoo