VO(Value Object), ์ฐ๋ฆฌ๋ ์ ๊ทธ๋ฆฌ๊ณ ์ด๋ป๊ฒ ์ฐ๊ณ ์๋๊ฐ
- #VO
- #DTO
- #frontend
- #FE
- #DDD
์๋ ํ์ธ์ ๋ ธ๋จธ์ค ํ๋ก ํธ์๋ ๊ฐ๋ฐ์ ๊น๋ฏผ์ฃผ์ ๋๋ค.
์ด๋ฒ ๊ธ์์ ์ ํฌ ํ์ด VO๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๊ณ ์๋์ง ์ดํด๋ณด๊ณ , ํ์ฌ ์ฌ์ฉ ๋ฐฉ์์์ ๋ฐ๊ฒฌํ ๋ฌธ์ ์ ๊ฐ์ ๋ฐฉํฅ์ ๋ํด ์ด์ผ๊ธฐํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
์ด ๊ธ์์ ๋งํ๋ VO๋ DDD์์ ์ ์ํ๋ Value Object๋ฅผ ๊ทธ๋๋ก ์๋ฏธํ๋ ๊ฒ์ด ์๋๋ผ, ์ ํฌ ํ์์ API ์๋ต ๋ฐ์ดํฐ๋ฅผ ๋๋ฉ์ธ์์ ์ฌ์ฉํ๋ ํํ๋ก ๋ณํํ๊ณ ๊ด๋ จ ๋ก์ง์ ์บก์ํํ๊ธฐ ์ํด ์ฌ์ฉํ๋ ๋ชจ๋ธ ํด๋์ค๋ฅผ ์๋ฏธํฉ๋๋ค.
๋ฐ๋ผ์ ์ด ๊ธ์์๋ ๋จผ์ DDD์์ ๋งํ๋ VO์ ์ ํฌ ํ์ VO๊ฐ ์ด๋ป๊ฒ ๋ค๋ฅธ์ง ์ดํด๋ณด๊ณ , ํ์ฌ์ ์ฌ์ฉ ๋ฐฉ์๊ณผ ํจ๊ป ๊ฐ์ ํ ์ ์๋ ๋ฐฉํฅ์ ์ด์ผ๊ธฐํด๋ณด๋ ค๊ณ ํฉ๋๋ค.
1. VO๋?
DDD์์ ๋งํ๋ Value Object
DDD์์ Value Object๋ ๊ณ ์ ํ ์๋ณ์๋ณด๋ค ๊ฐ ์์ฒด๋ก ์๋ฏธ์ ๋์ผ์ฑ์ ๊ฐ์ง๋ ๊ฐ์ฒด๋ฅผ ์๋ฏธํฉ๋๋ค. ๋ํ์ ์ผ๋ก Money, Address, Date Range ๋ฑ์ด ์์ต๋๋ค. ๋ํ ์ผ๋ฐ์ ์ผ๋ก ๋ถ๋ณ์ฑ์ ๊ฐ์ง๋ฉฐ, ํด๋น ๊ฐ๊ณผ ๊ด๋ จ๋ ๊ท์น์ด๋ ํ๋์ ๊ฐ์ฒด ์์ ์บก์ํํ ์ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ์ฐ๋ฆฌ๊ฐ ์ฌ์ฉํ๋ VO๋?
์ ํฌ ํ์์๋
OptionVo,ManagerVo์ ๊ฐ์ด API ์๋ต ๋ฐ์ดํฐ๋ฅผ ํ๋ก ํธ์๋์์ ์ฌ์ฉํ๋ ํํ๋ก ๋ณํํ๊ณ , ํ์ ๋ณํ์ด๋ ํ๋ ๋งคํ, ํ์๊ฐ ๊ณ์ฐ ๋ฑ์ ๋ก์ง์ ํจ๊ป ์บก์ํํ๋ ํด๋์ค๋ฅผVO๋ผ๊ณ ๋ถ๋ฅด๊ณ ์์ต๋๋ค.
์ด๋ ๊ฒ ๋ณด๋ฉด ํ์ฌ ์ ํฌ ํ์ VO๋ DDD์์ ๋งํ๋ Value Object์ ๋์ผํ ๊ฐ๋ ์ ์๋๋๋ค. ์คํ๋ ค API DTO์ ๋๋ฉ์ธ ๋ชจ๋ธ ์ฌ์ด์ ๋ณํ ์ญํ ๊ณผ ๋๋ฉ์ธ ๋ก์ง์ ์ผ๋ถ๋ฅผ ํจ๊ป ๋ด๋นํ๊ณ ์์ต๋๋ค.
2. ์ฐ๋ฆฌ ํ์ด VO๋ฅผ ์ฐ๋ ๋ฒ
ํ์ ๋ณํ
API์์ ๋ฌธ์์ด์ด๋ ์ซ์๋ก ์ ๋ฌ๋๋ ๊ฐ์ ํ๋ก ํธ์๋์์ ์ฌ์ฉํ๋ ๋๋ฉ์ธ ํ์ ์ผ๋ก ๋ณํํฉ๋๋ค.
๋ฌธ์์ด/์ซ์๋ก ์ ๋ฌ๋๋ ๊ธ์ก์ Decimal๋ก ๋ณํํด ๊ธ์ก ์ฐ์ฐ์ด ํ์ํ ๊ณณ์์ ์ผ๊ด๋ ํ์
์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ํฉ๋๋ค.
this.addPrice = new Decimal(response.addPrice);
API ํ๋ โ ๋๋ฉ์ธ ํ๋ ๋ณํ
API์ ํ๋๋ช ๊ณผ ํ๋ก ํธ์๋์์ ์ฌ์ฉํ๋ ํ๋๋ช ์ด ๋ค๋ฅผ ๊ฒฝ์ฐ VO์์ ์ด๋ฅผ ๋ณํํฉ๋๋ค.
์๋ฅผ ๋ค์ด API์์๋ maxCountPerUser๋ผ๋ ์ด๋ฆ์ผ๋ก ์ ๋ฌ๋๋ ๊ฐ์ ๋๋ฉ์ธ์์๋ maxCount๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ํน์ ์ฌ๋ฌ ํ๋๋ฅผ ์กฐํฉํด ์๋ก์ด ๊ฐ์ ๋ง๋ญ๋๋ค.
Option.voํ์ผ์ ์์๋ก ๋ณด๊ฒ ์ต๋๋ค.
export class OptionVo {
id: number;
name: string;
addPrice: Decimal;
maxCount?: number;
// ...
static from(response: GetGoodsOptionsResponse) { return new OptionVo(response); }
constructor(response: GetGoodsOptionsResponse) {
this.id = response.id;
this.addPrice = new Decimal(response.addPrice);
this.maxCount = response.maxCountPerUser; // API ํ๋๋ช
โ ๋๋ฉ์ธ ํ๋๋ช
// ...
}
}
์ปดํฌ๋ํธ ์
์ฅ์์๋ option.addPrice.plus(goods.price)์ฒ๋ผ ๋ฐ๋ก ์ฐ์ฐํ๋ฉด ๋๊ณ , new Decimal(...)์ด๋ API ํ๋๋ช
๋ ์ ๊ฒฝ ์ธ ํ์๊ฐ ์์ต๋๋ค. ๊ฒฐ๊ตญ VO๋ฅผ ํตํด API ์๋ต์ ๋ํ ๋ณํ ๋ก์ง์ ํ ๊ณณ์์ ๊ด๋ฆฌํ๊ณ , ์ปดํฌ๋ํธ์์๋ ํ๋ก ํธ์๋ ๋๋ฉ์ธ์ ๋ง๊ฒ ๋ณํ๋ ๊ฐ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋คํ์ฑ ํํ
์ฅ๋ฐ๊ตฌ๋ ์ํ์ ์ผ๋ฐ ์ํ๊ณผ ๋ฒ๋ค ์ํ์ ๋ฐ๋ผ ํ์ํ ๋ฐ์ดํฐ์ ๋์์ด ๋ฌ๋ผ์ง๋๋ค. ์ ํฌ ํ์์๋ ์ด๋ฅผ BaseCartGoodsVo๋ฅผ ์์ํ CartGoodsVo์ CartBundleVo๋ก ๋๋์ด ํํํ๊ณ ์์ต๋๋ค.
response.goods.isBundle ? CartBundleVo.from(...) : CartGoodsVo.from(...)
์์ฑ ์์ - ์ฟผ๋ฆฌ์์ VO๋ก ๋ณํ
ํ์ฌ ์ ํฌ ํ์์๋ API ์๋ต์ ์ฟผ๋ฆฌ์์ VO๋ก ๋ณํํ ๋ค ์ปดํฌ๋ํธ์ ์ ๋ฌํ๋ ๋ฐฉ์์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
queryFn: () => getManagers(query).then((response) => response.managers.map(ManagersVo.from))
์ปดํฌ๋ํธ์์ vo์ ์ฌ์ฉ๋ฒ
VO๋ฅผ ๊ฑฐ์น ์ดํ ์ปดํฌ๋ํธ์์๋ API ์๋ต์ ๊ตฌ์ฒด์ ์ธ ํํ๋ ํ์ ๋ณํ ๊ณผ์ ์ ์ ํ์ ์์ด, ๋๋ฉ์ธ์์ ์ฌ์ฉํ๋ ๊ฐ๊ณผ ์์ฑ์ ๊ทธ๋๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค.
amount: order.price.toNumber(),
const isMembership = orderGoodsItem.isMembership;
์์น์ ๋ค์ด๋ฐ
src/vo/ย ์๋ ๋๋ฉ์ธ๋ณ๋ก ์ ๋ฆฌํด ์ค์์ง์คํํด์ ์ฌ์ฉํ๊ฑฐ๋src/domains/*/*/vo/์ฒ๋ผ ๊ฐ ๋๋ฉ์ธ ํด๋์์ ํจ๊ป ๋๋ ๋ฐฉ์์ผ๋ก ์ฌ์ฉํฉ๋๋ค. ํ์ฌ ์ ํฌ ํ์ ํ๋ก์ ํธ ํน์ฑ์ ๋ฐ๋ผ ์กฐ๊ธ ์์ดํ๊ฒ ์ฌ์ฉ์ค์ ๋๋ค.- ํด๋์ค๋
static from(response)ํฉํ ๋ฆฌ ๋ฉ์๋์constructor(response)๋ฅผ ์ฌ์ฉํด API ์๋ต์ VO๋ก ๋ณํํ๋ ํํ๋ฅผ ์ฃผ๋ก ์ฌ์ฉํฉ๋๋ค.
3. DTO์ ์ฐ๋ฆฌ์ VO
์ฌ๊ธฐ์ ํ ๊ฐ์ง ๊ตฌ๋ถํ ํ์๊ฐ ์์ต๋๋ค. API ์๋ต๊ฐ์ ๋ด๋ถ์์ ํ์ํ ํํ๋ก ๋ณํํ๋ค๋ ์ค๋ช ๋ง ๋ณด๋ฉด DTO์ VO์ ์ญํ ์ด ๋น์ทํด ๋ณด์ผ ์ ์์ต๋๋ค.
DTO๊ฐ ๊ณ์ธต์ด๋ ์์คํ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํ๊ธฐ ์ํ ๊ตฌ์กฐ๋ผ๋ฉด, VO๋ ๋๋ฉ์ธ์์ ํด๋น ๊ฐ์ด ์ด๋ค ์๋ฏธ์ ๊ท์น์ ๊ฐ์ง๋์ง๋ฅผ ํํํ๋ ๋ฐ ์ด์ ์ด ์์ต๋๋ค.
ํ์ฌ ์ ํฌ ํ์ VO๋ API ์๋ต์ ๋๋ฉ์ธ์์ ์ฌ์ฉํ๋ ํํ๋ก ๋ณํํ๋ ์ญํ ๊ณผ ๋๋ฉ์ธ ๊ด๋ จ ๋ก์ง์ ์บก์ํํ๋ ์ญํ ์ด ํจ๊ป ์กด์ฌํฉ๋๋ค. ๋ฐ๋ผ์ DTO์ VO์ ์ญํ ์ด ์ผ๋ถ ์์ฌ ์๋ ํํ๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
4. ํ์ฌ VO ์ฌ์ฉ ๋ฐฉ์์์ ๋ฐ๊ฒฌํ ๋ฌธ์
์กฐ์ฌํ๋ฉด์ VO๋ฅผ ๋ ์ ํ์ฉํ ์ ์์๋ ์ง์ ๋ค์ด ๋ณด์์ต๋๋ค.
โ VO์์ ์ ๊ณตํ๋ ํ์๊ฐ์ ์ปดํฌ๋ํธ์์ ๋ค์ ๊ณ์ฐํ๊ณ ์๋ค
StatisticsMembershipCount.vo.ts์๋ ํ์ฌ ์ ์ผํ๊ฒ ํ์๊ฐ์ getter๋ก ์ ๊ณตํ๋ ํจํด์ด ์์ต๋๋ค.
get existingJoinCount() { return this.totalJoinCount - this.newJoinCount; }
๊ทธ๋ฐ๋ฐ ์ค์ ์ฌ์ฉ์ฒ์์๋ ํด๋น getter๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ปดํฌ๋ํธ์์ ๋ค์ totalJoinCount - newJoinCount๋ฅผ ๊ณ์ฐํ๊ณ ์์ต๋๋ค.
์ฆ, VO์์ ์ด๋ฏธ ์ ์ํ ๊ณ์ฐ ๋ก์ง์ ์ปดํฌ๋ํธ์์ ๋ค์ ๊ตฌํํ๊ณ ์๋ ์ํฉ์ ๋๋ค. VO์ ํ์๊ฐ์ getter๋ก ์ ์ํ๋ค๋ฉด, ์ฌ์ฉ์ฒ์์๋ ํด๋น getter๋ฅผ ์ฌ์ฉํ๋๋ก ์์ ํด์ผ ํ์๊ฐ์ ๋ํ ๊ณ์ฐ ๋ก์ง์ VO์์ ์ผ๊ด๋๊ฒ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
๋ค๋ง ๋ชจ๋ ๊ณ์ฐ ๋ก์ง์ VO๋ก ์ฎ๊ฒจ์ผ ํ๋ค๋ ์๋ฏธ๋ ์๋๋๋ค. ๋๋ฉ์ธ์์ ์๋ฏธ๋ฅผ ๊ฐ์ง๋ ๊ฐ์ด๋ ๊ท์น์ด๋ผ๋ฉด VO์์ ๊ด๋ฆฌํ๊ณ , ๋จ์ํ ํ๋ฉด์ ๊ตฌ์ฑํ๊ธฐ ์ํ ๊ณ์ฐ์ด๋ผ๋ฉด ์ปดํฌ๋ํธ์์ ์ฒ๋ฆฌํ๋ ๋ฑ ๊ธฐ์ค์ ๊ตฌ๋ถํ ํ์๊ฐ ์์ต๋๋ค. ๊ตฌ๋ถ์ ๊ธฐ์ค์ ํ๋ด ๋ ผ์๊ฐ ํ์ํด๋ณด์ ๋๋ค
โก ๋ ์ง ํฌ๋งทํ ๋ก์ง์ ์ฑ ์ ๋ฒ์๊ฐ ๋ช ํํ์ง ์๋ค
ํ์ฌ ์ ํฌํ์ ์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด dayjs๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ์ฌ๋ฌ ์ปดํฌ๋ํธ์์ ๊ฐ๊ฐ ๋ ์ง ํฌ๋งทํ
์ ์ฒ๋ฆฌํ๊ณ ์์ต๋๋ค.
๊ธ์ก์ ๊ฒฝ์ฐ Decimal์ ์ฌ์ฉํด ์ฐ์ฐ์ ํ์ํ ํ์
์ VO์์ ๊ด๋ฆฌํ๊ณ ์์ต๋๋ค. ๋ฐ๋ฉด ๋ ์ง์ ๊ฒฝ์ฐ startAt, endAt ์์ฒด๋ฅผ VO์์ ๊ด๋ฆฌํ๋ ๊ฒ๊ณผ ํ๋ฉด์ ํ์ํ ํ์๊น์ง VO์์ ๊ฒฐ์ ํ๋ ๊ฒ์ ๋ค๋ฅธ ๋ฌธ์ ๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
๋ ์ง์ ์ ํจ๊ธฐ๊ฐ์ด๋ ๊ธฐ๊ฐ ๊ณ์ฐ์ฒ๋ผ ๋๋ฉ์ธ ์๋ฏธ๋ฅผ ๊ฐ๋ ๋ก์ง์ VO์์ ๊ด๋ฆฌํ ์ ์์ง๋ง, ๋จ์ ํ์ ํ์๊น์ง VO์ ์ฑ ์์ผ๋ก ๋ณผ ๊ฒ์ธ์ง๋ ํ ์ฐจ์์ ๊ธฐ์ค์ด ํ์ํฉ๋๋ค.
โข ๋์ผํ ๋๋ฉ์ธ ์์์๋ VO ์ ์ฉ ๊ธฐ์ค์ด ์ผ๊ด๋์ง ์๋ค
partner ํ๋ก์ ํธ๋ฅผ ์ดํด๋ณด๋ฉด ๋์ผํ ๋๋ฉ์ธ ์์์๋ VO๋ฅผ ์ ์ฉํ๋ ๋ฐฉ์์ด ์๋ก ๋ค๋ฆ ๋๋ค.
// useGetManager.ts, useGetManagers.ts โ VO๋ก ๊ฐ์
queryFn: () => getManager(id).then((response) => ManagerVo.from(response))
// useGetPermissionChannels.ts, useGetPermissionArtis.ts ๋ฑ โ VO ์์ด raw ๊ทธ๋๋ก
select: (data) => data.channels
๊ฐ์ ๋๋ฉ์ธ์์ ์ด๋ค ๋ฐ์ดํฐ๋ VO๋ก ๋ณํํ๊ณ , ์ด๋ค ๋ฐ์ดํฐ๋ API ์๋ต์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ํํ์ ๋๋ค.
์ด๋ฐ ๋ถ์ผ์น ๋๋ฌธ์ ํ ํ์์์ API ์๋ต์ ๊ธฐ๋ณธ์ ์ผ๋ก VO๋ก ๊ฐ์ผ๋ค๋ ์ปจ๋ฒค์ ์ ์ ํ๊ณ , ์ ์ฝ๋๋ ๊ทธ ์ด์ ์ ์์ฑ๋ ๋ ๊ฑฐ์์ ๋๋ค. ๋จ์ ์ผ์ ์ด ์ฝ๋๋ค์ ์ปจ๋ฒค์ ์ ๋ง๊ฒ ์ ๋ฆฌํ๋ ๊ฒ์ ๋๋ค.
5. ๊ฐ์ ๋ฐฉํฅ ์ ์
- VO ์ปจ๋ฒค์
๋ฌธ์ํ์ ๋ ๊ฑฐ์ ์ ๋ฆฌ
โAPI ์๋ต์ ๊ธฐ๋ณธ์ ์ผ๋ก VO๋ก ๊ฐ์ผ๋คโ๋ ์ปจ๋ฒค์
์
CLAUDE.md๋ ์ฝ๋ ๋ฆฌ๋ทฐ ์ฒดํฌ๋ฆฌ์คํธ์ ๋ช ์ํ๊ณ , ์์ง ๋ฐ์๋์ง ์์ ์ฝ๋๋ฅผ ์์ฐจ์ ์ผ๋ก ์ ๋ฆฌํฉ๋๋ค. - ๋ ์งยท๊ธ์ก์ ๋๋ฉ์ธ ๋ก์ง๊ณผ ํํ ๋ก์ง ๊ตฌ๋ถ
๊ธ์ก์ ๊ณ์ฐ์ ํ์ํ
Decimal, ๋ ์ง์ ์ ํจ๊ธฐ๊ฐยท๊ธฐ๊ฐ ๊ณ์ฐ ๋ฑ ๋๋ฉ์ธ ์๋ฏธ๋ฅผ ๊ฐ๋ ๋ก์ง์ VO์์ ๊ด๋ฆฌํ ์ ์์ง๋ง, ํ๋ฉด ํ์๋ฅผ ์ํ ํฌ๋งทํ ์ ๋ณ๋์ ํํ ์์ญ์์ ๊ด๋ฆฌํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์ต๋๋ค. ์ฌ๋ฌ ํ๋ก์ ํธ์์ ๊ณตํต์ผ๋ก ์ฌ์ฉํ๋ ๊ฐ๊ฒฉ ํฌ๋งทํ ๋ก์ง์ ๊ณต์ฉ ํจํค์ง๋ก ๋ถ๋ฆฌํด ํ๋ก์ ํธ๋ณ ์ค๋ณต ๊ตฌํ์ ์ค์ผ ์ ์์๊ฒ ๊ฐ์ต๋๋ค. - getter ์ถ๊ฐ ์ ์ฌ์ฉ์ฒ๊น์ง ํจ๊ป ๋ฆฌํฉํ ๋ง ์๋ก์ด getter๋ฅผ ์ถ๊ฐํ ๋ ๊ธฐ์กด์ ๋์ผํ ๊ฐ์ ์ง์ ๊ณ์ฐํ๊ณ ์๋ ์ฌ์ฉ์ฒ๊ฐ ์๋์ง ํจ๊ป ํ์ธํด VO์ ์ ์๋ ๊ณ์ฐ ๋ก์ง์ ์ค๋ณต ๊ตฌํ์ ๋ฐฉ์งํฉ๋๋ค.
- VO๋ผ๋ ์ด๋ฆ๊ณผ ์ค์ ์ญํ ์ฌ์ด์ ๊ฐ๊ทน ํ์ฌ ์ ํฌ ํ์ VO๋ DDD์ Value Object์ ๋ฌ๋ฆฌ API ์๋ต์ ๋๋ฉ์ธ ํํ๋ก ๋ณํํ๋ ์ญํ ๊ณผ ๋๋ฉ์ธ ๋ก์ง์ ํจ๊ป ๋ด๋นํ๊ณ ์์ต๋๋ค. ํ๋ก์ ํธ์ ํ์คํ ๋ฆฌ๋ฅผ ๋ชจ๋ฅด๋ ์ฌ๋์ด OptionVo์ ๊ฐ์ ์ด๋ฆ๋ง ๋ดค์ ๋, ์ผ๋ฐ์ ์ผ๋ก ์๊ณ ์๋ Value Object๋ฅผ ๊ธฐ๋ํ ๊ฐ๋ฅ์ฑ์ด ๋์ต๋๋ค. ๋ฐ๋ผ์ ํ์ฌ์ VO๋ผ๋ ๋ค์ด๋ฐ์ด ์ค์ ์ญํ ์ ์ถฉ๋ถํ ์ ๋ฌํ๊ณ ์๋์ง ๊ฒํ ํด๋ณผ ํ์๊ฐ ์๋ค๊ณ ์๊ฐํฉ๋๋ค. ๋ค๋ง ์ด๋ฆ์ ๋ณ๊ฒฝํ๋ ๊ฒ๋ณด๋จ ํ์ฌ VO๊ฐ ์ด๋ค ์ฑ ์์ ๊ฐ์ ธ์ผ ํ๋์ง๋ฅผ ๋ช ํํ๊ฒ ์ ์ํ๋ ๊ฒ์ด ๋ ์ค์ํฉ๋๋ค.
๋ง์น๋ฉฐ
๋น์ฐํ๊ฒ ์ฐ๊ณ ์๋ VO๋ฅผ ๋ค์ ๋ค์ฌ๋ค๋ณด๋, DDD์ ์ ์์ ์ผ์นํ๋์ง๋ณด๋ค ์ง๊ธ ์ฐ๋ฆฌ VO๊ฐ ์ด๋ค ์ญํ ์ ํ๊ณ ์๊ณ ๊ทธ ์ญํ ์ ๋ง๋ ๊ธฐ์ค์ ๊ฐ์ง๊ณ ์ฐ์ด๋์ง๊ฐ ๋ ์ค์ํ๋ค๋ ์๊ฐ์ด ๋ค์์ต๋๋ค.
์ ํฌ ํ์ VO๋ DDD์ Value Object์ ๋์ผํ ํํ๋ ์๋์ง๋ง ๋๋ฆ์ ๋ช ํํ ์ญํ ์ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํ ์์์ ๊ทธ ์ญํ ๊ณผ ์ฌ์ฉ ๊ธฐ์ค์ด ํฉ์๋์ด ์๋ค๋ฉด, ์ด๋ฆ์ด ๋ฌด์์ด๋ ์ถฉ๋ถํ ์ ์ฉํ ๋๊ตฌ๊ฐ ๋ ์ ์๋ค๊ณ ์๊ฐํฉ๋๋ค.
์ด๋ฒ ๊ธ์ ๊ณ๊ธฐ๋ก ๊ทธ ๊ธฐ์ค์ ์กฐ๊ธ ๋ ๋ช ํํ๊ฒ ๋ค๋ฌ์ด๊ฐ๋ ค๊ณ ํฉ๋๋ค.
์ฝ์ด์ฃผ์ ์ ๊ฐ์ฌํฉ๋๋ค.