๐ ๋ฆฌํฉํ ๋ง & ์ฑ๋ฅ ๊ฐ์
April 3, 2024 ยท View on GitHub
์ฟ ๋ง
๊ฑด๊ตญ๋ํ๊ต์ ๊ณต์ง๋ ์ฐ๋ฆฌ๊ฐ ์ฑ ์์ง๋ค!
๐ ํ๋ก์ ํธ ์๊ฐ
ํน์?,
ํ์ํ ๊ฑด๊ตญ๋ํ๊ต์ ๊ณต์ง๋ฅผ ํ์ธํ์ง ๋ชปํ์ฌ ๊ณค๋ํ์ ์ ์ด ์์ผ์ ๊ฐ์?
์ข
์ข
๋์น๊ณค ํ๋ ๊ตํํ์ ๊ณต์ง์ฌํญ, ์ฅํ๊ธ ์ ์ฒญ ๋ฑ... ์ด์ ๊ฑฑ์ ํ์ง ๋ง์ธ์.
์ฐ๋ฆฌ ๋ํ ๊ณต์ง์ฌํญ, ์ฟ ๋ง์ด ์๋ ค๋๋ฆฝ๋๋ค!
๐ฉโ๐ฆโ๐ฆ Backend Members
| shine | ngwoon |
|---|---|
| zbqmgldjfh | ngwoon |
๐ง Pain Point
๋ณธ๋ฌธ ํ์ธ (๐ Click)
๊ธฐ์กด์ ํ๊ต ๊ณต์ง๋ฅผ ํ์ธํ๊ธฐ ์ํด์๋ ์ฑ์ด ์๋ ํํ์ด์ง๋ก ์ ๊ทผ โ ํด๋น ํ๊ณผ๋ก ์ด๋ โ ํ๊ณผ ๋ด์ ๊ณต์งํจ ์ ์
๊ณผ๊ฐ์ด ๋ถํ์ํ step์ ์งํํด์ผ๋ง ๊ณต์ง๋ฅผ ํ์ธํ ์ ์์์ผ๋ฉฐ, ๋
ธํธ๋ถ์ด ์๋ค๋ฉด ๊ณต์ง๋ฅผ ํ์ธํ๊ธฐ๊ฐ ๋งค์ฐ ๋ถํธ ํ์ต๋๋ค.
์ด๋ฌํ ๋ถํธํจ์ ์์ ๊ณ , ๋ชจ๋ ๊ฑด๊ตญ๋ ํ์๋ค์๊ฒ ํธ๋ฆฌํ ๊ณต์ง๋ฅผ ์ ๊ณตํ๊ธฐ ์ํด ๋ง๋ ์๋น์ค์
๋๋ค.
๋น๋ก ์์ง๋ ๋ง์ด ๋ถ์กฑํ์ง๋ง, ์ ์ฌ์ฉํ๊ณ ์๋ค๋ ํผ๋๋ฐฑ์ ๋ฐ์๋์ ๋ฟ๋ฏํจ์ ์๋๋ ฅ์ผ๋ก ๊ฐ์ ํด๋๊ฐ๋ ์ค ์
๋๋ค.
๐ EventStorming
๋ณธ๋ฌธ ํ์ธ (๐ Click)
๋๋ฉ์ธ ๋ชจ๋ธ ๋ถ๋ฆฌ๋ฅผ ์ํ Event Storming (4์ผ ์์)
์ด๋ฒคํธ ์คํ ๋ฐ ๋์ค ์ถ๊ฐ๋๋ ์ด๋ฒคํธ๋ ์ถฉ๋ถํ๊ฒ ๋ฐ์ํ ์ ์์ผ๋ฉฐ, ์ง๊ธ์ ์ ํ์ด 100% ๋ชจ๋๊ฐ ๋์ ๊ฐ๋ฅํ ๋ชจ๋ธ ๋ถ๋ฆฌ๋ ์๋ ์ ์๋ค.
2-2-1) Event (Orange Sticker)
์ฐ์ ์๊ฐ์ ํ๋ฆ์ ๋ฐ๋ผ ๋น์ง๋์ค์ ์ํ ๋ณ๊ฒฝ์ ์๋ฏธํ๋ ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ๋์ถํด๋ณด์์ต๋๋ค.
ํ์๋ค๊ณผ ํจ๊ป ์ค๋ ์ง์ ํฌ์คํธ์์ ์ด๋ฒคํธ ๋ช ์ ์์ฑํ์๋๋ฐ, ์ด๋ ์ด๋ฒคํธ ๋ช ์ ๊ณผ๊ฑฐ๋ช ์ผ๋ก ์์ฑํ๋ค. ๋ผ๋ ๋ด์ฉ์ ์ค์ํ๋ ค ๋ ธ๋ ฅํ์์ต๋๋ค.
์ด๋ฒคํธ๊ฐ์ ๊ณต๊ฐ์ ๋๋ ์ด๋ฒคํธ๊ฐ ์ฐ์์ ์ผ๋ก ๋ฐํํ๋ ๊ฒฝ์ฐ ๋ฐ๋ก ์์ ๋ถ์ธ๋ค. ๊ฐ์ ์์ ์ ๋น์ง๋์ค ์กฐ๊ฑด์ ๋ฐ๋ผ ๋์ฒด์ ์ผ๋ก ๋ฐ์๋ ์ ์๋ ์ด๋ฒคํธ๋ ์๋์ ๊ฐ์ ๋ผ์ธ์ ์์ผ๋ก ๋ถ์ธ๋ค.
๋๋ฉ์ธ ์ด๋ฒคํธ๋ ๋น์ง๋์ค์ ์ด๋ค ์ํ๋ฅผ ์์ฑ,๋ณ๊ฒฝ,์ญ์ ํ๋ ์์๋ผ ํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ์์คํ ์ ํ๋ฉด์ ์ฐ์ํ์ง ๋ง๊ณ ๋น์ง๋์ค๊ฐ ํ๋ฌ๊ฐ์ ๋ฐ๋ผ ๋น์ง๋์ค๋ฅผ ๊ตฌ์ฑํ๋ ์์๋ค์ ์ํ๊ฐ ์ด๋ป๊ฒ ๋ณ๊ฒฝ๋๋์ง๋ฅผ ์๊ฐํ๋๋ก ํ์์ต๋๋ค.
์ฐ๋ฆฌ ํ์ ์์คํ ์ ์ฌ์ฉํ๋ ์ญํ (์ฌ์ฉ์, ๋์์ด๋, ๊ฐ๋ฐ์)๋ก ๋๋์ด์ ์ฌ๋๋ค์ ๋ฐฐ์ ํ์ฌ ์ ๋ฌด๋ณ๋ก ๋ ผ์๊ฐ ๊ฐ๋ฅํ ์์ค์ธ ์ ์ ํ ์ธ์์ด(4๋ช ) ์ฐธ์ฌํ์์ต๋๋ค.
2-2-2) Command (Blue Sticker)
์ด๋ฒคํธ๋ฅผ ํธ๋ฆฌ๊ฑฐํ๋(๋ฐ์์ํค๋) ์ปค๋งจ๋๋ฅผ ๋์ถํ์์ผ๋ฉฐ ์ ์ฌ์ง๊ณผ ๊ฐ์ต๋๋ค.
์ปค๋งจ๋์ ๊ฒฝ์ฐ ํ๋์ ํฌ์คํธ์์ ์์ฑํ์ฌ ๋ถ์์ผ๋ฉฐ, ์ปค๋งจ๋๋ ์ด๋ฒคํธ๋ฅผ ๋ณด๋ฉด ์ฝ๊ฒ ์ ์ถํ ์ ์๋ค๊ณ ์๊ฐ๋ฉ๋๋ค.
ํ๋์ ์ปค๋งจ๋์ ์ํด ์ฌ๋ฌ๊ฐ์ ์ด๋ฒคํธ๊ฐ ์ฐ์ ๋ฐ์๋ ์ ์์ผ๋ฉฐ ์ปค๋งจ๋ ํ๋์ ์กฐ๊ฑด์ ๋ฐ๋ผ ๋ค๋ฅธ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์ ์์์ ์ ์ํ์!
[์ด๋ฒคํธ] ํ ๋๋ ํญ์ [์ปค๋งจ๋] ํ๋ค
2-2-3) Actor (Yellow Sticker)
์ํฐ๋ ์ฌ๋์ด๋ ์กฐ์ง์ด ๋ ์ ์๋๋ฐ ์ญํ ๊ด์ ์ผ๋ก ๋์ถํด๋ณด์์ต๋๋ค. ์ํฐ๋ ์ถ์์ ์ผ๋ก ์๋ณํ์ง ๋ง๊ณ ๋น์ง๋์ค๋ฅผ ์ํํ๋ ๊ตฌ์ฒด์ ์ธ ์ญํ ๋ก ๊ณ ๋ คํ์ฌ ๋์ถํ๋ค.
์ฆ ๊ทธ๋ฅ ๋ชจ๋ ์ ๋ฌด์์ ๋ณดํธ์ ์ผ๋ก ์ฌ์ฉ๋๋ ํ์, ๊ด๋ฆฌ์๋ก ๋ฝ์ง ๋ง๊ณ ํน์ ๋น์ง๋์ค๋ฅผ ์ค์ ์ ์ผ๋ก ์ํํ๋ ์ญํ ์๋ฅผ ๋์ถํ๋ ค๊ณ ๋ ธ๋ ฅํ์์ผ, ์กํฐ๊ฐ ๊ตฌ์ฒดํ ๋ ์๋ก ์๋ณํ์ง ๋ชปํ ์ปค๋งจ๋์ ์ด๋ฒคํธ๊ฐ ์ถ๊ฐ์ ์ผ๋ก ๋์ถ ๋ ์ ์์ต๋๋ค.
์ฐ๋ฆฌ์ ์๋น์ค๋ ์ํฐ๋ ํ๊ต์ ๋ค๋๋ ํ์, ๊ต์ง์ (๊ณต์ง์ฑ ์ฌ์ฉ์) ์ ๋๋ก ์๊ฐํ์์ต๋๋ค. ์ํฐ๋ฅผ ๋์ถํ๊ณ ๋ณด๋, ์ฌ์ง๊ป ๊ต์ง์์ ์ํ ๊ธฐ๋ฅ์ ์์์์ ํ๋ฒ ์๊ธฐํ๊ฒ ๋์์ต๋๋ค.
2-2-4) Aggregate (Yellow Sticker)
์ด๊ทธ๋ฆฌ๊ฒ์ดํธ๋ โ๊ฒฐํฉ๋ฌผโ์ ์๋ฏธํ๋๋ฐ ์ด๋ ํ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์ค์ฌ์ผ๋ก ์๊ฐํ์์ผ๋ฉฐ,
ํ๋์ ACIDํ ํธ๋์ญ์
์ ๋ฌถ์ฌ ๋ณํ๋์ด์ผ ํ ๊ฐ์ฒด์ ๋ฌถ์์ ๋์ถํ๊ณ , ๊ทธ๊ฒ๋ค์ ์ปค๋งจ๋, ์ด๋ฒคํธ์ ํจ๊ป ๋ฌถ์ด๋ณด์์ต๋๋ค.
2-2-5) ๋ฐ์ด๋๋ ์ปจํ ์คํธ๋ก ๋ฌถ๊ธฐ
Bounded Context(BC)๋ ๋์ผํ ๋ฌธ๋งฅ์ผ๋ก ํจ์จ์ ์ผ๋ก ์
๋ฌด ์ฉ์ด(๋๋ฉ์ธ ํด๋์ค)๋ฅผ ์ฌ์ฉํ ์ ์๋ ๊ฐ์ฒด ๋ฒ์๋ฅผ ๋ปํ๋ค๊ณ ํฉ๋๋ค.
ํ๋์ BC๋ ํ๋ ์ด์์ ์ด๊ทธ๋ฆฌ๊ฒ์ดํธ๋ฅผ ์์๋ก ๊ตฌ์ฑ๋ ์ ์์ผ๋ฉฐ, ์ด BC๋ฅผ ๋ง์ดํฌ๋ก์๋น์ค ๊ตฌ์ฑ ๋จ์๋ก ์ ํ๊ฒ ๋๋ฉด ์ด๋ฅผ ๋ด๋นํ๋ ํ ๋ด์ ์ปค๋ฎค๋์ผ์ด์
์ด ํจ์จํ ๋ ๊ฒ ๊ฐ์ต๋๋ค?
์ถํ MSAํ๋ฅผ ๊ณ ๋ ค์ค์ด๊ธฐ์ ํจ๊ป ๊ณ ๋ คํด๋ณธ ๋์์ ๋๋ค.
2-2-6) ์ธ๋ถ ์์คํ ์ถ๊ฐ
์ปค๋งจ๋ & ์ด๋ฒคํธ ๋ฐ์ ์ ํธ์ถ๋๊ฑฐ๋ ๊ด๋ จ๋๋ ๋ ๊ฑฐ์ ์์คํ
์ด๋ ์ธ๋ถ ์์คํ
๋๋ ์ฅ๋น๋ฅผ ๋์ถํ์ฌ ํํฌ์ ํฌ์คํธ์์ ์์ฑํ์ฌ ์ด๋ฒคํธ์ ์ค๋ฅธ์ชฝ ์๋จ์ ์ถ๊ฐ!
๋ณธ ์์คํ ์ ๊ตฌํ ๋์์ด ์๋์ง๋ง ์์คํ ์ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํด ์ฐ๊ณ๊ฐ ํ์ํ ์์คํ ๋ค์ ๋ชจ๋ ๋์ถํด๋ณธ ๊ฒฐ๊ณผ, FCM์ ์๋ฆผ ๊ธฐ๋ฅ ์ ๋๊ฐ ์ธ๋ถ ์์กด์ผ๋ก ์ถ๊ฐ๋์์ต๋๋ค.
2-2-7) Policy (Lilac Sticker) ๋์ถ
ํด๋ฆฌ์(Policy)๋ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ํ ์ฐ์ด์ด ๋ฐ์ํ๋ ๋ฐ์ํ ์ก์
์ผ๋ก, ํ ์๋น์ค ์ด๋ฒคํธ์ ๋ํด ์ํ๋์ด์ผ ํ ํ ์๋น์ค์ ์ก์
๋ค๋ก, ๋จผ์ ์ ์๋ ์ด๋ฒคํธ ์๋์ ์ถ๊ฐํ์์ต๋๋ค.
ํ๋์ ์ด๋ฒคํธ์ ๋ฐ์ํ์ฌ ์ํ๋์ด์ผ ํ ํด๋ฆฌ์๋ ์ฌ๋ฌ ํ์์ ๋์ถ๋ ๋ฉํฐ ์ก์
์ด ์กด์ฌํ ์ ์๋ค.
2-2-8) ํด๋ฆฌ์์ ์ด๋๊ณผ ์ปจํ ์คํธ ๋งคํ (์ ์ ์ Pub/Sub, ์ค์ ์ Req/Resp)
์์ ๊ฐ์ด ์ต์ข
์ ์ผ๋ก ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ถ๋ฆฌํ๊ฒ ๋์์ต๋๋ค!!
๐ ๋ฆฌํฉํ ๋ง & ์ฑ๋ฅ ๊ฐ์
๋ณธ๋ฌธ ํ์ธ (๐ Click)
1. ์๋ฏธ์๋ ์ด๋ฆ๊ณผ ํจ์
์ฝ๋๋ฅผ ๋ค์ ๋๋์๋ณด์์ ๋, ๋น์์๋ ์ดํดํ ์ ์์ ์ ๋์ ์ด๋ฆ์ผ๋ก ์ง์๋ค๊ณ ์๊ฐํ์ผ๋ ๋ช
ํํ๊ฒ ์๋ฟ์ง ์๋ ๋ค์ด๋ฐ๋ค์ด ์์์ต๋๋ค.
๋ฐ๋ผ์ ์ฃผ์์ด ํ์ ์์ ์ ๋๋ก ๋ช
ํํ๊ฒ ๋ณ์๋ช
๊ณผ ํจ์๋ช
์ ์์ ํ์์ต๋๋ค.
ํจ์์ ๋ํด์๋ Clean Code์์ 5์ค ์ด๋ด๋ฅผ ๊ถ์ฅํ๊ณ ์์์ต๋๋ค. ์ฝ๋๋ฅผ ๋๋์๋ณธ ๊ฒฐ๊ณผ ์๊ฐ๋ณด๋ค ํจ์๊ฐ ๊ธด ๊ฒ๋ค์ด ์กด์ฌํ๊ณ ์ถฉ๋ถํ ์ค์ผ ์ ์๋ ์์ค์ ๋ด์ฉ๋ค์ด์๊ธฐ์ ํ ์ ์๋ ํ์์ 5์ค ๋ด์ธ๋ฅผ ์งํค๋๋ก ์์ ํ์ต๋๋ค.
2. ํฅ์ฌ๊ณ ๋ ์ํคํ์ฒ๋ก์ ์ ํ
๋ฌธ์ ์ํฉ
- ๊ธฐ์กด ์ํคํ์ฒ์ ํ๊ณ์ (๋ฐ์ดํฐ ์ค์ฌ์ ์ค๊ณ๊ฐ ๋ถ๋ฌ์จ ํ๊ณ)
- ์ ํํ ๊ธฐ์ค ์์ด ๊ทธ๋ ๊ทธ๋ ๋ฌ๋ผ์ง๋ ํํค์ง ๊ตฌ์กฐ์ ๋ค์ด๋ฐ ๋ฐฉ์
- ํ์ฅ์ ๋ํ ๊ณ ๋ ค๊ฐ ์๋ ๊ธฐ์กด์ ์ค๊ณ
๋ฌธ์ ํด๊ฒฐ
- ๊ธฐ์กด์ ์ํคํ ์ฒ๋ฅผ ํฅ์ฌ๊ณ ๋ ์ํคํ ์ฒ๋ก ์ ํํ๋ฉด์ ์ด๋ฅผ ๊ทน๋ณต
์ ์ฐ์ฑ, ์ ์ง๋ณด์์ฑ : ์ธ๋ถ ์์คํ
์ด๋ ์ธํ๋ผ์์ ์์กด์ฑ์ ๋ฎ์ถ์ด, ๊ตฌ์ฑ ์์๋ฅผ ์ฝ๊ฒ ๊ต์ฒดํ๊ฑฐ๋ ์
๋ฐ์ดํธํ ์ ์๊ฒ ๋์์ต๋๋ค.
๊ทธ๋ ๊ทธ๋ด ๊ฒ์ด application์ service๋ค์ ๋ชจ๋ ์ธํฐํ์ด์ค์ ํด๋น๋๋ port์ ์์กดํ๊ฒ ๋์์ต๋๋ค.
๋ ์ด์ ์ค ๊ตฌํ์ฒด๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ค๊ฐ์ ๋ค๋ฅธ ๊ตฌํ์ฑ๋ก ๋ณ๊ฒฝ๋์ด๋ ์ ์ฐํ๊ฒ ๋์ํ ์ ์๋ ์ฅ์ ์ ๊ฐ๊ฒ ๋์์ฃ ! ์ด๋ ๊ณง ์ ์ง๋ณด์์ฑ๊ณผ๋ ์ง๊ฒฐ๋๋ค ์๊ฐ๋๋๋ผ๊ณ ์!
ํ
์คํธ ์ฉ์ด์ฑ : ๋น์ฆ๋์ค ๋ก์ง์ ๋
๋ฆฝ์ ์ผ๋ก ํ
์คํธํ ์ ์์ด ํ์ง ํฅ์๊ณผ ๊ฐ๋ฐ ์๋ ํฅ์์ ๋์์ด ๋ฉ๋๋ค!
์ธํฐํ์ด์ค๋ฅผ ์ ์ ํ๊ฒ ์ฌ์ฉํ์๊ธฐ์ ํด๋น ๋ก์ง์ ๋
๋ฆฝ์ฑ์ ์ ์งํ ์ ์๋ ์ ์ด ๋งค์ฐ ์ฅ์ ์ด ๋ผ์ค ๊ฒ ๊ฐ์ต๋๋ค.
ํ์๊ณผ์ ํ์
: ์ฑ
์์ด ๋ถ๋ฆฌ๋์ด ์์ด, ์ฝ๋์ ์ดํด์ ์์ ์ด ์ฉ์ดํ๋ฉฐ, ๋ณํ์ ๋น ๋ฅด๊ฒ ๋์ํ ์ ์์ต๋๋ค.
์ฆ, ํํ๊ฒ ๋งํ๋ SOLID๊ฐ ๋ชจ๋ ์ง์ผ์ง๊ณ ์๋ ์ข์ ์ํคํ
์ฒ ๊ตฌ์กฐ์
๋๋ค.
๋ํ ์ 2์ ๋ฉค๋ฒ๊ฐ ๋ค์ด์์ ์ ์ง๋ณด์๋ฅผ ํ๊ฑฐ๋ ๊ฐํธํด์ผ ํด๋ HexagonalArchitecture ์์ฒด์ ์ดํด๋๋ง ์๋ค๋ฉด ์ถฉ๋ถํ ๋น ๋ฅธ ์ ์์ด ๊ฐ๋ฅํ๋ค ์๊ฐ๋ฉ๋๋ค.
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
3. ๋ ๊ฑฐ์ ์ฝ๋์ ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋จ๋ฐฉํฅ์ผ๋ก!
JPA์ ๋ํด์๋ ์๋ก ์ด๋ ์ ๋ ์ดํดํ๊ณ ์์ด, ์ ์ ํ fetch join์ ์ฌ์ฉํ์ฌ ์ฝ๋ฉํ์๊ธฐ์ N+1 ๋ฌธ์ ๋ ๋ฐ์ํ์ง ์์์ต๋๋ค. ํ์ง๋ง ์ฐ๊ด๊ด๊ณ์ ๋ํด์ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค. ๊ฐ์ฅ ์ข์ ์ฐ๊ด๊ด๊ณ ์ค๊ณ๋ ๋จ๋ฐฉํฅ์ ๊ธฐ์ด๋ก ํ๋ ํ์ํ๋ฉด ์๋ฐฉํฅ ์ค๊ณ๋ฅผ ํ๋ ๊ฒ์ ๋๋ค.
JPA ํ๋ก๊ทธ๋๋ฐ์ ์ ์, ๊น์ํ ์ ์๋์ ์๊ฒฌ์ ๋น๋ฆฌ์๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์๋ฐฉํฅ์ผ๋ก ํ๋ฉด ๋ณต์ก๋๊ฐ ๋์์ง๋ ๋จ์ ์ด ์์ง๋ง ์ฑ๋ฅ์ ์ด์ ์ ์ป์ ์ ์์ต๋๋ค. ์ ๋ง ์ฑ๋ฅ์ด ๋๋ฌด ์ค์ํด์ ์ฟผ๋ฆฌ ํ๋๋ฅผ ์ค์ด๋๊ฒ ๊ผญ ํ์ํ ์ํฉ์ด๋ผ๋ฉด ๋ณต์กํด์ง๋๋ผ๋ ์ต์ ํ๋ฅผ ํด์ผํฉ๋๋ค. ๋ฐ๋ฉด์ ์ฟผ๋ฆฌ๊ฐ ํ๋ ๋ ๋๊ฐ๋๋ผ๋ ์์คํ ์์์ด ์ถฉ๋ถํด์ ์ฑ๋ฅ์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒ์ด ๋ฏธ๋ฏธํ๋ค๋ฉด ์ฝ๋ ๋ณต์ก๋๋ฅผ ๋ฎ๊ฒ ์ ์งํ๋ ๊ฒ์ด ๋ ์ค์ํฉ๋๋ค.
๋๊ฐ์ ์๋ฐฉํฅ์ผ๋ก ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ๊ณ ์๋ค.
๊ทธ๋ผ UserCategory์ ์ถ๊ฐํด์ค๋, User์ชฝ์ private List<UserCategory> userCategories = new ArrayList<>(); ์๋ UserCategory๋ฅผ ์ถ๊ฐํ๊ณ , UserCategory ์ชฝ์์๋ User๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค!!
์ด๋ ์๋ฐฉํฅ์ผ๋ก ๋งคํ์ค์ด๊ธฐ ๋๋ฌธ์ด๋ค.
๋น์ฐํ ์ฐ๊ด๊ด๊ณ ์ฃผ์ธ์ด UserCategory ์ด๊ธฐ ๋๋ฌธ์ UserCategory์ ์ถ๊ฐํ๋์ ์ ์ ํฉํ๋ค.
ํ์ง๋ง ๋ค์ ์ฝ๋๋ UserCategory์ชฝ์๋ง ์ถ๊ฐ์ค์ด๋ค. ํํ ๋งํ๋ JPA ํธ์ ๋ฉ์๋๋ฅผ ์์ฑํ์ด์ผ ํ๋๋ฐ, ๋ค์ ์ฝ๋๋ ํธ์ ๋ฉ์๋๊ฐ ์๋ค.
๋ฐ๋ผ์ UserCategory์๋ ์ ๊ท UserCategory๊ฐ ์ถ๊ฐ ๋์ง๋ง, User๊ฐ ๋ค๊ณ ์๋ List๋ ๋น์ด ์๊ฒ ๋๋คโฆ
๋ค์ ๊ธ์ 3๋ฒ โ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ์ฃผ์์ โ์ ๋ณด๋ฉด ์ดํดํ ์ ์๋ค. https://blogshine.tistory.com/345
์์ User์์ UserCategory๋ฅผ ์ญ์ ํ๋ ํธ์ด ๋ ์ข์๊ฒ ๊ฐ๋ค. ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๊ฐ ํ์์ ์ธ ํฌ์ธํธ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ด๋ค! โ User์์ ์ ๊ฑฐ!
ํ ์ด๋ธ ๊ตฌ์กฐ์ ๋ณํ๋ ์๊ธฐ์ ์ ์ฉ๊ฐ๋ฅ
4. ๊ณต์ง Scrap์์ multi-threading ์ฒ๋ฆฌ๋ก ์๊ฐ ๊ฐ์ ํ๊ธฐ
๋ฌธ์ ์ํฉ
- ๊ธฐ์กด์ 60๊ฐ์ ํ๊ณผ๋ฅผ ์ ๋ถ Scrapํ๋๋ฐ ๋จ์ผ thread๋ก๋ ๋๋ฌด ์ค๋ ๊ฑธ๋ฆฌ๋ ๋ฌธ์ ๋ฐ์
๋ฌธ์ ํด๊ฒฐ
- 60๊ฐ ํ๊ณผ์ ๊ณต์ง๋ฅผ scrapํ๋ ๊ณผ์ ์ ๋ณ๋ ฌ์ฒ๋ฆฌ ํ๋ฉด์ Crawling ์ฑ๋ฅ๊ฐ์
- ๋จ์ผ ๊ณต์ง ํ์ด์ง ๊ธฐ์ค, core 6๊ฐ : 3๋ถ50์ด โ 49์ด๋ก ์ฑ๋ฅ์ 4.39๋ฐฐ ๊ฐ์
- ์ ์ฒด ๊ณต์ง ํ์ด์ง ๊ธฐ์ค, core 6๊ฐ : 1์๊ฐ 12๋ถ 11์ด โ 15๋ถ 35์ด๋ก ์ฑ๋ฅ์ 4.70๋ฐฐ ๊ฐ์
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
5. Full-Text-Index๋์ ์ ํตํ ๊ฒ์ ์ฑ๋ฅ๊ฐ์
๋ฌธ์ ์ํฉ
- ๊ธฐ์กด ๊ฒ์์ like ์ ์ ํ์ฉํ ๋จ์ full-scan๋ฐฉ์์ ๊ฒ์์ด๋ผ๋ ๋จ์
๋ฌธ์ ํด๊ฒฐ
- ๊ณต์ง ๊ฒ์ ์ฟผ๋ฆฌ ๋ณ๊ฒฝ, ์ค์ง๋จ์ด, Full-Text-Index๋์
์ ํตํ ๊ฒ์ ์ฑ๋ฅ๊ฐ์
- ๊ฐ์ ์ : ๊ฒ์์ full Scan์ ํตํด ์คํ๊ณํ์ด ์๋ฆฝ โ 11s 59ms
- ๊ฐ์ ํ : Full Text index๊ณผ stop word ๋์ โ 591ms
- ๊ณต์ง 500๋ง๊ฑด ๊ธฐ์ค ๊ฒ์ ์๋ 18.71๋ฐฐ ๊ฐ์ ํ๊ฒ ๋์์ต๋๋ค
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
6. HeapDump๋ฅผ ํตํด ๋ฉ๋ชจ๋ฆฌ ๋์ ์์ธ ์ฐพ๊ธฐ ๊ฒ์ ์ฑ๋ฅ๊ฐ์
๋ฌธ์ ์ํฉ
- ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ฌผ๋ฆฌ์ ์ผ๋ก ํ ๋น๋ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๋์ด, swap ๋ฉ๋ชจ๋ฆฌ๊น์ง ์ฌ์ฉํ๊ณ ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์
๋ฌธ์ ํด๊ฒฐ
- ๋งค๋ฒ URL ๊ฒ์ฆ์ ์ํ ๊ฐ์ฒด๋ฅผ ์์ฑํ ๊ฒ์ฌ ํ๋๊ฒ์ด ์๋, ํ๋ฒ Compiled๋ Pattern ์ฌ์ฉ์ ํตํ ๋ฉ๋ชจ๋ฆฌ ๋ญ๋น ํด๊ฒฐ
- ๊ฐ์ ์ : ์ ์ฒด 512MB์ค 170MB๊ฐ eden space์ ์ฃผ๊ธฐ์ ์ผ๋ก ์์ฑ โ 32%
- ๊ฐ์ ํ : ์ ์ฒด 512MB์ค 47MB๋ง ์์ฑ๋๋๋ก ๊ฐ์ โ 9%
- ๋ฏธ๋ฆฌ compiled๋ Pattern ๊ฐ์ฒด๋ฅผ ํ์ฉํ์ฌ ๋ฉ๋ชจ๋ฆฌ ๋์๋ฅผ ํด๊ฒฐํ์์ต๋๋ค.
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
7. Bulk Query๋ฅผ ํตํ ์ฑ๋ฅ ๊ฐ์
๋ฌธ์ ์ํฉ
- ๊ณต์ง๋ฅผ ์ฃผ๊ธฐ์ ์ผ๋ก ์ ์ฅํ๊ณ ์ญ์ ํ๋ ๊ณผ์ ์ด ํ๋ฃจ์๋ ์์ญ๋ฒ ๋ฐ๋ณตํ๋ ์ด ์ฑ์ ํต์ฌ ๋ก์ง์ค ํ๋์ ๋๋ค.
- ๋ฌธ์ ๋ ์ด ๊ณผ์ ์์ ๋ฐ์ํ๋ ์ฟผ๋ฆฌ๊ฐ ๋๋ฌด ๋ง๋ค๋ ๊ฒ์ ๋๋ค. ์ฟผ๋ฆฌ๋ก๊ทธ๋ฅผ ์ฐ์ด๋ณธ ๊ฒฐ๊ณผ save์ delete ๋ชจ๋ ํ๋ฐฉ ์ฟผ๋ฆฌ๊ฐ ์๋๋ผ ์ฌ๋ฌ๋ฒ์ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
๋ฌธ์ ํด๊ฒฐ
๋ค์๊ณผ ๊ฐ์ด ์์ ํ์ฌ ํด๊ฒฐํ ์ ์์์ต๋๋ค.
- Insert์ ๊ฒฝ์ฐ : JdbcTemplate.batchUpdate() ์ฌ์ฉ
- delete์ ๊ฒฝ์ฐ : queryDsl์ in ์ฟผ๋ฆฌ ์ฌ์ฉ
7-1) Insert ํด๊ฒฐ์ฑ
ํด๊ฒฐ์ฑ ์ 2๊ฐ์ง๊ฐ ์กด์ฌํ์ต๋๋ค.
- Table Id strategy๋ฅผ SEQUENCE๋ก ๋ณ๊ฒฝํ๊ณ Batch ์์
- JdbcTemplate.batchUpdate() ์ฌ์ฉ
MySQL๊ณผ MariaDB์ Table Id ์ ๋ต์ ๋๋ถ๋ถ์ด IDENTITY ์ ๋ต์ ์ฌ์ฉํ๊ธฐ๋ ํ๊ณ , ์ ํฌ๋ ์ด๋ฏธ Id ์ ๋ต์ IDENTITY ์ ๋ต์ผ๋ก ์ฌ์ฉํ๊ณ ์์๊ธฐ์ Id์ ๋ต ์์ฒด๋ฅผ ๋ณ๊ฒฝํ๊ธฐ์๋ ๋ฌด๋ฆฌ๊ฐ ์์์ต๋๋ค. ๋ํ, Jdbc๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ฑ๋ฅ์ ๋ ๋ฐ์ด๋๋ค๋ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํ์ต๋๋ค. ์ถ์ฒ
7-2) Delete ํด๊ฒฐ์ฑ
์ด๋ฏธ ํ๋ก์ ํธ์์ queryDsl๋ฅผ ์ฌ์ฉํ๊ณ ์์ด ์ด๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ๊ฐ๋จํ๊ธฐ ๋๋ฌธ์ queryDsl์ delete in ์ฟผ๋ฆฌ๋ฅผ ์ฌ์ฉํ์ฌ ํด๊ฒฐํ์ต๋๋ค.
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
8. ์ธ์ฆ, ์ธ๊ฐ๋ฅผ ๋น์ฆ๋์ค ๋ก์ง์ผ๋ก๋ถํฐ ๋ถ๋ฆฌํ๊ธฐ
๋ฌธ์ ์ํฉ
- ๋ถ๊ฐ์ ์ธ ์ธ์ฆ, ์ธ๊ฐ ๋ก์ง์ด ์ ํ๋ฆฌ์ผ์ด์ ์ ๋น์ฆ๋์ค ๋ก์ง๊ณผ ํจ๊ป ํผ์ฌ๋์ด ์๋ ์ํ
๋ฌธ์ ํด๊ฒฐ
- ์ธ์ฆ, ์ธ๊ฐ๋ฅผ ํต์ฌ ๋น์ฆ๋์ค๋ก์ง ์ผ๋ก ๋ถํฐ ๋ถ๋ฆฌํ์ฌ ๋ฆฌํฉํ ๋ง ํ๊ธฐ
- Spring Security์ ์ ์ฌ ๊ตฌ์กฐ๋ฅผ ์ง์ ๊ตฌํ
- ์ง์ ๊ตฌํํ ์ ์ฒด ์ธ์ฆ ๋ก์ง ํ๋ฆ๋
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
9. ํํ๋ ํํ N+1 ์ฟผ๋ฆฌ ๊ฐ์ ๊ธฐ
์๋ ๋ก์ง์์๋ ์ฌ์ฉ์์ Category ์ด๋ฆ ๋ชฉ๋ก์ ๊ฐ์ ธ์ค๊ธฐ ์ํด์ ๋ค์๊ณผ ๊ฐ์ด ์ฒ๋ฆฌ๊ฐ ๋๊ณ ์์์ต๋๋ค!
getUserCategories ๋ ๋ค์๊ณผ ๊ฐ๊ณ ,
public List<Category> getUserCategories(String token) {
User user = userRepository.findByToken(token);
// User์์ ์ด๋ฏธ ์ฐ๊ด๊ด๊ณ๋ก ๋ค๊ณ ์๋ ์ํฉ์ด์๋ค.
List<UserCategory> userCategories = userCategoryRepository.findAllByUser(user);
return userCategories.stream()
.map(UserCategory::getCategory)
.collect(Collectors.toList());
}
์์ ๊ธฐ์กด ์ฝ๋์์ user๋ฅผ ์ฐพ์์ฌ๋ ์ฌ์ค UserCategory๋ฅผ EAGER๋ก ์ฐพ์์ค๊ณ ์์๋ค.
๋ฐ๋ผ์ ๋ค์๊ณผ ๊ฐ์ด ๋ณ๊ฒฝ ํ์ด๋ ๋ฌ์๊ฒ ๊ฐ๋ค!
List<UserCategory> userCategories = user.getUserCategories(); // ์ด๋ฏธ User๋ UserCategory ์ ๋ณด๊ฐ ์์
์ฆ, User๋ฅผ ์ฐพ์์ฌ๋ ์ด๋ฏธ Category๋ฅผ ์ฐพ์์ค๋ ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๋๋ฐ, findAllByUser๋ก ์ฐพ์์ฌ ํ์๊ฐ ์์๋ค.
(ps, ๋คํ์ด 1์ฐจ ์บ์ ๋๋ถ์ ์์์ฑ ์ปจํ ์คํธ์์ ์ฐพ์์ค๊ธฐ์ ๋์ผํ ์ฟผ๋ฆฌ๊ฐ 2๋ฒ ๋๊ฐ์ง๋ ์๋๋ค)
getCategoryNamesFromCategories ๋ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํ๋์ด ์์๋ค!
public List<String> getCategoryNamesFromCategories(List<Category> categories) {
return categories.stream()
.map(Category::getName)
.collect(Collectors.toList());
}
์ด๋ ๊ฒ ์ฒ๋ฆฌ๋์ด ์ฌ์ฉ์์ Category์ด๋ฆ์ ์ ๋ถ ๋ณด์ฌ์ฃผ๊ณ ์์๋ค!
์ฆ, User ํ๋๋ง ์กฐํํด๋ UserCategory๊น์ง ํจ๊ป ์กฐํํ๊ณ ์์ผ๋~
-
token๊ฐ์ ๊ฐ๋ User๋ฅผ ์ฐพ์์จ ํ // ์ฟผ๋ฆฌ 1๋ฒ
-
User์ UserCategory๋ฅผ ๋ค ์ฐพ์์จ๋ค. // UserCategory๋ฅผ ๋ฐ๋ก ์ฐพ์์ค๋ ์ฟผ๋ฆฌ N๊ฐ (N+1๋ฌธ์ )
-
์ดํ ์ฐพ์์จ UserCategory ๋ชฉ๋ก์ ํตํด Category ๋ชฉ๋ก์ ์ฐพ๋๋ค. // Category N๊ฐ๋งํผ ์ฟผ๋ฆฌ
-
์ฐพ์์จ Category ๋ชฉ๋ก์ String ์ด๋ฆ๋ก ๋ฐ๊พผ๋ค.
์ฟผ๋ฆฌ๊ฐ ์ด 1 + 2N ๋งํผ ๋ฐ์์ค์ด๋ค.
9 - 1) ๋ณ๊ฒฝ ์ ์ฟผ๋ฆฌ
Hibernate:
select
user0_.id as id1_5_,
user0_.token as token2_5_
from
user user0_
where
user0_.token=?
2023-01-25 21:19:36.747 INFO 16011 --- [o-auto-1-exec-5] p6spy : #1674649176747 | took 1ms | statement | connection 22| url jdbc:mariadb://localhost:52131/test
select user0_.id as id1_5_, user0_.token as token2_5_ from user user0_ where user0_.token=?
select user0_.id as id1_5_, user0_.token as token2_5_ from user user0_ where user0_.token='test_fcm_token';
Hibernate:
select
usercatego0_.user_token as user_tok3_6_0_,
usercatego0_.id as id1_6_0_,
usercatego0_.id as id1_6_1_,
usercatego0_.category_name as category2_6_1_,
usercatego0_.user_token as user_tok3_6_1_
from
user_category usercatego0_
where
usercatego0_.user_token=?
2023-01-25 21:19:36.749 INFO 16011 --- [o-auto-1-exec-5] p6spy : #1674649176749 | took 1ms | statement | connection 22| url jdbc:mariadb://localhost:52131/test
select usercatego0_.user_token as user_tok3_6_0_, usercatego0_.id as id1_6_0_, usercatego0_.id as id1_6_1_, usercatego0_.category_name as category2_6_1_, usercatego0_.user_token as user_tok3_6_1_ from user_category usercatego0_ where usercatego0_.user_token=?
select usercatego0_.user_token as user_tok3_6_0_, usercatego0_.id as id1_6_0_, usercatego0_.id as id1_6_1_, usercatego0_.category_name as category2_6_1_, usercatego0_.user_token as user_tok3_6_1_ from user_category usercatego0_ where usercatego0_.user_token='test_fcm_token';
Hibernate:
select
user0_.id as id1_5_1_,
user0_.token as token2_5_1_,
usercatego1_.user_token as user_tok3_6_3_,
usercatego1_.id as id1_6_3_,
usercatego1_.id as id1_6_0_,
usercatego1_.category_name as category2_6_0_,
usercatego1_.user_token as user_tok3_6_0_
from
user user0_
left outer join
user_category usercatego1_
on user0_.token=usercatego1_.user_token
where
user0_.token=?
2023-01-25 21:19:36.755 INFO 16011 --- [o-auto-1-exec-5] p6spy : #1674649176755 | took 1ms | statement | connection 22| url jdbc:mariadb://localhost:52131/test
select user0_.id as id1_5_1_, user0_.token as token2_5_1_, usercatego1_.user_token as user_tok3_6_3_, usercatego1_.id as id1_6_3_, usercatego1_.id as id1_6_0_, usercatego1_.category_name as category2_6_0_, usercatego1_.user_token as user_tok3_6_0_ from user user0_ left outer join user_category usercatego1_ on user0_.token=usercatego1_.user_token where user0_.token=?
select user0_.id as id1_5_1_, user0_.token as token2_5_1_, usercatego1_.user_token as user_tok3_6_3_, usercatego1_.id as id1_6_3_, usercatego1_.id as id1_6_0_, usercatego1_.category_name as category2_6_0_, usercatego1_.user_token as user_tok3_6_0_ from user user0_ left outer join user_category usercatego1_ on user0_.token=usercatego1_.user_token where user0_.token='test_fcm_token';
HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Wed, 25 Jan 2023 12:19:36 GMT
Keep-Alive: timeout=60
Connection: keep-alive
N+1 ๋ฌธ์ ๋ก Userํ๋ฒ ์กฐํํ๋๋ฐ ์์ ๊ฐ์ด ์ฟผ๋ฆฌ๊ฐ 3๋ฒ ๋๊ฐ๊ฒ ๋จ
9 - 2) ๋ณ๊ฒฝ ํ
๋ณ๊ฒฝ ํ ํ๋ฐฉ ์ฟผ๋ฆฌ๋ก ์กฐํ ๋
public List<String> getUserCategoryNamesByToken(String token) {
return queryFactory
.select(userCategory.category.name)
.from(userCategory)
.where(userCategory.user.token.eq(token))
.fetch();
}
10. Test Container๋ฅผ ํตํ ํ ์คํธ์ ๋ฉฑ๋ฑ์ฑ ๋ณด์ฅํ๊ธฐ
ํ ์คํธ์, ์ค์ ์ด์ DB๋ฅผ ๋๋ค MariaDB ํ๊ฒฝ์ผ๋ก ์ฌ์ฉํ์ฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ผ์ด ์๋ค ์๊ฐํ์์ต๋๋ค. ํ์ง๋ง, utf8๊ณผ ๊ฐ์ ์ธ์ฝ๋ฉ ๋ฐฉ์์ด ๋ก์ปฌ๊ณผ ํ๋ก๋์ ์ด ๋ฌ๋ผ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์์ผ๋ฉฐ, ์ด๋ํ ํ ์คํธ ํ๊ฒฝ์์ ๊ฑธ๋ฌ๋ด์ง ๋ชปํ ๊ฒ์ด ๋ฌธ์ ๋ผ ์๊ฐํ์์ต๋๋ค.
๋ฐ๋ผ์ ์ดํ๋ถํฐ๋ ํ๊ฒฝ ์์ฒด๋ฅผ ๋์ผํ๊ฒ ๋ง๋ Test ์ปจํ
์ด๋๋ฅผ ์ฌ์ฉํ์ฌ ํ๋ก๋์
ํ๊ฒฝ๊ณผ ๋์ผํ ํ๊ฒฝ๋ณ์ ํ๊ฒฝ์์ ํ
์คํธ๋ฅผ ์งํํ๋๋ก ํ์์ต๋๋ค.
ํ
์คํธ์์ ์ํ ์๊ฐ์ด ์กฐ๊ธ ๊ธธ์ด์ก์ง๋ง, ํ
์คํธ์ ๋ชฉ์ ์ ๋ถํฉํ๋๋ก ๋์ํ๊ฒ ๋์์ต๋๋ค.
11. CI / ์ ์ ๋ถ์๊ธฐ(SonarCloud, jacoco)๋ฅผ ์ฌ์ฉํ ์ฝ๋ ์ปจ๋ฒค์ ์ ๋ํ ์ฝ๋๋ฆฌ๋ทฐ ์๋ํ
๋ฌธ์ ์ํฉ
- ์ ์ ๋ถ์ ๋๊ตฌ๊ฐ ์์ด ์ฝ๋์ ํ์ง ๊ด๋ฆฌ๋, ๋ฒ๊ทธ ๋ฐ๊ฒฌ๋ฑ์ด ์ด๋ ค์ ๋ ์ํฉ
๋ฌธ์ ํด๊ฒฐ
- ์ ์ ๋ถ์ ๋๊ตฌ๋ฅผ ํตํ ๋ถ์์ ํตํ์ฌ ์ฌ์ ์ ๋ฏธ๋ฆฌ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๋ ์ง์ ๋ค์ ๋ณด์ํ ์ ์์
- ํ ์คํธ ์ฝ๋์ ์ปค๋ฒ๋ฆฌ์ง์ ๋ํ ๊ด๋ฆฌ๊ฐ ํธ๋ฆฌํ๋ค ์
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
12. ์๋ฒ ๋ชจ๋ํฐ๋ง
๋ฌธ์ ์ํฉ
- ์ด์ ์๋ ๋ชจ๋ํฐ๋ง ๋๊ตฌ๊ฐ ์์ด ์ค์๊ฐ์ผ๋ก ์๋ฒ์ ์ํ๋ฅผ ํ์ธํ ์ ์์๋ค.
- ์๋ฒ์ ์ํ๋ฅผ ํ์ธํ๊ธฐ ์ํด ์๋ฒ์ ์ ์ํ์ฌ ๋ก๊ทธ๋ฅผ ํ์ธํด์ผ ํ๋ค.
๋ฌธ์ ํด๊ฒฐ
- ์๋ฒ์ ์ํ๋ฅผ ์ค์๊ฐ์ผ๋ก ํ์ธํ ์ ์์ด ์๋ฒ์ ์ํ๋ฅผ ๋น ๋ฅด๊ฒ ํ์ ํ ์ ์๋ค.
- ์ผ์ ๊ธฐ๊ฐ๋์์ ์๋ฒ ์ ๋ณด๊ฐ ์ ์ฅ๋์ด ์๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๋ฐ์์ ์ญ์ถ์ ํด๋ณผ ์ ์๋ค.
- ๋ค์ ๊ธ ๋งํฌ์์๋ ์ด๋ฅผ ํตํ์ฌ ์๋ฒ๊ฐ ๋ค์ด๋๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๊ธ ์ด๋ค!
์์ธ ๋ด์ฉ ๋งํฌ : (๊ธ ๋งํฌ)
๐ ์ ์ด ๊ธฐ์ ์ ์ฌ์ฉํ๋๊ฐ?
๋ณธ๋ฌธ ํ์ธ (๐ Click)
1. Querydsl
Spring Data JPA๊ฐ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํด์ฃผ๋ CRUD ๋ฉ์๋ ๋ฐ ์ฟผ๋ฆฌ ๋ฉ์๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๋๋ผ๋, ์ํ๋ ์กฐ๊ฑด์ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ธฐ ์ํด์๋ ํ์ฐ์ ์ผ๋ก JPQL์ ์์ฑํ๊ฒ ๋ฉ๋๋ค. ๊ฐ๋จํ ๋ก์ง์ ์์ฑํ๋๋ฐ ํฐ ๋ฌธ์ ๋ ์์ผ๋, ๋ณต์กํ ๋ก์ง์ ๊ฒฝ์ฐ ๊ฐํ์ด ํฌํจ๋ ์ฟผ๋ฆฌ ๋ฌธ์์ด์ด ์๋นํ ๊ธธ์ด์ง๋๋ค. JPQL ๋ฌธ์์ด์ ์คํ ํน์ ๋ฌธ๋ฒ์ ์ธ ์ค๋ฅ๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ, ์ ์ ์ฟผ๋ฆฌ๋ผ๋ฉด ์ดํ๋ฆฌ์ผ์ด์ ๋ก๋ฉ ์์ ์ ์ด๋ฅผ ๋ฐ๊ฒฌํ ์ ์์ผ๋ ๊ทธ ์ธ๋ ๋ฐํ์ ์์ ์์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด ์ฃผ๋ ๊ฒ์ด Querydsl์ด๊ธฐ์ Querydsl์ ๋์ ํ์ต๋๋ค. Querydsl ๋์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ์ ์ด์ ์ ์ป์์ต๋๋ค.
- ๋ฌธ์๊ฐ ์๋ ์ฝ๋๋ก ์ฟผ๋ฆฌ๋ฅผ ์์ฑํจ์ผ๋ก์จ, ์ปดํ์ผ ์์ ์ ๋ฌธ๋ฒ ์ค๋ฅ๋ฅผ ์ฝ๊ฒ ํ์ธํ ์ ์๋ค.
- ์๋ ์์ฑ ๋ฑ IDE์ ๋์์ ๋ฐ์ ์ ์๋ค.
- ๋์ ์ธ ์ฟผ๋ฆฌ ์์ฑ์ด ํธ๋ฆฌํ๋ค.
- ์ฟผ๋ฆฌ ์์ฑ ์ ์ ์ฝ ์กฐ๊ฑด ๋ฑ์ ๋ฉ์๋ ์ถ์ถ์ ํตํด ์ฌ์ฌ์ฉํ ์ ์๋ค.
2. Flyway
dev, local ํ๊ฒฝ์์๋ ๋จ์ํ ddl์ create-drop ๋๋ update ์ต์
์ ์ฌ์ฉํ๊ณ ์์๊ธฐ์ DB์ ๋ํด ๊ณ ๋ฏผํ ํ์๊ฐ ์์์ต๋๋ค.
ํ์ง๋ง ์ด์ํ๊ฒฝ์์๋ ddl์ validate ๋๋ none ์ต์
์ ์ฌ์ฉํด์ผํ๊ธฐ ๋๋ฌธ์ ์ด๊ธฐ์๋ DB script๋ฅผ ๋ฝ์์ ๋ณ๋๋ก ๊ด๋ฆฌ๋ฅผ ํ์ต๋๋ค.
์ดํ ๊ธฐ๋ฅ์ด ์ถ๊ฐ๋๋ฉด์ script๊ฐ ๋ณ๊ฒฝ๋๋ ์ผ์ด ๋น๋ฒํด์ก๊ณ , ๋งค๋ฒ ์ผ์ผ์ด ์คํฌ๋ฆฝํธ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ์ด ๋ฒ๊ฑฐ๋ก์ธ ๋ฟ ์๋๋ผ ์ค์ํ๊ธฐ ๋ฑ ์ข์ ๋ถ๋ถ์ด๋ผ Flyway๋ฅผ ๋์
ํ์ฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ์๊ด๋ฆฌ๋ฅผ ์งํํ์ต๋๋ค.
์ถ๊ฐ๋ก ์ ์ ์๊ฐ์ ์ด์ ์
- ํ์ ์ ํ์์ด ddl์ ์ฝ๋๋ฆฌ๋ทฐ๋ฅผ ํ๊ธฐ ๋งค์ฐ ํธํ๋ค.
- ๋ด๊ฐ ์์ฑํ ddl์ด ์ ์์ ์ผ๋ก ์ถ๊ฐ๋๋ค, ์ฆ ๋ณต๋ถ์ด๋ ํ์ดํ ํ๋ค ๋๋ ํด๋จผ์๋ฌ ๋ฑ์ ๋ฐฉ์งํ ์ ์๋ค.
โฐ ํ์ ๋ฐฉ์ - Jira
๋ณธ๋ฌธ ํ์ธ (๐ Click)
์ ํฌ ์ฟ ๋งํ์ ํ์ ๋ฐฉ์์ผ๋ก Jira๋ฅผ ์ฌ์ฉํ์ต๋๋ค.
๊ตฌํํด์ผํ ํฐ ๊ธฐ๋ฅ๋ค์ ์ํฝ์ผ๋ก ์ ์ํ์ฌ ์ผ์ ์ ์ค์ ํ๊ณ ํ๋์ ์ํฝ์ ํ์ํ ๊ธฐ๋ฅ๋ค์ธ task๋ฅผ ์ธ์ธํ๊ฒ ๋๋์์ต๋๋ค.
์นธ๋ฐ๋ณด๋๋ฅผ ํตํด task๋ค์ ๊ฐ๋ฐํด์ผํ ๋ชจ๋ ๊ธฐ๋ฅ๋ค, ์ด๋ฒ์ฃผ์ ๊ฐ๋ฐํด์ผํ ๊ธฐ๋ฅ, ๊ฐ๋ฐ ์งํ์ค, ๊ฐ๋ฐ ์๋ฃ๋ ์นธ์ผ๋ก ์ฎ๊ธฐ๋ฉด์ ํ๋์ ๋ณผ ์ ์๋๋ก ์งํํ์ต๋๋ค.
์คํ๋ฆฐํธ๋ 1์ฃผ์ผ ๋จ์๋ก ์ค์ ํ์ฌ Jira ๋ด Confluence์์ ์คํ๋ฆฐํธ ์ฃผ๊ธฐ๋์ ์งํํด์ผํ ๊ธฐ๋ฅ๋ค์ ์ ์ํ๊ณ ๋ง์๊ฐ์ง๊ณผ ์คํ๋ฆฐํธ๋ฅผ ๋ง์น ํ ํ๊ณ ๋ฅผ ์์ฑํ๋ ๋ฐฉ์์ผ๋ก ์คํ๋ฆฐํธ๋ฅผ ์งํํ์ต๋๋ค.