0718 ~ 0724


# 0718 ~ 0724

# 0719 - ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„(Domain Driven Development) ์ดํ•ด

# ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„ ๋„์ž… ๋ฐฐ๊ฒฝ

Before

# ๊ธฐ์กด ๊ฐœ๋ฐœ

  • ๋ฐ์ดํ„ฐ์— ์ข…์†์ ์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
  • ๋ชจ๋ธ๋ง๊ณผ ๊ฐœ๋ฐœ๊ณผ์˜ ๋ถˆ์ผ์น˜ ๋ฐœ์ƒ

After

# ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„

  • ์ด๋Ÿฐ ๋ถˆ์ผ์น˜๋ฅผ ํ•ด์†Œํ•˜๊ธฐ ์œ„ํ•œ ๋…ธ๋ ฅ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ DDD
  • ๊ณตํ†ต์˜ ์–ธ์–ด(*์œ ๋น„์ฟผํ„ฐ์Šค ์–ธ์–ด)๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋„๋ฉ”์ธ๊ณผ ๊ตฌํ˜„์„ ์ถฉ๋ถ„ํžˆ ๋งŒ์กฑํ•˜๋Š” ๋ชจ๋ธ์„ ๋งŒ๋“ ๋‹ค.
  • *์œ ๋น„์ฟผํ„ฐ์Šค ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์šฉ์–ด์‚ฌ์ „์„ ๋งŒ๋“ ๋‹ค. (์˜ˆ) ํ—Œํ„ฐ | hunter | ๋ณด๋ฌผ์„ ์ฐพ๋Š” ์‚ฌ๋ƒฅ๊พผ
  • '์„ค๊ณ„'์™€ '๊ตฌํ˜„'์€ ๊ณ„์†๋œ ์ˆ˜์ • ๊ณผ์ •์„ ๊ฑฐ์นœ๋‹ค. (๋ฐ˜๋ณต ์ž‘์—…)

*์œ ๋น„์ฟผํ„ฐ์Šค ์–ธ์–ด(๋ณดํŽธ ์–ธ์–ด)๋ž€? ๋„๋ฉ”์ธ ์–ดํœ˜๋ฅผ ์ดํ•ด๊ด€๋ฆฌ์ž๋“ค์ด ๊ณตํ†ต์ ์œผ๋กœ ์˜๋ฏธ๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก ์ •์˜ํ•˜๋Š” ๊ฒƒ

ํšจ๊ณผ์ ์ธ ๋ชจ๋ธ๋ง

  • ์‚ฌ์šฉ์ž์™€ ๊ฐœ๋ฐœ์ž๋Š” ๋™์ผํ•œ ์–ธ์–ด๋กœ ์ด์•ผ๊ธฐ ํ•˜๋Š”๊ฐ€?
  • ํ•ด๋‹น ์–ธ์–ด๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ˆ˜ํ–‰ํ•ด์•ผ ํ•  ๋‚ด์šฉ์— ๊ด€ํ•œ ๋…ผ์˜๋ฅผ ์ด๋Œ์–ด๊ฐˆ ๋งŒํผ ํ’์„ฑํ•œ๊ฐ€?

๋„๋ฉ”์ธ

  • ์ผ๋ฐ˜์ ์ธ ์š”๊ตฌํ•˜์ƒ, ์ „๋ฌธ ์šฉ์–ด, ๊ทธ๋ฆฌ๊ณ  ์ปดํ“จํ„ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ถ„์•ผ์—์„œ ๋ฌธ์ œ๋ฅผ ํ’€๊ธฐ ์œ„ํ•ด ์„ค๊ณ„๋œ ์–ด๋–ค ์†Œํ”„ํŠธ์›จ์–ด ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ๊ธฐ๋Šฅ์„ฑ์„ ์ •์˜ํ•˜๋Š” ์—ฐ๊ตฌ์˜ ํ•œ ์˜์—ญ
  • ์†Œํ”„ํŠธ์›จ์–ด๋กœ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฌธ์ œ ์˜์—ญ (์˜ˆ) ๊ด‘๊ณ ํšŒ์‚ฌ์˜ ๊ด‘๊ณ ์™€ ๊ด€๋ จ๋œ ์ง€์‹ = ๋„๋ฉ”์ธ

๋„๋ฉ”์ธ ๋ชจ๋ธ

  • ํŠน์ • ๋„๋ฉ”์ธ์„ ๊ฐœ๋…์ ์œผ๋กœ ํ‘œํ˜„ํ•œ ๊ฒƒ
  • ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ ๊ด€๊ณ„์ž๋“ค(๊ฐœ๋ฐœ์ž, ๊ธฐํš์ž, ์‚ฌ์šฉ์ž ๋“ฑ)์ด ๋™์ผํ•œ ๋ชจ์Šต์œผ๋กœ ๋„๋ฉ”์ธ์„ ์ดํ•ดํ•˜๊ณ  ๋„๋ฉ”์ธ ์ง€์‹์„ ๊ณต์œ ํ•˜๋Š”๋ฐ ๋„์›€์ด ๋œ๋‹ค.
  • ๋ชจ๋ธ์˜ ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ํŠน์ • ๋„๋ฉ”์ธ์„ ํ•œ์ •ํ•  ๋•Œ ๋น„๋กœ์†Œ ์˜๋ฏธ๊ฐ€ ์™€์ „ํ•ด์ง€๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ ํ•˜์œ„ ๋„๋ฉ”์ธ๋งˆ๋‹ค ๋ณ„๋„๋กœ ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
    (์˜ˆ) ์ฟ ํŒก์—์„œ ์ƒํ’ˆ์„ ์ฃผ๋ฌธํ•  ๋•Œ ํ•„์š”ํ•œ ๊ฒƒ : ๊ณ ๊ฐ์˜ ์ฃผ๋ฌธ์„œ ๋ชจ๋ธ, ์ƒํ’ˆ ์ •๋ณด์˜ ์ƒํ’ˆ ๋ชจ๋ธ

# ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„ ์•„ํ‚คํ…์ฒ˜ ๊ฐœ์š”

image *ํ•ต์‹ฌ ๋กœ์ง(๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง)์€ ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ๋‹ด์•„์„œ ์‚ฌ์šฉํ•œ๋‹ค.

๋„๋ฉ”์ธ ๋ชจ๋ธ์˜ ๋„ค ๊ฐœ์˜ ์˜์—ญ

image *์•„๋ž˜๋กœ ๋‚ด๋ ค๊ฐˆ์ˆ˜๋ก ์˜์กด์„ฑ์ด ๊ฐ•ํ•ด์ง„๋‹ค.

  • PRESENTATION LAYER : ํ‘œํ˜„ ์˜์—ญ ๋˜๋Š” UI์˜์—ญ. ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ๋ฐ›์•„ ์‘์šฉ ์˜์—ญ์— ์ „๋‹ฌํ•˜๊ณ , ์‘์šฉ ์˜์—ญ์˜ ์ฒ˜๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณด์—ฌ์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. (Controller ์˜์—ญ, DispatcherServlet์—๊ฒŒ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ „๋‹ฌํ•˜๋Š” ์—ญํ• )
  • APPLICATION LAYER : ์‘์šฉ ์˜์—ญ. ์‹œ์Šคํ…œ์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค. (Service ์˜์—ญ)
  • DOMAIN LAYER : ๋„๋ฉ”์ธ ์˜์—ญ. ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๊ตฌํ˜„ํ•œ๋‹ค. (์ด๋ฆ„, ์ฃผ์†Œ, ์ƒํ’ˆ, ์ฃผ๋ฌธ์„œ ๋“ฑ)
  • INFRASTRUCTURE LAYER : ๊ตฌํ˜„ ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ๊ฒƒ์„ ๋‹ค๋ฃฌ๋‹ค. (์™ธ๋ถ€ API, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ ๋“ฑ)

# PRESENTATION LAYER(ํ‘œํ˜„์˜์—ญ)

  • ์‚ฌ์šฉ์ž๊ฐ€ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” (ํ™”๋ฉด) ํ๋ฆ„์„ ์ œ๊ณตํ•˜๊ณ  ์ œ์–ด
  • ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ์•Œ๋งž์€ ์‘์šฉ ์„œ๋น„์Šค์— ์ „๋‹ฌํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•œ๋‹ค.
  • ์‚ฌ์šฉ์ž์˜ ์„ธ์…˜์„ ๊ด€๋ฆฌํ•œ๋‹ค.

# APPLICATION LAYER(์‘์šฉ์˜์—ญ)

  • ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ๋กœ๋ถ€ํ„ฐ ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ•˜๊ณ , ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
  • ๋กœ์ง์„ ์ง์ ‘ ์ˆ˜ํ–‰ํ•˜๊ธฐ๋ณด๋‹ค๋Š” ๋„๋ฉ”์ธ ๋ชจ๋ธ์— ๋กœ์ง ์ˆ˜ํ–‰์„ ์œ„์ž„ํ•œ๋‹ค.
  • ๋„๋ฉ”์ธ ๊ฐ์ฒด ๊ฐ„์˜ ์‹คํ–‰ ํ๋ฆ„์„ ์ œ์–ด
  • *ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ
  • ๋„๋ฉ”์ธ ์˜์—ญ์—์„œ ๋ฐœ์ƒ์‹œํ‚จ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌ

*ํŠธ๋žœ์žญ์…˜์ด๋ž€? ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€ํ™”์‹œํ‚ค๊ธฐ ํ•ด์„œ ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์˜ ๋‹จ์œ„.

# ๋„๋ฉ”์ธ ์ฃผ๋„ ์„ค๊ณ„ ๊ธฐ๋ณธ์š”์†Œ

์—”ํ‹ฐํ‹ฐ(Entity)์™€ ๋ฒจ๋ฅ˜(Value)

  • ๋„์ถœํ•œ ๋ชจ๋ธ์€ ํฌ๊ฒŒ ์—”ํ‹ฐํ‹ฐ์™€ ๋ฒจ๋ฅ˜๋กœ ๊ตฌ๋ถ„
  • ๋ฐ์ดํ„ฐ์™€ ํ•จ๊ป˜ ๋„๋ฉ”์ธ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค. image

Entity

  • ์‹๋ณ„์ž๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • ์‹๋ณ„์ž๋Š” ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋งˆ๋‹ค ๊ณ ์œ ํ•ด์„œ ๊ฐ ์—”ํ‹ฐํ‹ฐ๋Š” ์„œ๋กœ ๋‹ค๋ฅธ ์‹๋ณ„์ž๋ฅผ ๊ฐ–๋Š”๋‹ค.

๋„๋ฉ”์ธ ๋ชจ๋ธ์— set ๋ฉ”์„œ๋“œ ๋„ฃ์ง€ ์•Š๊ธฐ

  • ๋„๋ฉ”์ธ ๋ชจ๋ธ์— get/set ๋ฉ”์„œ๋“œ๋ฅผ ๋ฌด์กฐ๊ฑด ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์ง€ ์•Š์€ ๋ฒ„๋ฆ‡์ด๋‹ค.
  • ํŠนํžˆ set ๋ฉ”์„œ๋“œ๋Š” ๋„๋ฉ”์ธ์˜ ํ•ต์‹ฌ ๊ฐœ๋…์ด๋‚˜ ์˜๋„๋ฅผ ์ฝ”๋“œ์—์„œ ์‚ฌ๋ผ์ง€๊ฒŒ ํ•œ๋‹ค.
  • set ๋ฉ”์„œ๋“œ์˜ ๋˜ ๋‹ค๋ฅธ ๋ฌธ์ œ๋Š” ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•  ๋•Œ ์™„์ „ํ•œ ์ƒํƒœ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.
  • ๋„๋ฉ”์ธ ๊ฐ์ฒด๊ฐ€ ๋ถˆ์™„์ „ํ•œ ์ƒํƒœ๋กœ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ง‰์œผ๋Ÿฌ๋ฉด ์ƒ์„ฑ ์‹œ์ ์— ํ•„์š”ํ•œ ๊ฒƒ์„ ์ „๋‹ฌํ•ด ์ฃผ์–ด์•ผ ํ•œ๋‹ค.

Value Object

  • ๋ฒจ๋ฅ˜ ํƒ€์ž…์€ ๋ถˆ๋ณ€์„ ์›์น™์œผ๋กœ ํ•œ๋‹ค.
  • ์˜๋ฏธ๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œํ˜„ํ•˜๊ฑฐ๋‚˜ ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋ฐ์ดํ„ฐ๊ฐ€ ๊ฐœ๋…์ ์œผ๋กœ ํ•˜๋‚˜์ธ ๊ฒฝ์šฐ ๋ฒจ๋ฅ˜ ํƒ€์ž…์„ ์ด์šฉํ•œ๋‹ค.
  • ์‹œ์Šคํ…œ์ด ์„ฑ์ˆ™ํ•จ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ ๊ฐ’์„ ๊ฐ์ฒด๋กœ ๋Œ€์ฒดํ•œ๋‹ค.
  • ๋ฒจ๋ฅ˜ ๊ฐ์ฒด์˜ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ์ƒˆ๋กœ์šด ๋ฒจ๋ฅ˜ ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜๋Š” ๊ฒƒ๋ฟ์ด๋‹ค.
  • ์‹๋ณ„์ž๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

Aggregate

  • ๊ด€๋ จ ๊ฐ์ฒด๋ฅผ ํ•˜๋‚˜๋กœ ๋ฌถ์€ ๊ตฐ์ง‘
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋Š” ๊ตฐ์ง‘์— ์†ํ•œ ๊ฐ์ฒด๋“ค์„ ๊ด€๋ฆฌํ•˜๋Š” ๋ฃจํŠธ ์—”ํ‹ฐํ‹ฐ๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋กœ ๋ฌถ์–ด์„œ ๋ฐ”๋ผ๋ณด๋ฉด ์ข€ ๋” ์ƒ์œ„ ์ˆ˜์ค€์—์„œ ๋„๋ฉ”์ธ ๋ชจ๋ธ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ์†ํ•œ ๊ฐ์ฒด๋Š” ์œ ์‚ฌํ•˜๊ฑฐ๋‚˜ ๋™์ผํ•œ ๋ผ์ดํ”„์‚ฌ์ดํด์„ ๊ฐ–๋Š”๋‹ค.
  • ํ•œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ์†ํ•œ ๊ฐ์ฒด๋Š” ๋‹ค๋ฅธ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ์†ํ•˜์ง€ ์•Š๋Š”๋‹ค.
  • ๋Œ€๋ถ€๋ถ„์˜ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋Š” ํ•œ๊ฐœ์˜ ์—”ํ‹ฐํ‹ฐ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋‘ ๊ฐœ ์ด์ƒ์˜ ์—”ํ‹ฐํ‹ฐ๋กœ ๊ตฌ์„ฑ๋˜๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋Š” ๋“œ๋ฌผ๊ฒŒ ์กด์žฌํ•œ๋‹ค.
  • ๊ฐ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋Š” ์ž๊ธฐ ์ž์‹ ์„ ๊ด€๋ฆฌํ• ๋ฟ ๋‹ค๋ฅธ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋Š” ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š”๋‹ค.
    (์˜ˆ)์ฃผ๋ฌธ ์• ๊ทธ๋ฆฌ ๊ฑฐํŠธ๋Š” ๋ฐฐ์†ก์ง€ ๋ณ€๊ฒฝ, ์ฃผ๋ฌธ ์ƒํ’ˆ ๋ณ€๊ฒฝ ๋“ฑ ์ž์‹ ์€ ๊ด€๋ฆฌํ•˜์ง€๋งŒ ํšŒ์› ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ, ์ƒํ’ˆ ๊ฐ€๊ฒฉ ๋ณ€๊ฒฝ ๋“ฑ์€ ํ•˜์ง€ ์•Š๋Š”๋‹ค.

image *์ฃผ๋ฌธ(Order) ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ : ์ฃผ๋ฌธ, ๋ฐฐ์†ก์ง€ ์ •๋ณด, ์ฃผ๋ฌธ์ž, ์ฃผ๋ฌธ๋ชฉ๋ก, ์ด ๊ฒฐ์ œ๊ธˆ์•ก์˜ ํ•˜์œ„ ๋ชจ๋ธ์ด ์žˆ๋‹ค. ์ด๋•Œ ์ด ํ•˜์œ„ ๊ฐœ๋…์„ ํ‘œํ˜„ํ•œ ๋ชจ๋ธ์„ ํ•˜๋‚˜๋กœ ๋ฌถ์–ด์„œ '์ฃผ๋ฌธ'์ด๋ผ๋Š” ์ƒ์œ„ ๊ฐœ๋…์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค.
์ฆ‰, ์ฃผ๋ฌธ์€ Root Aggregate๊ฐ€ ๋œ๋‹ค.
Root Aggregate๋ฅผ ์ค‘์ ์œผ๋กœ ์ข…์†๋˜์–ด ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ๋“ค์€ ๋™์ผํ•œ ๋ผ์ดํ”„์‚ฌ์ดํด(ํ•˜๋‚˜์˜ ํŠธ๋žœ์žญ์…˜)์„ ๊ฐ€์ง„๋‹ค.
*ํผ์‚ฌ๋“œ ํŒจํ„ด๊ณผ ์œ ์‚ฌํ•˜๋‹ค. (์ฐธ๊ณ : https://jusungpark.tistory.com/23)

์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋ฃจํŠธ

  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋ฃจํŠธ์˜ ํ•ต์‹ฌ ์—ญํ• ์€ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ์ผ๊ด€์„ฑ์ด ๊บ ์ง€์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.(์• ๊ทธ๋ฆฌ๊ฑฐํŠธ: ๋…๋ฆฝ๋œ ๊ฐ์ฒด๊ตฐ)
  • ๋ถ€๋“์ดํ•˜๊ฒŒ ํŠธ๋žœ์žญ์…˜์œผ๋กœ ๋‘ ๊ฐœ ์ด์ƒ์˜ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์—์„œ ๋‹ค๋ฅธ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ , ์‘์šฉ ์„œ๋น„์Šค์—์„œ ๋‘ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ˆ˜์ •ํ•˜๋„๋ก ๊ตฌํ˜„ํ•ด์•ผ ํ•œ๋‹ค.
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋ฃจํŠธ๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๊ฐ€ ์ œ๊ณตํ•ด์•ผ ํ•  ๋„๋ฉ”์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•œ๋‹ค.
  • ์ด๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ๋‚ด๋ถ€ ๊ตฌํ˜„์„ ์ˆจ๊ฒจ์„œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋‹จ์œ„๋กœ ๊ตฌํ˜„์„ ์บก์Šํ™” ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋•๋Š”๋‹ค.
  • ๋ฃจํŠธ ์—”ํ‹ฐํ‹ฐ๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ์†ํ•ด ์žˆ๋Š” ์—”ํ‹ฐํ‹ฐ์™€ ๋ฒจ๋ฅ˜ ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์„œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๊ฐ€ ๊ตฌํ˜„ํ•ด์•ผ ํ•  ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
*์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋ฃจํŠธ๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋„๋ฉ”์ธ ๋กœ์ง์„ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋งŒ๋“œ๋Š” ์Šต๊ด€*

- ๋‹จ์ˆœํžˆ ํ•„๋“œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” set ๋ฉ”์†Œ๋“œ๋ฅผ public์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค.
- ๋ฒจ๋ฅ˜ํƒ€์ž…์€ ๋ถˆ๋ณ€์œผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.

์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ์ฐธ์กฐ

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

๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ

  • ์—”ํ‹ฐํ‹ฐ๋‚˜ ๋ฒจ๋ฅ˜๊ฐ€ ์š”๊ตฌ์‚ฌํ•ญ์—์„œ ๋„์ถœ๋˜๋Š” ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด๋ผ๋ฉด, ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ๋Š” ๊ตฌํ˜„์„ ์œ„ํ•œ ๋„๋ฉ”์ธ ๋ชจ๋ธ
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ๋‹จ์œ„๋กœ ๋„๋ฉ”์ธ ๊ฐ์ฒด๋ฅผ ์ €์žฅํ•˜๊ณ  ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ •์˜ํ•œ๋‹ค.
  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ๊ตฌํ•˜๋Š” ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ ๋ฉ”์„œ๋“œ๋Š” ์™„์ „ํ•œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•œ๋‹ค.
  • ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ๊ฐ€ ์™„์ „ํ•œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ์ œ๊ณตํ•˜์ง€ ์•Š์œผ๋ฉด, ํ•„๋“œ๋‚˜ ๊ฐ’์ด ์˜ฌ๋ฐ”๋ฅด์ง€ ์•Š์•„ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•˜๋Š” ๋„์ค‘์— NPE์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ฒŒ ๋œ๋‹ค.
  • ๋ฆฌํฌ์ง€ํ„ฐ๋ฆฌ๋Š” ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ(๋ฃจํŠธ) ๋‹จ์œ„๋กœ ์กด์žฌํ•˜๋ฉฐ ํ…Œ์ด๋ธ” ๋‹จ์œ„๋กœ ์กด์žฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.

(์˜ˆ์‹œ)

public interface OrderRepository {
    public Order findByNumber(OrderNumber number);
    public void save(Order order);
    public void delete(Order order);
}

์—ฌ๋Ÿฌ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ
*๊ฒฐ์ œ ๊ธˆ์•ก ๊ณ„์‚ฐ ๋กœ์ง

  • ์ƒํ’ˆ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ : ๊ตฌ๋งคํ•˜๋Š” ์ƒํ’ˆ์˜ ๊ฐ€๊ฒฉ์ด ํ•„์š”ํ•˜๋‹ค. ๋˜ํ•œ ์ƒํ’ˆ์— ๋”ฐ๋ผ ๋ฐฐ์†ก๋น„๊ฐ€ ์ถ”๊ฐ€๋˜๊ธฐ๋„ ํ•œ๋‹ค.
  • ์ฃผ๋ฌธ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ : ์ƒํ’ˆ๋ณ„๋กœ ๊ตฌ๋งค ๊ฐœ์ˆ˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ํ• ์ธ ์ฟ ํฐ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ : ์ฟ ํฐ๋ณ„๋กœ ์ง€์ •ํ•œ ํ• ์ธ ๊ธˆ์•ก์ด๋‚˜ ๋น„์œจ์— ๋”ฐ๋ผ ์ฃผ๋ฌธ ์ด ๊ธˆ์•ก์„ ํ• ์ผํ•œ๋‹ค. ํ• ์ธ ์ฟ ํฐ์„ ์กฐ๊ฑด์— ๋”ฐ๋ผ ์ค‘๋ณต ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๊ฑฐ๋‚˜ ์ง€์ •ํ•œ ์นดํ…Œ๊ณ ๋ฆฌ์˜ ์ƒํ’ˆ์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ œ์•ฝ ์กฐ๊ฑด์ด ์žˆ๋‹ค๋ฉด ํ• ์ธ ๊ผ์‚ฐ์ด ๋ณต์žกํ•ด์ง„๋‹ค.
  • ํšŒ์› ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ : ํšŒ์› ๋“ฑ๊ธ‰์— ๋”ฐ๋ผ ์ถ”๊ฐ€ ํ• ์ธ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

"์ด ์ƒํ™ฉ์—์„œ ์‹ค์ œ ๊ฒฐ์ œ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•ด์•ผ ํ•˜๋Š” ์ฃผ์ฒด๋Š” ์–ด๋–ค ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ ์ผ๊นŒ?"

๋„๋ฉ”์ธ ์„œ๋น„์Šค

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

(์˜ˆ) ๊ณ„์ขŒ์ด์ฒด ๋กœ์ง์€ ๊ณ„์ขŒ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค. ๊ฒฐ์ œ ๊ธˆ์•ก ๋กœ์ง์€ ์ฃผ๋ฌธ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ์ฃผ๋ฌธ ๊ธˆ์•ก์„ ๊ณ„์‚ฐํ•œ๋‹ค. ์ด ๋‘๋กœ์ง์€ ๊ฐ๊ฐ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ  ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ๊ฐ’์„ ๊ณ„์‚ฐํ•˜๋Š” ๋„๋ฉ”์ธ ๋กœ์ง์ด๋‹ค.
๋„๋ฉ”์ธ ๋กœ์ง์ด๋ฉด์„œ ํ•œ ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์— ๋„ฃ๊ธฐ ์ ํ•ฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ์ด ๋‘ ๋กœ์ง์€ ๋„๋ฉ”์ธ ์„œ๋น„์Šค๋กœ ๊ตฌํ˜„ํ•˜๊ฒŒ ๋œ๋‹ค.

*ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ์™€ ๊ฐ™์€ ๋กœ์ง์€ ์‘์šฉ ๋กœ์ง์ด๋ฏ€๋กœ ์‘์šฉ ์„œ๋น„์Šค์—์„œ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.

UML

  • ๋ชจ๋ธ ๊ธฐ๋ฐ˜ ์˜์‚ฌ์†Œํ†ต์€ *UML ์ƒ์˜ ๋‹ค์ด์–ด๊ทธ๋žจ์œผ๋กœ ํ•œ์ •๋ผ์„œ๋Š” ์•ˆ๋œ๋‹ค.

BOUNDED CONTEXT

  • ์• ๊ทธ๋ฆฌ๊ฑฐํŠธ์˜ ๋ช…์‹œ์  ๊ฒฝ๊ณ„
  • ํ•˜์œ„ ๋„๋ฉ”์ธ๋งˆ๋‹ค ๊ฐ™์€ ์šฉ์–ด๋ผ๋„ ์˜๋ฏธ๊ฐ€ ๋‹ค๋ฅด๊ณ  ๊ฐ™์€ ๋Œ€์ƒ์ด๋ผ๋„ ์ง€์นญํ•˜๋Š” ์šฉ์–ด๊ฐ€ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ํ•œ ๊ฐœ์˜ ๋ชจ๋ธ๋กœ ๋ชจ๋“  ํ•˜์œ„ ๋„๋ฉ”์ธ์„ ํ‘œํ˜„ํ•˜๋ ค๋Š” ์‹œ๋„๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋ฉฐ ํ‘œํ˜„ํ•  ์ˆ˜๋„ ์—†๋‹ค.
  • ํ•˜์œ„ ๋„๋ฉ”์ธ๋งˆ๋‹ค ์‚ฌ์šฉํ•˜๋Š” ์šฉ์–ด๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ์˜ฌ๋ฐ”๋ฅธ ๋„๋ฉ”์ธ ๋ชจ๋ธ์„ ๊ฐœ๋ฐœํ•˜๋ ค๋ฉด ํ•˜์œ„ ๋„๋ฉ”์ธ ๋งˆ๋‹ค ๋ชจ๋ธ์„ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
  • ๋ชจ๋ธ์€ ํŠน์ •ํ•œ ์ปจํ…์ŠคํŠธ(๋ฌธ๋งฅ)ํ•˜์—์„œ ์™„์ „ํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ–๋Š”๋‹ค.
  • ์ด๋ ‡๊ฒŒ ๊ตฌ๋ถ„๋˜๋Š” ๊ฒฝ๊ณ„๋ฅผ ๊ฐ–๋Š” ์ปจํ…์ŠคํŠธ๋ฅผ DDD์—์„œ๋Š” BOUNDED CONTEXT๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.
  • ๋„๋ฉ”์ธ : Bounded Context = 1:1 ์ด ์ด์ƒ์ ์ด๋‹ค. image

*์ฃผ์˜ํ•  ์ 

  • ํ•˜์œ„ ๋„๋ฉ”์ธ ๋ชจ๋ธ์ด ๋’ค์„ž์ด์ง€ ์•Š๋„๋ก ํ•˜๋Š” ๊ฒƒ
  • ๊ฐœ๋ณ„ Bounded Context Package๋กœ ๊ตฌ์„ฑํ•˜์—ฌ ํ•˜์œ„ ๋„๋ฉ”์ธ์ด ์„ž์ด์ง€ ์•Š๋„๋ก ํ•˜์—ฌ ํšจ๊ณผ๋ฅผ ๋‚ผ ์ˆ˜ ์žˆ๋‹ค.
  • ๋„๋ฉ”์ธ์ด ์„ž์ด๊ฒŒ ๋œ๋‹ค๋ฉด ๊ธฐ๋Šฅ ํ™•์žฅ์ด ์–ด๋ ต๊ฒŒ ๋˜๊ณ  ์ด๋Š” ์„œ๋น„์Šค์˜ ๊ฒฝ์Ÿ๋ ฅ์„ ๋–จ์–ด๋œจ๋ฆฌ๋Š” ์›์ธ์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

# 0720 - ์ž๋ฐ” ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•๊ณผ ์ข…๋ฅ˜

java exception handling (Checked Exception, Unchecked Exception)

# ์˜ˆ์™ธ์™€ ์—๋Ÿฌ์˜ ์˜๋ฏธ

์˜ˆ์™ธ(Exception)๋ž€ ์ž…๋ ฅ ๊ฐ’์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๊ฑฐ๋‚˜, ํ”„๋กœ๊ทธ๋žจ ์‹œํ–‰ ์ค‘์— ์ฐธ์กฐ๋œ ๊ฐ’์ด ์ž˜๋ชป๋œ ๊ฒฝ์šฐ ๋“ฑ ์ •์ƒ์ ์ธ ํ”„๋กœ๊ทธ๋žจ์˜ ํ๋ฆ„์„ ์–ด๊ธ‹๋‚˜๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. ๋˜ํ•œ, ์ž๋ฐ”์—์„œ์˜ ์˜ˆ์™ธ๋Š” ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์˜ˆ์™ธ ์ƒํ™ฉ์„ ๋ฏธ๋ฆฌ ์˜ˆ์ธกํ•˜์—ฌ ๋‹ค๋ฃฐ ์ˆ˜ ์žˆ๋‹ค.

์—๋Ÿฌ(Error)๋Š” ์‹œ์Šคํ…œ์— ๋น„์ •์ƒ์ ์ธ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ๋ฅผ ๋งํ•œ๋‹ค. ์ฃผ๋กœ ์ž๋ฐ” ๊ฐ€์ƒ ๋จธ์‹ (JVM)์„ ํ†ตํ•ด ๋ฐœ์ƒ๋˜๋ฉฐ ์˜ˆ์™ธ์™€ ๋ฐ˜๋Œ€๋กœ ์ด๋ฅผ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ์—์„œ ์žก์œผ๋ ค๊ณ  ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

package src.throwable.error;

public class ErrorExample {

    public static void gillog(String log) {
        System.out.println(log);
    }

    public static void main(String[] args) {
        try {
            gillog("Error Test");
        } catch (StackOverflowError e) {
            // ......... :(
        }
    }
}

์—๋Ÿฌ์˜ ๊ฒฝ์šฐ StackOverflowError์— ๋Œ€ํ•ด Catch๋ฅผ ํ•˜๋ ค ํ•ด๋„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์—†๋‹ค.

# ์˜ˆ์™ธ(Exception)์˜ ๊ตฌ๋ถ„

image

  • RuntimeException์„ ์ƒ์†ํ•˜์ง€ ์•Š๋Š” ํด๋ž˜์Šค๋Š” Checked Exception๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • RuntimeException์„ ์ƒ์†ํ•˜๋Š” ํด๋ž˜์Šค๋Š” Unchecked Exception์œผ๋กœ ๋ถ„๋ฅ˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

# ์—๋Ÿฌ(Error)์˜ ์ข…๋ฅ˜

์—๋Ÿฌ์˜ ์ข…๋ฅ˜์—๋Š” LinkageError, ThreadDeath, AssertionError, VirtualMachineError๊ฐ€ ์žˆ๋‹ค.

  • LinkageError : ์–ด๋–ค ํด๋ž˜์Šค๊ฐ€ ๋‹ค๋ฅธ ํด๋ž˜์Šค์— ๋Œ€ํ•œ ์ข…์†์„ฑ์ด ์žˆ๋Š” ์ƒํ™ฉ์—์„œ, ํ›„์ž ํด๋ž˜์Šค๊ฐ€ ์ด์ „ ํด๋ž˜์Šค๋ฅผ ์ปดํŒŒ์ผ ํ•œ ํ›„ ๋น„ํ˜ธํ™˜์ ์œผ๋กœ ๋ณ€๊ฒฝ๋œ ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ
  • ThreadDeath : ๋” ์ด์ƒ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š” Thread์— ๋Œ€ํ•ด Thread.stop() method๊ฐ€ ํ˜ธ์ถœ ๋  ๋•Œ, ์‚ญ์ œ๋˜๋Š” Thread์—์„œ Instance๊ฐ€ throw ๋˜๋ฉฐ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ
  • AssertionError : Assertion์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ. (ํ•ด๋‹น ์ง€์ ์—์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋ฐ˜๋“œ์‹œ ์ฐธ์ด์–ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์‚ฌํ•ญ์„ ํ‘œํ˜„ํ•œ ๋…ผ๋ฆฌ์‹์„ Assertion์ด๋ผ ํ•œ๋‹ค.)
  • VirtualMachine : JVM์ด ์†์ƒ๋˜์—ˆ๊ฑฐ๋‚˜ ๊ณ„์† ์ž‘๋™ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๊ฐ€ ๋ถ€์กฑํ• ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์—๋Ÿฌ

# CheckedException๊ณผ UncheckedException

CheckedException

  • ๋ฐ˜๋“œ์‹œ ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋ฉฐ, ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ์˜ˆ์™ธ ๋ฐœ์ƒ์ด ํ™•์ธ๋œ๋‹ค.
  • ์—๋Ÿฌ์™€ RuntimeException์„ ์ƒ์†ํ•˜์ง€ ์•Š์€ ์˜ˆ์™ธ๋“ค์„ ๋ชจ๋‘ ํฌํ•จํ•œ๋‹ค.
  • Error, FileNotFoundException, ClassNotFoundException ๋“ฑ์ด ๋Œ€ํ‘œ์ ์ด๋‹ค.
  • ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ CheckedException์€ ํŠธ๋žœ์ ์…˜ ์ฒ˜๋ฆฌ ์‹œ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•ด๋„ ๋กค๋ฐฑํ•˜์ง€ ์•Š๋Š”๋‹ค.

UncheckedException

  • ๋ช…์‹œ์ ์œผ๋กœ ์˜ˆ์™ธ ์ฒ˜๋ฆฌํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฉฐ, ๋Ÿฐํƒ€์ž„ ์‹œ์ ์—์„œ ์˜ˆ์™ธ ๋ฐœ์ƒ์ด ํ™•์ธ๋œ๋‹ค.
  • RuntimeException์„ ์ƒ์†๋ฐ›๋Š” ์˜ˆ์™ธ๋“ค์„ ํฌํ•จํ•œ๋‹ค.
  • NullPointerException, ClassCastException ๋“ฑ์ด ๋Œ€ํ‘œ์ ์ด๋‹ค.
  • ์Šคํ”„๋ง ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ UncheckedException์€ ํŠธ๋žœ์ ์…˜ ์ฒ˜๋ฆฌ์‹œ์— ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒฝ์šฐ ๋กค๋ฐฑ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.

์ˆœ์ˆ˜ ์ž๋ฐ” ๊ด€์ ์—์„œ์˜ UncheckedException ์ƒํ™ฉ์—์„œ๋Š” ๋กค๋ฐฑ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

# ์˜ˆ์™ธ์ฒ˜๋ฆฌ ๋ฐฉ๋ฒ•

์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฐฉ๋ฒ•์—๋Š” ๋ณต๊ตฌ, ํšŒํ”ผ, ์ „ํ™˜์ด ์žˆ๋‹ค.

์˜ˆ์™ธ ๋ณต๊ตฌ

  • ์˜ˆ์™ธ ์ƒํ™ฉ์„ ํŒŒ์•…ํ•˜๊ณ  ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์„œ ์ •์ƒ ์ƒํƒœ๋กœ ๋Œ๋ ค๋†“๋Š” ๋ฐฉ๋ฒ•
  • ์˜ˆ์™ธ๋ฅผ ์žก์•„์„œ ์ผ์ • ์‹œ๊ฐ„, ์กฐ๊ฑด๋งŒํผ ๋Œ€๊ธฐํ•˜๊ณ  ๋‹ค์‹œ ์žฌ์‹œ๋„๋ฅผ ๋ฐ˜๋ณตํ•œ๋‹ค.
  • ์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋„˜๊ธฐ๊ฒŒ ๋˜๋Š” ๊ฒฝ์šฐ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
final int MAX_RETRY = 100;
public Object someMethod() {
    int maxRetry = MAX_RETRY;
    while(maxRetry > 0) {
        try {
            ...
        } catch(SomeException e) {
            // ๋กœ๊ทธ ์ถœ๋ ฅ. ์ •ํ•ด์ง„ ์‹œ๊ฐ„๋งŒํผ ๋Œ€๊ธฐํ•œ๋‹ค.
        } finally {
            // ๋ฆฌ์†Œ์Šค ๋ฐ˜๋‚ฉ ๋ฐ ์ •๋ฆฌ ์ž‘์—…
        }
    }
    // ์ตœ๋Œ€ ์žฌ์‹œ๋„ ํšŸ์ˆ˜๋ฅผ ๋„˜๊ธฐ๋ฉด ์ง์ ‘ ์˜ˆ์™ธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.
    throw new RetryFailedException();
}

์˜ˆ์™ธ์ฒ˜๋ฆฌ ํšŒํ”ผ

  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ์ง์ ‘ ๋‹ด๋‹นํ•˜์ง€ ์•Š๊ณ  ํ˜ธ์ถœํ•œ ์ชฝ์œผ๋กœ ๋˜์ ธ ํšŒํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•
  • ๊ทธ๋ž˜๋„ ์˜ˆ์™ธ ์ฒ˜๋ฆฌ์˜ ํ•„์š”์„ฑ์ด ์žˆ๋‹ค๋ฉด ์–ด๋Š ์ •๋„๋Š” ์ฒ˜๋ฆฌํ•˜๊ณ  ๋˜์ง€๋Š” ๊ฒƒ์ด ์ข‹๋‹ค.
  • ๊ธด๋ฐ€ํ•˜๊ฒŒ ์—ญํ• ์„ ๋ถ„๋‹ดํ•˜๊ณ  ์žˆ๋Š” ๊ด€๊ณ„๊นŒ ์•„๋‹ˆ๋ผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๊ทธ๋ƒฅ ๋˜์ง€๋Š” ๊ฒƒ์€ ๋ฌด์ฑ…์ž„ํ•˜๋‹ค.
// ์˜ˆ์‹œ 1
public void add() throws SQLException {
    // ...์ƒ๋žต
}

// ์˜ˆ์‹œ 2 
public void add() throws SQLException {
    try {
        // ... ์ƒ๋žต
    } catch(SQLException e) {
        // ๋กœ๊ทธ๋ฅผ ์ถœ๋ ฅํ•˜๊ณ  ๋‹ค์‹œ ๋‚ ๋ฆฐ๋‹ค!
        throw e;
    }
}

์˜ˆ์™ธ ์ „ํ™˜

  • ์˜ˆ์™ธ ํšŒํ”ผ์™€ ๋น„์Šทํ•˜๊ฒŒ ๋ฉ”์„œ๋“œ ๋ฐ–์œผ๋กœ ์˜ˆ์™ธ๋ฅผ ๋˜์ง€์ง€๋งŒ, ๊ทธ๋ƒฅ ๋˜์ง€์ง€ ์•Š๊ณ  ์ ์ ˆํ•œ ์˜ˆ์™ธ๋กœ ์ „ํ™˜ํ•ด์„œ ๋„˜๊ธฐ๋Š” ๋ฐฉ๋ฒ•
  • ์กฐ๊ธˆ ๋” ๋ช…ํ™•ํ•œ ์˜๋ฏธ๋กœ ์ „๋‹ฌ๋˜๊ธฐ ์œ„ํ•ด ์ ํ•ฉํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„ ์˜ˆ์™ธ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.
  • ์˜ˆ์™ธ ์ฒ˜๋ฆฌ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ํฌ์žฅ(wrap) ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
// ์กฐ๊ธˆ ๋” ๋ช…ํ™•ํ•œ ์˜ˆ์™ธ๋กœ ๋˜์ง„๋‹ค.
public void add(User user) throws DuplicateUserIdException, SQLException {
    try {
        // ...์ƒ๋žต
    } catch(SQLException e) {
        if(e.getErrorCode() == MysqlErrorNumbers.ER_DUP_ENTRY) {
            throw DuplicateUserIdException();
        }
        else throw e;
    }
}

// ์˜ˆ์™ธ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ํฌ์žฅํ•œ๋‹ค.
public void someMethod() {
    try {
        // ...์ƒ๋žต
    }
    catch(NamingException ne) {
        throw new EJBException(ne);
        }
    catch(SQLException se) {
        throw new EJBException(se);
        }
    catch(RemoteException re) {
        throw new EJBException(re);
        }
}

# 0721 - ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ(Dynamic Test)

# ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ(Dynamic Test)๋ž€?

๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ ์ „์— ์ƒ๋Œ€๋˜๋Š” ๊ฐœ๋…์ธ ์ •์  ํ…Œ์ŠคํŠธ์™€ ํ•จ๊ป˜ ๊ฐœ๋…์„ ๋น„๊ตํ•ด์„œ ํŠน์ง•์„ ํ•œ๋ฒˆ ์‚ดํŽด๋ณด์ž.

JUnit์„ ์ด์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ๋ณดํ†ต @Test๋ผ๋Š” ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉ ํ•ด์„œ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด์™€ ๊ฐ™์€ ๋ฐฉ์‹์˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ •์  ํ…Œ์ŠคํŠธ๋ผ๊ณ  ํ•œ๋‹ค. ์ •์  ํ…Œ์ŠคํŠธ๋Š” ์ปดํŒŒ์ผ ์‹œ์ ์— ์ฝ”๋“œ๊ฐ€ ์ง€์ •๋œ๋‹ค๋Š” ํŠน์ง•์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. ๊ฐ€์ •์€ ๋™์ ์ธ ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ํ…Œ์ŠคํŠธ ํ˜•ํƒœ๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ, ๊ทธ ํ‘œํ˜„์ด ์ปดํŒŒ์ผ ์‹œ์ ์— ์ œํ•œ๋œ๋‹ค๋Š” ํ•œ๊ณ„๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

์ด์— ๋น„ํ•ด ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ๋Š” ๋Ÿฐํƒ€์ž„ ๋™์•ˆ์— ํ…Œ์ŠคํŠธ๊ฐ€ ์ƒ์„ฑ๋˜๊ณ  ์ˆ˜ํ–‰๋œ๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋กœ๊ทธ๋žจ์ด ์ˆ˜ํ–‰๋˜๋Š” ๋„์ค‘์—๋„ ๋™์ž‘์„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋Š” ํŠน์ง•์ด ์žˆ๋‹ค. ์ด ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ๋Š” @Test์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , @TestFactory ์–ด๋…ธํ…Œ์ด์…˜์„ ํ†ตํ•ด ํŒฉํ† ๋ฆฌ ๋ฉ”์„œ๋“œ๋กœ ์ƒ์„ฑ๋œ๋‹ค.

# ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ์˜ ์žฅ์ 

  1. ์œ ์—ฐ์„ฑ

๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฐ€์žฅ ํฐ ์ด์œ ๋Š” ์•„๋งˆ๋„ ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์œ ์—ฐ์„ฑ์„ ๊ผฝ์„ ์ˆ˜ ์žˆ๋‹ค.

@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void isUnderTenTest(int number) {
  boolean result = isUnderTen(number);
  
  assertThat(result).isTrue();
}
@TestFactory
Stream<DynamicTest> isUnderTenTest() {
  List<Integer> numbers = getNumberFromDatabase() // 1, 2, 3, 4, 5, 6, 7, 8, 9

  return numbers.stream()
      .map(num -> dynamicTest(num + "๊ฐ€ 10๋ฏธ๋งŒ์ธ์ง€ ๊ฒ€์‚ฌ",
          () -> {
               boolean result = isUnderTen(num);
               assertThat(result).isTrue();
          }
    ));
}

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

  1. ๊ฐ€๋…์„ฑ

์ธ์ˆ˜ํ…Œ์ŠคํŠธ ์ฒ˜๋Ÿผ ํ•˜๋‚˜์˜ ๋ฉ”์„œ๋“œ ์•ˆ์—์„œ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ž‘์„ฑํ•ด์•ผํ•  ๊ฒฝ์šฐ

/*
Feature: ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ฆฌ

  Scenario: ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ๊ด€๋ฆฌํ•œ๋‹ค.
    When ์ง€ํ•˜์ฒ  ๋…ธ์„  n๊ฐœ ์ถ”๊ฐ€ ์š”์ฒญ์„ ํ•œ๋‹ค.
    Then ์ง€ํ•˜์ฒ  ๋…ธ์„ ์ด ์ถ”๊ฐ€ ๋˜์—ˆ๋‹ค.
    
    When ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ์„ ํ•œ๋‹ค.
    Then ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก์„ ์‘๋‹ต ๋ฐ›๋Š”๋‹ค.
    And ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก์€ n๊ฐœ์ด๋‹ค.
    
    When ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ˆ˜์ • ์š”์ฒญ์„ ํ•œ๋‹ค.
    Then ์ง€ํ•˜์ฒ  ๋…ธ์„ ์ด ์ˆ˜์ • ๋˜์—ˆ๋‹ค.

    When ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ œ๊ฑฐ ์š”์ฒญ์„ ํ•œ๋‹ค.
    Then ์ง€ํ•˜์ฒ  ๋…ธ์„ ์ด ์ œ๊ฑฐ ๋˜์—ˆ๋‹ค.
    
    When ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก ์กฐํšŒ ์š”์ฒญ์„ ํ•œ๋‹ค.
    Then ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก์„ ์‘๋‹ต ๋ฐ›๋Š”๋‹ค.
    And ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก์€ n-1๊ฐœ์ด๋‹ค.
 */
@DisplayName("์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ๊ด€๋ฆฌํ•œ๋‹ค.")
@Test
void manageLine() {
    // when
    createLine("์‹ ๋ถ„๋‹น์„ ");
    createLine("1ํ˜ธ์„ ");
    createLine("2ํ˜ธ์„ ");
    createLine("3ํ˜ธ์„ ");
    // then
    List<LineResponse> lines = getLines();
    assertThat(lines.size()).isEqualTo(4);
  
    // when
    LineResponse line = getLine(lines.get(0).getId());
    //then
    assertThat(line.getId()).isNotNull();
    assertThat(line.getName()).isNotNull();
    assertThat(line.getStartTime()).isNotNull();
    assertThat(line.getEndTime()).isNotNull();
    assertThat(line.getIntervalTime()).isNotNull();
  
    ...
}
@DisplayName("๋…ธ์„ ์„ ๊ด€๋ฆฌํ•œ๋‹ค.")
@TestFactory
Stream<DynamicTest> dynamicTestsFromCollection() {
    return Stream.of(
        dynamicTest("๋…ธ์„ ์„ ๋งŒ๋“œ๋Š” ์š”์ฒญ์œผ๋กœ ์ƒˆ๋กœ์šด ๋…ธ์„ ์„ ์ƒ์„ฑํ•œ๋‹ค.", () -> {
            // when
            createLine("์‹ ๋ถ„๋‹น์„ ");
            createLine("1ํ˜ธ์„ ");
            createLine("2ํ˜ธ์„ ");
            createLine("3ํ˜ธ์„ ");

            // then
            List<LineResponse> lines = getLines();
            assertThat(lines.size()).isEqualTo(4);
        }),
    
        dynamicTest("์ƒ์„ฑ๋œ ๋…ธ์„  ๋ชฉ๋ก์„ ๋ถˆ๋Ÿฌ์˜จ๋‹ค.", () -> {
            // given
            List<LineResponse> lines = getLines();
 
            // when  
            LineResponse line = lines.get(0);
 
            // then
            assertThat(line.getId()).isNotNull();
            assertThat(line.getName()).isNotNull();
            assertThat(line.getStartTime()).isNotNull();
            assertThat(line.getEndTime()).isNotNull();
            assertThat(line.getIntervalTime()).isNotNull();
        }),
      
        ...
    );
}

# ๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ ์ž‘์„ฑ๋ฐฅ๋ฒ•

# 1. @TestFactory ์–ด๋…ธํ…Œ์ด์…˜ ์‚ฌ์šฉ

  • @TestFactory ๋ฉ”์†Œ๋“œ๋Š” ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์ƒ์‚ฐํ•˜๋Š” ํŒฉํ† ๋ฆฌ์ด๋‹ค.
  • @TestFactory ๋ฉ”์„œ๋“œ๋Š” private ๋˜๋Š” static์ด๋ฉด ์•ˆ๋œ๋‹ค.

# 2. ์ปฌ๋ ‰์…˜ ๋ฐ˜ํ™˜

  • @TestFactory ๋ฉ”์„œ๋“œ๋Š” Stream, Collection, Iterable ๋˜๋Š” Iterato ๋ฅผ return ํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด, JUnitException์„ ๋ฐœ์ƒ ์‹œํ‚จ๋‹ค.
  • ํ…Œ์ŠคํŠธ ์ˆ˜๋Š” ๋™์ ์ด๋ฉฐ, ArrayList ํฌ๊ธฐ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.

# 3. ์ฒซ๋ฒˆ์งธ ์ธ์ž๋กœ ํ…Œ์ŠคํŠธ ์ด๋ฆ„ ์ž‘์„ฑ

  • dynamicTest ๋Š” ํ…Œ์ŠคํŠธ ์ด๋ฆ„๊ณผ, ์‹คํ–‰ ํ•จ์ˆ˜ ๋‘ ์š”์†Œ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๋‹ค
  • ๊ทธ ๋งŒํผ ํ…Œ์ŠคํŠธ ์ด๋ฆ„์„ ์ž˜ ์ž‘์„ฑํ•ด์ฃผ๋Š” ๊ฒƒ์ด ๊ฐ€๋…์„ฑ์„ ๋†’์ด๋Š” ์ธก๋ฉด์—์„œ๋„ ์ค‘์š”ํ•˜๋‹ค
@TestFactory
Stream<DynamicTest> exampleDynamicTest() {
    return Stream.of(
        dynamicTest("First Dynamic Test", () -> {
            // test code
        }),
        dynamicTest("Second Dynamic test", () -> {
            // test code
        })
    );
}

# ์ฃผ์˜ ์‚ฌํ•ญ

๋‹ค์ด๋‚˜๋ฏน ํ…Œ์ŠคํŠธ๋Š” JUnit์˜ ์ƒ๋ช…์ฃผ๊ธฐ ์ฝœ๋ฐฑํ•จ์ˆ˜๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋Ÿฌ๋ฏ€๋กœ @BeforeEach๋‚˜ @AfterEach์™€ ๊ฐ™์€ ํ…Œ์ŠคํŠธ ์ƒ๋ช… ์ฃผ๊ธฐ์™€ ๊ด€๋ จ๋œ ์š”์†Œ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค


# 0722 - AssertJ ํ•„์ˆ˜๊ธฐ๋Šฅ์ •๋ฆฌ

https://joel-costigliola.github.io/assertj/assertj-core-features-highlight.html

# AssertJ๋ž€?

์ž๋ฐ” ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด ์ข€ ๋” ํ’๋ถ€ํ•œ ๋ฌธ๋ฒ•์„ ์ œ๊ณตํ•˜๊ณ  ๋ฉ”์„œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ์ง๊ด€์ ์ธ ํ…Œ์ŠคํŠธ ํ๋ฆ„์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ฐœ๋ฐœ๋œ ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

์˜ˆ์ œ

@Test
  public void split() {
    String[] values = "1,2".split(",");
    assertThat(values).containsExactly("1", "2");

    values = "1".split(",");
    assertThat(values).containsExactly("1");
  }

JUnit5์˜ ๊ฒฝ์šฐ, assertEquals(expected, actual)๊ณผ ๊ฐ™์ด ๋‘ ๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›์•„์„œ ๋น„๊ต๋ฅผ ํ•˜์ง€๋งŒ, AssertJ๋Š” ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์„ ํ†ตํ•ด ๊ฐ€๋…์„ฑ์„ ๋†’์—ฌ์ฃผ๋Š” ํŠน์ง•์ด ์žˆ์Šต๋‹ˆ๋‹ค. assertEquals()๋Š” ์™ผ์ชฝ์ด expected์ธ์ง€ actual์ธ์ง€ ํ˜ผ๋™๋  ์—ฌ์ง€๊ฐ€ ์žˆ์ง€๋งŒ, assertThat()์€ actual ์ธ์ž ํ•˜๋‚˜๋งŒ ์š”๊ตฌํ•˜๊ณ  ๊ทธ ๋’ค๋กœ ๋ฉ”์†Œ๋“œ ์ฒด์ด๋‹์„ ํ•˜๋ฏ€๋กœ acutal๊ณผ expected๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„์ง€์–ด์ค€๋‹ค๋Š” ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

# Test Fail Message

JUnit5์˜ ๊ฒฝ์šฐ, ๋งˆ์ง€๋ง‰ ์ธ์ž๊ฐ’์— ์„ ํƒ์ ์œผ๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋„ฃ์–ด์คŒ์œผ๋กœ์จ ํ…Œ์ŠคํŠธ ์‹คํŒจ ๋ฉ”์‹œ์ง€๋ฅผ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, AssertJ์—์„œ๋Š” as()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋‹จ, assertion์ด ์ˆ˜ํ–‰๋˜๊ธฐ ์ „์— ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

TolkienCharacter frodo = new TolkienCharacter("Frodo", 33, HOBBIT);
 // failing assertion, remember to call as() before the assertion, not after !
 assertThat(frodo.getAge()).as("check %s's age", frodo.getName()).isEqualTo(100);

๋งŒ์•ฝ, frodo์˜ ๋‚˜์ด๊ฐ€ 100๊ณผ ๊ฐ™์ง€ ์•Š๋‹ค๋ฉด "check 33's age"์™€ ๊ฐ™์€ ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

# Filtering assertions

import static org.assertj.core.api.Assertions.in;
import static org.assertj.core.api.Assertions.not;
import static org.assertj.core.api.Assertions.notIn;
...

// filters use introspection to get property/field values
assertThat(fellowshipOfTheRing).filteredOn("race", HOBBIT)
                               .containsOnly(sam, frodo, pippin, merry);

// nested properties are supported
assertThat(fellowshipOfTheRing).filteredOn("race.name", "Man")
                               .containsOnly(aragorn, boromir);

// you can apply different comparison
assertThat(fellowshipOfTheRing).filteredOn("race", notIn(HOBBIT, MAN))
                               .containsOnly(gandalf, gimli, legolas);

assertThat(fellowshipOfTheRing).filteredOn("race", in(MAIA, MAN))
                               .containsOnly(gandalf, boromir, aragorn);

assertThat(fellowshipOfTheRing).filteredOn("race", not(HOBBIT))
                               .containsOnly(gandalf, boromir, aragorn, gimli, legolas);

// you can chain multiple filter criteria
assertThat(fellowshipOfTheRing).filteredOn("race", MAN)
                               .filteredOn("name", not("Boromir"))
                               .containsOnly(aragorn);

๋žŒ๋‹ค์‹์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•„ํ„ฐ๋ง๋„ ๊ฐ€๋Šฅํ•˜๋‹ค

# Assertions on extracted properties/fields of iterable/array elements

// extract the names ...
List<String> names = new ArrayList<String>();
for (TolkienCharacter tolkienCharacter : fellowshipOfTheRing) {
  names.add(tolkienCharacter.getName());
}
// ... and finally assert something
assertThat(names).contains("Boromir", "Gandalf", "Frodo", "Legolas");
  • extracing()
// ๋‹จ์ผํ•„๋“œ๊ฒ€์‚ฌ
assertThat(fellowshipOfTheRing).extracting("name", String.class)
                               .contains("Boromir", "Gandalf", "Frodo", "Legolas")
                               .doesNotContain("Sauron", "Elrond");
// ์—ฌ๋Ÿฌํ•„๋“œ๊ฒ€์‚ฌ
import static org.assertj.core.api.Assertions.tuple;

// extracting name, age and and race.name nested property
assertThat(fellowshipOfTheRing).extracting("name", "age", "race.name")
                               .contains(tuple("Boromir", 37, "Man"),
                                         tuple("Sam", 38, "Hobbit"),
                                         tuple("Legolas", 1000, "Elf"));

# Soft assertions

@Test
public void host_dinner_party_where_nobody_dies() {
   Mansion mansion = new Mansion();
   mansion.hostPotentiallyMurderousDinnerParty();
   // use SoftAssertions instead of direct assertThat methods
   SoftAssertions softly = new SoftAssertions();
   softly.assertThat(mansion.guests()).as("Living Guests").isEqualTo(7);
   softly.assertThat(mansion.kitchen()).as("Kitchen").isEqualTo("clean");
   softly.assertThat(mansion.library()).as("Library").isEqualTo("clean");
   softly.assertThat(mansion.revolverAmmo()).as("Revolver Ammo").isEqualTo(6);
   softly.assertThat(mansion.candlestick()).as("Candlestick").isEqualTo("pristine");
   softly.assertThat(mansion.colonel()).as("Colonel").isEqualTo("well kempt");
   softly.assertThat(mansion.professor()).as("Professor").isEqualTo("well kempt");
   // Don't forget to call SoftAssertions global verification !
   softly.assertAll();
}

๋ชจ๋“  assertions์„ ์‹คํ–‰ํ•œ ํ›„ ์‹คํŒจ ๋‚ด์—ญ์„ ํ™•์ธ

# Exception assertions

@ParameterizedTest
  @ValueSource(strings = {"", "spring"})
  @DisplayName("์ด๋ฆ„ ๊ธธ์ด๊ฐ€ 0 ์ดํ•˜ ๋˜๋Š” 5 ์ด์ƒ์ผ ๋•Œ ์—๋Ÿฌ ํ™•์ธ")
  void car_name_exception(String name) {
    assertThatThrownBy(() -> new Car(name))
        .isInstanceOf(IllegalStateException.class)
        .hasMessageContaining("์ด๋ฆ„ ๊ธธ์ด๋Š” 0์ดํ•˜ ๋˜๋Š” 5์ด์ƒ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.");
  }

# 0723 - ์ž๋ฐ” ์ž๋ฃŒ๊ตฌ์กฐ

์ž๋ฐ” ์ž๋ฃŒ๊ตฌ์กฐ ๊ตฌ์กฐ ๋ฐ ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ

# ํ(Queue)

์ˆœ์„œ๋Œ€๋กœ ์ฒ˜๋ฆฌ๋˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ(FIFO : First In First Out)

  • Enqueue : ํ ๋งจ ๋’ค์— ๋ฐ์ดํ„ฐ ์ถ”๊ฐ€
  • Dequeue : ํ ๋งจ์•ž์ชฝ์˜ ๋ฐ์ดํ„ฐ ์‚ญ์ œ

# Queue ํŠน์ง•

  • FIFO(First In First Out) ๊ตฌ์กฐ
  • ํ๋Š” ํ•œ ์ชฝ ๋์€ ํ”„๋ŸฐํŠธ(front)๋กœ ์ •ํ•˜์—ฌ ์‚ญ์ œ ์—ฐ์‚ฐ๋งŒ ์ˆ˜ํ–‰ํ•จ
  • ๋‹ค๋ฅธ ํ•œ ์ชฝ ๋์€ ๋ฆฌ์–ด(rear)๋กœ ์ •ํ•˜์—ฌ ์‚ฝ์ž… ์—ฐ์‚ฐ๋งŒ ์ˆ˜ํ–‰ํ•จ
  • ๊ทธ๋ž˜ํ”„์˜ ๋„“์ด ์šฐ์„  ํƒ์ƒ‰(BFS)์—์„œ ์‚ฌ์šฉ
  • ์ปดํ“จํ„ฐ ๋ฒ„ํผ์—์„œ ์ฃผ๋กœ ์‚ฌ์šฉ, ๋งˆ๊ตฌ ์ž…๋ ฅ์ด ๋˜์—ˆ์œผ๋‚˜ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜์ง€ ๋ชปํ•  ๋•Œ, ๋ฒ„ํผ(ํ)๋ฅผ ๋งŒ๋“ค์–ด ๋Œ€๊ธฐ

# Queue ์‚ฌ์šฉ๋ฒ•

  • ์„ ์–ธ
Queue<Integer> intQueue = new LinkedList<>();
Queue<String> stringQueue = new LinkedList<>();
  • ๊ฐ’ ์ถ”๊ฐ€
Queue<Integer> queue = new LinkedList<>();
queue.add(1);
queue.add(2);
queue.offer(3);
  • ๊ฐ’ ์‚ญ์ œ
Queue<Integer> queue = new LinkedList<>(List.of(1, 2, 3));

queue.poll();   // ์ฒซ๋ฒˆ์งธ ๊ฐ’ ๋ฐ˜ํ™˜ ๋ฐ ์ œ๊ฑฐ ๋น„์–ด์žˆ์„์‹œ null
queue.remove(); // ์ฒซ๋ฒˆ์งธ ๊ฐ’ ์ œ๊ฑฐ
queue.clear();  // ์ดˆ๊ธฐํ™”
  • ์ฒซ๋ฒˆ์งธ ๊ฐ’ ์ถœ๋ ฅ
Queue<Integer> queue = new LinkedList<>(List.of(1, 2, 3));

queue.peek();   // ์ถœ๋ ฅ

# ์Šคํƒ(Stack)

๋ฐ์ดํ„ฐ๋ฅผ ์Œ“์•„์˜ฌ๋ฆฌ๋Š” ์ž๋ฃŒ๊ตฌ์กฐ(Last In First Out)

# ํŠน์ง•

  • ๋จผ์ € ๋“ค์–ด๊ฐ„ ์ž๋ฃŒ๊ฐ€ ๋‚˜์ค‘์— ๋‚˜์˜ด LIFO(Last In First Out)
  • ์‹œ์Šคํ…œ ํ•ดํ‚น์—์„œ ๋ฒ„ํผ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•œ ๊ณต๊ฒฉ์„ ํ•  ๋•Œ ์Šคํƒ๋ฉ”๋ชจ๋ฆฌ์˜ ์˜์—ญ์—์„œ ํ•จ
  • ์ธํ„ฐ๋ŸฝํŠธ ์ฒ˜๋ฆฌ, ์ˆ˜์‹์˜ ๊ณ„์‚ฐ, ์„œ๋ธŒ๋ฃจํ‹ด์˜ ๋ณต๊ท€ ๋ฒˆ์ง€ ์ €์žฅ ๋“ฑ์— ์“ฐ์ž„
  • ๊ทธ๋ž˜ํ”„์˜ ๊นŠ์ด ์šฐ์„  ํƒ์ƒ‰(DFS)์—์„œ ์‚ฌ์šฉ
  • ์žฌ๊ท€์ (Recursion) ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ ํ•  ๋•Œ ์‚ฌ์šฉ

# stack ์‚ฌ์šฉ๋ฒ•

  • ์„ ์–ธ
Stack<Integer> stack = new Stack<>();
  • ๊ฐ’ ์ถ”๊ฐ€
Stack<Integer> stack = new Stack<>();

stack.push(1);
stack.push(2);
stack.push(3);
  • ๊ฐ’ ์‚ญ์ œ
Stack<Integer> stack = new Stack<>();

stack.push(1);
stack.push(2);
stack.push(3);

stack.pop();
stack.clear();
  • ์ƒ๋‹จ ๊ฐ’ ์ถœ๋ ฅ
Stack<Integer> stack = new Stack<>();

stack.push(1);
stack.push(2);
stack.push(3);

stack.peek();
Last update: September 13, 2022 21:44
Contributors: ahnjs