0718 ~ 0724
# 0718 ~ 0724
# 0719 - ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ(Domain Driven Development) ์ดํด
# ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ ๋์ ๋ฐฐ๊ฒฝ
Before
# ๊ธฐ์กด ๊ฐ๋ฐ
- ๋ฐ์ดํฐ์ ์ข ์์ ์ธ ์ ํ๋ฆฌ์ผ์ด์
- ๋ชจ๋ธ๋ง๊ณผ ๊ฐ๋ฐ๊ณผ์ ๋ถ์ผ์น ๋ฐ์
After
# ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ
- ์ด๋ฐ ๋ถ์ผ์น๋ฅผ ํด์ํ๊ธฐ ์ํ ๋ ธ๋ ฅ ์ค ํ๋๊ฐ ๋ฐ๋ก DDD
- ๊ณตํต์ ์ธ์ด(*์ ๋น์ฟผํฐ์ค ์ธ์ด)๋ฅผ ์ฌ์ฉํ์ฌ ๋๋ฉ์ธ๊ณผ ๊ตฌํ์ ์ถฉ๋ถํ ๋ง์กฑํ๋ ๋ชจ๋ธ์ ๋ง๋ ๋ค.
- *์ ๋น์ฟผํฐ์ค ์ธ์ด๋ฅผ ์ฌ์ฉํ์ฌ ์ฉ์ด์ฌ์ ์ ๋ง๋ ๋ค. (์) ํํฐ | hunter | ๋ณด๋ฌผ์ ์ฐพ๋ ์ฌ๋ฅ๊พผ
- '์ค๊ณ'์ '๊ตฌํ'์ ๊ณ์๋ ์์ ๊ณผ์ ์ ๊ฑฐ์น๋ค. (๋ฐ๋ณต ์์ )
*์ ๋น์ฟผํฐ์ค ์ธ์ด(๋ณดํธ ์ธ์ด)๋? ๋๋ฉ์ธ ์ดํ๋ฅผ ์ดํด๊ด๋ฆฌ์๋ค์ด ๊ณตํต์ ์ผ๋ก ์๋ฏธ๋ฅผ ์ดํดํ ์ ์๋๋ก ์ ์ํ๋ ๊ฒ
ํจ๊ณผ์ ์ธ ๋ชจ๋ธ๋ง
- ์ฌ์ฉ์์ ๊ฐ๋ฐ์๋ ๋์ผํ ์ธ์ด๋ก ์ด์ผ๊ธฐ ํ๋๊ฐ?
- ํด๋น ์ธ์ด๊ฐ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ํํด์ผ ํ ๋ด์ฉ์ ๊ดํ ๋ ผ์๋ฅผ ์ด๋์ด๊ฐ ๋งํผ ํ์ฑํ๊ฐ?
๋๋ฉ์ธ
- ์ผ๋ฐ์ ์ธ ์๊ตฌํ์, ์ ๋ฌธ ์ฉ์ด, ๊ทธ๋ฆฌ๊ณ ์ปดํจํฐ ํ๋ก๊ทธ๋๋ฐ ๋ถ์ผ์์ ๋ฌธ์ ๋ฅผ ํ๊ธฐ ์ํด ์ค๊ณ๋ ์ด๋ค ์ํํธ์จ์ด ํ๋ก๊ทธ๋จ์ ๋ํ ๊ธฐ๋ฅ์ฑ์ ์ ์ํ๋ ์ฐ๊ตฌ์ ํ ์์ญ
- ์ํํธ์จ์ด๋ก ํด๊ฒฐํ๊ณ ์ ํ๋ ๋ฌธ์ ์์ญ (์) ๊ด๊ณ ํ์ฌ์ ๊ด๊ณ ์ ๊ด๋ จ๋ ์ง์ = ๋๋ฉ์ธ
๋๋ฉ์ธ ๋ชจ๋ธ
- ํน์ ๋๋ฉ์ธ์ ๊ฐ๋ ์ ์ผ๋ก ํํํ ๊ฒ
- ๋๋ฉ์ธ ๋ชจ๋ธ์ ์ฌ์ฉํ๋ฉด ์ฌ๋ฌ ๊ด๊ณ์๋ค(๊ฐ๋ฐ์, ๊ธฐํ์, ์ฌ์ฉ์ ๋ฑ)์ด ๋์ผํ ๋ชจ์ต์ผ๋ก ๋๋ฉ์ธ์ ์ดํดํ๊ณ ๋๋ฉ์ธ ์ง์์ ๊ณต์ ํ๋๋ฐ ๋์์ด ๋๋ค.
- ๋ชจ๋ธ์ ๊ฐ ๊ตฌ์ฑ ์์๋ ํน์ ๋๋ฉ์ธ์ ํ์ ํ ๋ ๋น๋ก์ ์๋ฏธ๊ฐ ์์ ํด์ง๊ธฐ ๋๋ฌธ์, ๊ฐ ํ์ ๋๋ฉ์ธ๋ง๋ค ๋ณ๋๋ก ๋ชจ๋ธ์ ๋ง๋ค์ด์ผ ํ๋ค.
(์) ์ฟ ํก์์ ์ํ์ ์ฃผ๋ฌธํ ๋ ํ์ํ ๊ฒ : ๊ณ ๊ฐ์ ์ฃผ๋ฌธ์ ๋ชจ๋ธ, ์ํ ์ ๋ณด์ ์ํ ๋ชจ๋ธ
# ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ ์ํคํ ์ฒ ๊ฐ์
*ํต์ฌ ๋ก์ง(๋น์ฆ๋์ค ๋ก์ง)์ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ด์์ ์ฌ์ฉํ๋ค.
๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ค ๊ฐ์ ์์ญ
*์๋๋ก ๋ด๋ ค๊ฐ์๋ก ์์กด์ฑ์ด ๊ฐํด์ง๋ค.
- PRESENTATION LAYER : ํํ ์์ญ ๋๋ UI์์ญ. ์ฌ์ฉ์์ ์์ฒญ์ ๋ฐ์ ์์ฉ ์์ญ์ ์ ๋ฌํ๊ณ , ์์ฉ ์์ญ์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๋ ์ญํ ์ ํ๋ค. (Controller ์์ญ, DispatcherServlet์๊ฒ ์์ฒญ๊ณผ ์๋ต์ ์ ๋ฌํ๋ ์ญํ )
- APPLICATION LAYER : ์์ฉ ์์ญ. ์์คํ ์ด ์ฌ์ฉ์์๊ฒ ์ ๊ณตํด์ผ ํ ๊ธฐ๋ฅ์ ๊ตฌํํ๋ค. (Service ์์ญ)
- DOMAIN LAYER : ๋๋ฉ์ธ ์์ญ. ๋๋ฉ์ธ ๋ชจ๋ธ์ ๊ตฌํํ๋ค. (์ด๋ฆ, ์ฃผ์, ์ํ, ์ฃผ๋ฌธ์ ๋ฑ)
- INFRASTRUCTURE LAYER : ๊ตฌํ ๊ธฐ์ ์ ๋ํ ๊ฒ์ ๋ค๋ฃฌ๋ค. (์ธ๋ถ API, ๋ฐ์ดํฐ๋ฒ ์ด์ค, ์ธ๋ถ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ๋ฑ)
# PRESENTATION LAYER(ํํ์์ญ)
- ์ฌ์ฉ์๊ฐ ์์คํ ์ ์ฌ์ฉํ ์ ์๋ (ํ๋ฉด) ํ๋ฆ์ ์ ๊ณตํ๊ณ ์ ์ด
- ์ฌ์ฉ์์ ์์ฒญ์ ์๋ง์ ์์ฉ ์๋น์ค์ ์ ๋ฌํ๊ณ ๊ฒฐ๊ณผ๋ฅผ ์ฌ์ฉ์์๊ฒ ์ ๊ณตํ๋ค.
- ์ฌ์ฉ์์ ์ธ์ ์ ๊ด๋ฆฌํ๋ค.
# APPLICATION LAYER(์์ฉ์์ญ)
- ์ฌ์ฉ์์ ์์ฒญ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด ๋ฆฌํฌ์งํฐ๋ฆฌ๋ก๋ถํฐ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ๊ณ , ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ค.
- ๋ก์ง์ ์ง์ ์ํํ๊ธฐ๋ณด๋ค๋ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ก์ง ์ํ์ ์์ํ๋ค.
- ๋๋ฉ์ธ ๊ฐ์ฒด ๊ฐ์ ์คํ ํ๋ฆ์ ์ ์ด
- *ํธ๋์ญ์ ์ฒ๋ฆฌ
- ๋๋ฉ์ธ ์์ญ์์ ๋ฐ์์ํจ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌ
*ํธ๋์ญ์ ์ด๋? ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํ๋ฅผ ๋ณํ์ํค๊ธฐ ํด์ ์ํํ๋ ์์ ์ ๋จ์.
# ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ ๊ธฐ๋ณธ์์
์ํฐํฐ(Entity)์ ๋ฒจ๋ฅ(Value)
- ๋์ถํ ๋ชจ๋ธ์ ํฌ๊ฒ ์ํฐํฐ์ ๋ฒจ๋ฅ๋ก ๊ตฌ๋ถ
- ๋ฐ์ดํฐ์ ํจ๊ป ๋๋ฉ์ธ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
Entity
- ์๋ณ์๋ฅผ ๊ฐ๋๋ค.
- ์๋ณ์๋ ์ํฐํฐ ๊ฐ์ฒด๋ง๋ค ๊ณ ์ ํด์ ๊ฐ ์ํฐํฐ๋ ์๋ก ๋ค๋ฅธ ์๋ณ์๋ฅผ ๊ฐ๋๋ค.
๋๋ฉ์ธ ๋ชจ๋ธ์ set ๋ฉ์๋ ๋ฃ์ง ์๊ธฐ
- ๋๋ฉ์ธ ๋ชจ๋ธ์ get/set ๋ฉ์๋๋ฅผ ๋ฌด์กฐ๊ฑด ์ถ๊ฐํ๋ ๊ฒ์ ์ข์ง ์์ ๋ฒ๋ฆ์ด๋ค.
- ํนํ set ๋ฉ์๋๋ ๋๋ฉ์ธ์ ํต์ฌ ๊ฐ๋ ์ด๋ ์๋๋ฅผ ์ฝ๋์์ ์ฌ๋ผ์ง๊ฒ ํ๋ค.
- set ๋ฉ์๋์ ๋ ๋ค๋ฅธ ๋ฌธ์ ๋ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋ ์์ ํ ์ํ๊ฐ ์๋ ์๋ ์๋ค๋ ๊ฒ์ด๋ค.
- ๋๋ฉ์ธ ๊ฐ์ฒด๊ฐ ๋ถ์์ ํ ์ํ๋ก ์ฌ์ฉ๋๋ ๊ฒ์ ๋ง์ผ๋ฌ๋ฉด ์์ฑ ์์ ์ ํ์ํ ๊ฒ์ ์ ๋ฌํด ์ฃผ์ด์ผ ํ๋ค.
Value Object
- ๋ฒจ๋ฅ ํ์ ์ ๋ถ๋ณ์ ์์น์ผ๋ก ํ๋ค.
- ์๋ฏธ๋ฅผ ๋ช ํํ๊ฒ ํํํ๊ฑฐ๋ ๋ ๊ฐ ์ด์์ ๋ฐ์ดํฐ๊ฐ ๊ฐ๋ ์ ์ผ๋ก ํ๋์ธ ๊ฒฝ์ฐ ๋ฒจ๋ฅ ํ์ ์ ์ด์ฉํ๋ค.
- ์์คํ ์ด ์ฑ์ํจ์ ๋ฐ๋ผ ๋ฐ์ดํฐ ๊ฐ์ ๊ฐ์ฒด๋ก ๋์ฒดํ๋ค.
- ๋ฒจ๋ฅ ๊ฐ์ฒด์ ๊ฐ์ ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ์ ์๋ก์ด ๋ฒจ๋ฅ ๊ฐ์ฒด๋ฅผ ํ ๋นํ๋ ๊ฒ๋ฟ์ด๋ค.
- ์๋ณ์๊ฐ ์กด์ฌํ์ง ์๋๋ค.
Aggregate
- ๊ด๋ จ ๊ฐ์ฒด๋ฅผ ํ๋๋ก ๋ฌถ์ ๊ตฐ์ง
- ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ๊ตฐ์ง์ ์ํ ๊ฐ์ฒด๋ค์ ๊ด๋ฆฌํ๋ ๋ฃจํธ ์ํฐํฐ๋ฅผ ๊ฐ๋๋ค.
- ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ก ๋ฌถ์ด์ ๋ฐ๋ผ๋ณด๋ฉด ์ข ๋ ์์ ์์ค์์ ๋๋ฉ์ธ ๋ชจ๋ธ ๊ฐ์ ๊ด๊ณ๋ฅผ ํ์ ํ ์ ์๋ค.
- ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ํ ๊ฐ์ฒด๋ ์ ์ฌํ๊ฑฐ๋ ๋์ผํ ๋ผ์ดํ์ฌ์ดํด์ ๊ฐ๋๋ค.
- ํ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ํ ๊ฐ์ฒด๋ ๋ค๋ฅธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ํ์ง ์๋๋ค.
- ๋๋ถ๋ถ์ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ํ๊ฐ์ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๊ฐ์ง๋ฉฐ, ๋ ๊ฐ ์ด์์ ์ํฐํฐ๋ก ๊ตฌ์ฑ๋๋ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ๋๋ฌผ๊ฒ ์กด์ฌํ๋ค.
- ๊ฐ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ์๊ธฐ ์์ ์ ๊ด๋ฆฌํ ๋ฟ ๋ค๋ฅธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ๊ด๋ฆฌํ์ง ์๋๋ค.
(์)์ฃผ๋ฌธ ์ ๊ทธ๋ฆฌ ๊ฑฐํธ๋ ๋ฐฐ์ก์ง ๋ณ๊ฒฝ, ์ฃผ๋ฌธ ์ํ ๋ณ๊ฒฝ ๋ฑ ์์ ์ ๊ด๋ฆฌํ์ง๋ง ํ์ ๋น๋ฐ๋ฒํธ ๋ณ๊ฒฝ, ์ํ ๊ฐ๊ฒฉ ๋ณ๊ฒฝ ๋ฑ์ ํ์ง ์๋๋ค.
*์ฃผ๋ฌธ(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 ์ด ์ด์์ ์ด๋ค.
*์ฃผ์ํ ์
- ํ์ ๋๋ฉ์ธ ๋ชจ๋ธ์ด ๋ค์์ด์ง ์๋๋ก ํ๋ ๊ฒ
- ๊ฐ๋ณ 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)์ ๊ตฌ๋ถ
- 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
์ด๋
ธํ
์ด์
์ ํตํด ํฉํ ๋ฆฌ ๋ฉ์๋๋ก ์์ฑ๋๋ค.
# ๋ค์ด๋๋ฏน ํ ์คํธ์ ์ฅ์
- ์ ์ฐ์ฑ
๋ค์ด๋๋ฏน ํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ฐ์ฅ ํฐ ์ด์ ๋ ์๋ง๋ ๋ฐํ์ ์์ ์ ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ ์ ์๋ค๋ ์ ์ฐ์ฑ์ ๊ผฝ์ ์ ์๋ค.
@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์์์ ๋ฐ์ดํฐ ๊ฒฐ๊ณผ๋ฅผ ๊ณต์ ํ๊ณ ์ฐ์์ฑ ์๋ ํ
์คํธ๋ฅผ ์์ฑํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
- ๊ฐ๋ ์ฑ
์ธ์ํ ์คํธ ์ฒ๋ผ ํ๋์ ๋ฉ์๋ ์์์ ์ฌ์ฉ์ ์๋๋ฆฌ์ค๋ฅผ ์์ฑํด์ผํ ๊ฒฝ์ฐ
/*
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();