๐ย ๋ฏ์ด๋ณด๊ธฐ 1์ผ์ฐจ - ์์์ build.gradle ๋ถํฐ?(feat. Entity vs Domain)
Table of contents
์์
์ผ๋จ ํธ์ํฐ์ ์คํ ์์ค ๋ฏ์ด๋ณด๊ฒ ์ต๋๋ค! ์ค๋ก์ธ๋ถํฐ ํ ๊ฑฐ์์! ๋ผ๊ณ ์ง๋ฌ์ ์ค๋ ์ค๋ก์ธ ์์ค ์ฝ๋๋ฅผ ๋ค์ด ๋ฐ์๋ค. ๋ฉ์ฒญํ๊ฒ ์๋ฒ ํ์ผ ์ธํ ๋ฆฌ์ ํ ๊บผ๋ฒ์ ์ฌ๋ ค์ ์ ์ฒด ๋ค ๋ค์ด ๋ฐ๋๋ฐ๋ง 20๋ถ ๊ฑธ๋ ธ๋ค.
๋ด ๋
ธํธ๋ถ์ด ๋ฌธ์ ์ธ๊ฐ?
์ฌํผ ๋ชจ๋ฅด๋ ์ฝ๋๋ฅผ ๋ณผ ๋ build.gradle ๋ถํฐ ๋ณด๋๊ฒ ์ต๊ด์ด๋ผ ์ฌ๊ธฐ๋ถํฐ ์์ํ๋ค.
์์๋ถํฐ Distributed under CC BY-NC-SA
๋ผ๋ ๋ฌธ๊ตฌ๊ฐ ๋์ ๋์๋๋ฐ ๋น์ฐํ ๋ชฐ๋๊ธฐ ๋๋ฌธ์ ๊ฒ์์ ํด๋ดค๋๋ ๋ผ์ด์ผ์ค ๊ด๋ จ๋ ๋ฌธ๊ตฌ์๋ค. ์ค ๋ญ๊ฐ ์คํ ์์ค๋ ์ด๋ ๊ฒ ๊ผผ๊ผผํด์ผ ํ๋ ๊ฑด๊ฐ ์ถ์๋ค.
- This license lets others remix, tweak, and build upon your work non-commercially, as long as they credit you and license their new creations under the identical terms.
- ์ด ๋ผ์ด์ผ์ค๋ ์์ ๋ชฉ์ ์ด ์๋๋ฉด ๋ค๋ฅธ ์ฌ๋์ด ์์ ํด๋ ์๊ด ์๋ค~ ๋ผ๋ ๊ฑฐ ๊ฐ๋ค. ๋์ผ ์กฐ๊ฑด์ด๋ฉด ์๋ก์ด ์ฐฝ์๋ฌผ์๋ ๋ผ์ด์ผ์ค๋ฅผ ๋ฐ๋ก ๋ถ์ฌํ ์ ์๋ค๋ ๊ฑด๊ฐ? ์ฌํผ ์ถ์ฒ ์์ ๋ ์์ธํ ๊ฑด ๋ณด์ธ์.
๊ทธ๋ค์ ๋ณด๊ฒ ๋ ๊ฒ์ jvm 17๊ณผ kotlin version 1.6.10 ์ด๋ผ๋ ๊ฑด๋ฐ 1.6?
๊ฐ์๊ธฐ ๋๋ ๋ช ๋ฒ์ ์ฐ์ง ํ๊ณ ๊ถ๊ธํด์ ธ์ ๋ด ์ฝ๋ ๋ณด๋ค๊ฐ ์ ฏ๋ธ๋ ์ธ ์ฝํ๋ฆฐ ๋ธ๋ก๊ทธ๋ฅผ ๊ฐ๋๋ฐ 1.6.0 ๋ฆด๋ฆฌ์ฆ๊ฐ 2021๋ 12์ ์ค์์ด๋ค. ์์ง 3๊ฐ์ ๋ฐ์ ์์ง๋ ๊ฑฐ ๊ฐ์๋ฐ ์์ฒญ ์ต์ ๋ฒ์ ์ฐ๋ค? ์ถ์๋ค. ๊ทธ๋ฆฌ๊ณ ์ข ๋ ์๊ฐํด๋ณด๋ ์ ์ด๊ฑฐ ์ธํ ๋ฆฌ์ ์ด ๊ธฐ๋ณธ์ผ๋ก ๋ง๋ค๋ฉด ์ฝํ๋ฆฐ ์ต์ ๋ฒ์ ์ผ๋ก ๋๊ณ java 17 ์ค์ ํด์ ์ด๋ ๊ฒ ๋์๋ ์ถ์๋ค.(์๋๋ฉด ๋ด๊ฐ ์ต๊ทผ์ ๋ง๋ ๊ฒ
๊ทผ๋ฐ ๊ฒ์ํด๋ณด๋ฉด์ ์ ฏ๋ธ๋ ์ธ ๋ธ๋ก๊ทธ ์ฒ์ ๋ค์ด๊ฐ๋ดค๋๋ฐ ์ด๊ฒ๋ ๊ฐ์ก๊ณ ์ ๋ฆฌํ๋ฉด์ ๊ณต๋ถํ๋ ๊ธ ์ฐ๋ฉด ์์ฒญ๋ ๊ณต๋ถ๊ฐ ๋ ๊ฑฐ ๊ฐ๋ค. ์ฝํ๋ฆฐ ์ ๋ณด๋ ๋ค ์ฌ๊ธฐ ์์๊ตฌ๋!!
1.6.10 ์์ ๋ค๋ฅธ ๊ฑด ์ ๋ชจ๋ฅด๊ฒ ๊ณ Kover๋ผ๋๊ฒ ์๊ฒผ๋ค๊ณ ํ๋ค. ์ฝ๋ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ธก์ ํ๋ gradle plugin์ด๋ผ๋๋ฐ ๊ธฐ์กด์ jacoco๊ฐ gradle toolchain, ๋ฉํฐ ํ๋ซํผ ํ๋ก์ ํธ์์๋ ์์ ํ ํตํฉ๋์ง ์์ ์ด์๋ฅผ ํฝ์คํ๊ธฐ ์ํด์ ๋ง๋ค์๋ค๊ณ ํ๋ค. ์์ง ๊ฐ๋ฐ ์ด๊ธฐ ๋จ๊ณ๊ตฌ๋.
Kotlin + Coverage = Kover ์ธ๊ฑด๊ฐ!
์ด๊ฑฐ 2๊ฐ๋ ์ฒ์ ๋ณธ๋ค.
version_javax_inject = "1"
์๋ maven repository ๊ณต์ ํํ์ด์ง ๊ฐ๋ณด๋ ๊ตฌ๊ธ์์ ๋ง๋ ๊ฑฐ ๊ฐ๊ณ ์๋์ผ๋ก ์์กด์ฑ ์ฃผ์ ํด์ฃผ๋ ๊ฑด๊ฐ ๋ณด๋ค. ํ์ฌ ์ฝ๋ ์ด๋์ ์ฐ์๋์ง ๋์ค์ ๋ด๋ด์ผ์ง. ๋ด๊ฐ ๊ฒ์ํด์ ์์๋ด๋ ๊ฒ ๋ณด๋ค ๋น ๋ฅด๊ฒ ์ง
๋๋ ์ฒ์ ๋ต๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ธ๋ฐ ๊ตฌ์๋ฐ, ์คํ๋ง ๋น์ฆ์ ์ฐ์ด์ ๊ฑด์ง Artifacts using Javax Inject ์น๋ ์ฌ๋ฌ๊ฐ์ง๊ฐ ๋์ค๋ ๊ตฌ๋ง
JSR-330: Dependency Injection for Java Welcome to the home of JSR-330: Dependency Injection for Java.
์ ๋ญ๊ฐ ๋จ์ถํด์(?) ์ข๊ตฐ์!
version_jsr305 = "3.0.2"
jsr305๋ ์ฒ์ ๋ณด๋๋ฐ ์ปดํ์ผ ์์ ์ ์ ์ ์ผ๋ก ๋ฒ๊ทธ ์ก์ ์ค๋ค๊ณ ํ๋๋ฐ ์ด๊ฑฐ ์ด๋์ ์ฐ์์๊น ํํ
์คํธ ์ด๋ ธํ ์ด์ ์ด javax.validation์์ ๋ณด๋ ๊ฒ๊ณผ ๋น์ทํ๊ฒ ๋ณด์ด๋๋ฐ NonNull ๊ฐ์ ๊ฑฐ.
์ด๊ฑฐ ์ปดํ์ผ ํ ๋ ์ ๊ธฐ ์ด๋ ธํ ์ด์ ๋ถ์ ๊ฒ๋ค ๋ฐ์ดํฐ ์๋ํ๋๋ก ๋ด๊ณ ์๋์ง ๋ค ์ฒดํฌํด์ฃผ๋ ๋ณด๋ค. ์ด๊ฑฐ๋ ๋์ถฉ ๋ด๋ ๊ฝค ์ข์ ๊ฑฐ ๊ฐ๋ค!! ๋์ค์ ์ฌ์ฉํ๋ ์์ ์ข ๋ณด๊ณ ๊ฐ์ธ ํ๋ก์ ํธ์ ์จ๋ด์ผ์ง.
์ค๋์ ์ฌ๊ธฐ๊น์ง ํ๊ณ ๋ค๋ฅธ ๊ฑฐ ์ข ๋ค์ ธ๋ณผ๊น~? ํ๋ค๊ฐ ์ฌ๋ฐ๋ ๊ฑธ ๋ฐ๊ฒฌํ๋ค.
์ฌ๋ฐ๊ฒ ์ด๋ฐ ์ง๋ฌธ์ด ์๋ค!!!
// POINT: ์ด ํด๋์ค๋ฅผ data class ๋ก ์ ์ธํ๊ณ , equals / hashCode ๋ฅผ ์ญ์ ํด๋ ๋ฌธ์ ๊ฐ ์์๊น์?
// POINT: Entity ์ Domain Model ์ ์ฐจ์ด๋ ๋ญ๊น์?
api-core-infra-impl ์ชฝ domain.user ๋๋ ํ ๋ฆฌ ์์ UserEntity ์์ ๋ฌ๋ฆฐ ์ฌ๋ฐ๋ ์ฃผ์์ด ๋ฌ๋ ค ์์๋ค!
infra๋ผ๊ณ ์จ์๋๊ฒ JPA ๊ฐ์๊ฑฐ๋ ์ธ๋ถ ์๋น์ค, message ๊ด๋ จ์ธ๊ฐ ์ถ๊ธด ํ๋๋ฐ domain.user ๋ฐ repository๊ฐ ์์๋ค. ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ๊ฐ ๋ญ๊ฐ ์ ๊ธฐํ๋ฐ ์ ๋ ๊ฒ ๋๋ฉ์ธ๋ณ๋ก ๊ตฌ๋ถํ๋ ๊ฑด๊ฐ?
์ผ๋จ ์ฒซ ๋ฒ์งธ ํฌ์ธํธ์ ๋ํ ์๊ฐ์ ์ ์ด๋ณด์๋ฉด(์ฝํ๋ฆฐ 3๊ฐ์์ฐจ๋ผ ํ๋ฆด ์ ์์)
- data class ์์ฑํ๋ฉด ์์์ equals, hashCode ๊ฐ์๊ฑฐ ์์ฑ๋์ ์๊ด์ ์๋๋ฐ
- ๋ฌธ์ ๊ฐ ์ ๊ฒ JPA๋ ๊ฐ์ด ์ธ ๋ ์๋ฌ๊ฐ ๊ฝค ๋ฟ๋ฟ ํ๋ค. ์๋ฐฉํฅ ๋งตํ ํ์ ๋ toString() ๋๋ฌธ์ StackOverFlow ๋ ๋จ๊ณ , ๋ญ ์ด๋ฐ์ ๋ฐโฆ
- ๊ฒฐ๋ก ์ ์ญ์ ํด๋ ๋ฌธ์ ๋ ์์ผ๋ data class๋ฅผ ์ํฐํฐ๋ก ์ธ ๋ ๋ฐ์ํ ์ ์๋ side effect๊ฐ ์์ด์ ๊ผญ ์ ํฉํ์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค!
- ๊ทผ๋ฐ ์ง๊ธ ๋ณด๋๊น ์ด ํด๋์ค JPA๋ก ๋ง๋ Entity๊ฐ ์๋๊ตฌ๋!
- equals๋ hashCode ์๋ ์์ฑํด์ ๋น๊ตํด๋ณผ๊น.
// ์ด๊ฒ ์๋ ์๋ ์ฝ๋
override fun equals(other: Any?): Boolean =
if (other !is UserEntity) {
false
} else {
Objects.equals(id, other.id) &&
Objects.equals(uuid, other.uuid) &&
Objects.equals(nickname, other.nickname) &&
Objects.equals(profileImageUrl, other.profileImageUrl) &&
Objects.equals(deletedAt, other.deletedAt) &&
Objects.equals(createdAt, other.createdAt) &&
Objects.equals(updatedAt, other.updatedAt) &&
Objects.equals(version, other.version)
}
// ์ด๊ฒ ์ธํ
๋ฆฌ์ ์ด ๊ธฐ๋ฅ์ผ๋ก ๋ง๋ ๊ฑฐ!
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as UserEntity
if (id != other.id) return false
if (uuid != other.uuid) return false
if (deletedAt != other.deletedAt) return false
if (createdAt != other.createdAt) return false
if (version != other.version) return false
if (nickname != other.nickname) return false
if (profileImageUrl != other.profileImageUrl) return false
if (updatedAt != other.updatedAt) return false
return true
}
์ ์๋ ์์ฑํด์ ๋ง๋ ์ฝ๋๊ฐ ์๋์๋ค. !is ๋ฅผ ์ด ์ฝ๋ ์ฒ์ ๋ณธ๋ค.
Object์ equals๋ฅผ ์จ์ ๊ฐ์ ํ๋ํ๋ ๋น๊ตํ๋๊ตฌ๋.
Object ์์ equals ํ๊ณ ๋ค์ด๊ฐ๋ ์๋ ์ฝ๋๊ฐ ๋์ค๋๋ฐ ์ด๋ ๊ฒ ๋ณด๋๊น ๊ฐ์ ์ฝ๋๋ฅผ ๊ฐ๋ ์ฑ ์๊ฒ ๋ค์ ์ผ๊ตฌ๋ ์ถ๋ค.
public static boolean equals(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
// ์์ฑ๋์ด ์๋ ์ฝ๋
override fun hashCode(): Int {
return Objects.hash(
this.id,
this.uuid,
this.nickname,
this.profileImageUrl,
this.deletedAt,
this.createdAt,
this.updatedAt,
this.version
)
}
// ์ธํ
๋ฆฌ ์ ์ด ๊ธฐ๋ฅ์ผ๋ก ์๋ ์์ฑํ ์ฝ๋
override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + uuid.hashCode()
result = 31 * result + (deletedAt?.hashCode() ?: 0)
result = 31 * result + createdAt.hashCode()
result = 31 * result + version.hashCode()
result = 31 * result + nickname.hashCode()
result = 31 * result + profileImageUrl.hashCode()
result = 31 * result + updatedAt.hashCode()
return result
}
hashCode ๋ ๊ทธ๋ ๋ค! ์๋ Object์ hash๋ฅผ ์จ์ ๋ฐ๋ก ์์ฑํ ์ฝ๋์๋ค.
์๋์์ฑ๋ ์ฝ๋ result ๋ฐ๋ฅ๋ฐ๋ฅ ์จ ์์ด์ ์ง์ง ๊ผด๋ณด๊ธฐ ์ซ๋ค
Object.hash๋ก ํ ๋ฒ์ ๋ฌถ์ผ๋๊น ์์ฒญ ๊น๋ํ๋ค. ์ํ
์ค์ Object ์์ ์๋ hash()์ hashCode()๋ฅผ ํ๊ณ ๋ค์ด๊ฐ๋ result ๋๊ฐ์ด ์จ์ฃผ๋ ๊ฑฐ ๋ณด๋ ๊ธฐ๋ฅ์ ๋์ผํ๊ตฌ๋. ๋ hashCode ๊ตฌํํด๋ณธ ์ ์๋๋ฐ ํ ๋ฏ
์ผ๋จ ์๊ฐ์๋ data class๋ hashCode(), equals(), toString() ๋ฑ์ ์๋์ผ๋ก ์์ฑํด์ฃผ๋ ๋ฌธ์ ๋ ์์ง ์์๊น ์ถ๋ค.
2๋ฒ์งธ ํฌ์ธํธ๋ ์ํฐํฐ์ ๋๋ฉ์ธ์ ์ฐจ์ด์ ๋ํ ์ ์ธ๋ฐ.
ํฅ์ฌ๊ณ ๋ ์ํคํ ์ฒ๋ฅผ ํ์ตํ๋ฉด์ ๊ณต๋ถํ๋ ๋ถ๋ถ์ด๋ผ ์ ์ ๋ฆฌํด๋ณด์๋ฉด.
๋๋ฉ์ธ์ ์์ ๋น์ฆ๋์ค ๋ก์ง๋ง์ ํํํ๊ณ ์บก์ํ๋์ด์ ๊ธฐ๋ฅ์ ์ธ ์๊ตฌ์ฌํญ์ ๋ง๊ฒ ์ค๊ณ๋ฅผ ํ๋ค๊ณ ๋ณด๋ฉด ๋๊ณ
์ํฐํฐ๋ ์ธ๋ถ์ ์ธํ๋ผ์ ํด๋นํด์ ๋ด๋ถ ์์ญ์ธ ๋๋ฉ์ธ๊ณผ ๋ถ๋ฆฌํด์ ๊ตฌ์ฑํ๋ค.
์ต๊ทผ์ ๋๋ ์ด์์ฒด์ ์คํฐ๋์์ ๋๋ณด๋ค ์ ๋ฐฐ ๊ฐ๋ฐ์๋ถ๋ค์ด JPA ์ฐ๊ธฐ ์ซ๋ค ๊ผด๋ ๋ณด๊ธฐ ์ซ๋ค ์ด๋ฐ ์๊ธฐ ์์ฒญ ํ์ จ๋๋ฐ ๊ฒฐ๊ตญ DB์ ์์กด์ ์ด๊ฒ ๋๊ณ , JPA์ ์์กด์ ์ด๊ฒ ๋์ ๊ทธ ๋ถ๋ถ์์ ๋ฐ์ํ๋ ์ด์์ ์ง์ ๋ฆฌ(?)๊ฐ ๋์ ๊ฑฐ ๊ฐ์๋ค.
์ฌํผ ํฅ์ฌ๊ณ ๋ ์ ๋ด๋ถ์ ์ธ๋ถ๋ฅผ ๋๋ ์ ๋น์ฆ๋์ค ๋ก์ง์ด ํํ ๋ก์ง์ด๋ ๋ฐ์ดํฐ ์ ๊ทผ์ ์์กดํ์ง ์๊ฒ ๋ง๋๋๊ฒ ํฌ์ธํธ๋ผ๊ณ ํ ์ ์๋๋ฐ ์ฌ๊ธฐ์ ๋ด๋ถ์ ํด๋นํ๋๊ฒ ๋๋ฉ์ธ! ์ธ๋ถ์ ํด๋นํ๋๊ฒ ์ํฐํฐ๋ผ๊ณ ๋ณด๋ฉด ๋ ๊ฑฐ ๊ฐ๋ค!
๋ผ๊ณ ์ผ์๋๋ฐ ํธ์น๋์ด ์ค ํ ๋ฉ์ ์ผ๋ก ๋ธ๋ก๊ทธ ๊ธ์ ์ข ๋ ์์ธํ ์จ์ผ ๊ฒ ๋ค๊ณ ์๊ฐํ๋ค.
๋ฃฐ๋ฃจ๋๋ผ ๋ธ๋ก๊ทธ ๊ธ ์ฐ๊ณ ์ ๊ธ ์ผ์ด์! ํ๊ณ ํธ์ํฐ์ ์ฌ๋ ธ๋ค๊ฐ ์ํฐํฐ ์ฉ์ด๊ฐ DDD์์ ๋งํ๋ ๊ฒ๊ณผ ํท๊ฐ๋ฆด ์๋ ์๋ค๋ ๋ง์ ๋ฃ๊ณ ๋ ์น!!! ํ๋ค.
๊ทธ๋์ ๊ธ ๊ณต๋ถํด์ ์ถ๊ฐํด ๊ธ์ ์ฐ๊ฒ ๋๋ค.
์ผ๋จ ๋๋ DDD๋ฅผ ์ ๋ชจ๋ฅด๊ณ ์๋์ ๊ฐ์ด ๋๋ฉ์ธ, ์ํฐํฐ๋ฅผ ์๊ฐํ๊ณ ์์ ๊ธ์ ์ผ๋ค.
๋๋ฉ์ธ โ ๋น์ฆ๋์ค ๋ก์ง
์ํฐํฐ โ ์์์ฑ ๋ก์ง
ํธ์น๋์ด ๋งํด์ฃผ์ ๋ถ๋ถ์ ์ํฐํฐ๋ผ๋ ์ฉ์ด๊ฐ DDD์์ ์ธํ๋ผ ์์ญ์ด ์๋ Domain Model์ ํ ์ข
๋ฅ๋ผ๋! ๋ง์ด์๋ค. ์ ์ค๋ก์ธ์ ์ง๋ฌธ์ผ๋ก ๋์จ ํ์ผ์ด @Table
์ด๋
ธํ
์ด์
์ด ๋ถ์ด์ ๋น์ฐํ ์ธํ๋ผ ์์ญ์ด๋ผ๊ณ ์๊ฐํ๊ณ ๊ธ์ ์ผ๋๋ฐ ์๊ฐํด๋ณด๋ ๋ด๊ฐ ์ด context๋ฅผ ์์ ์ค๋ช
ํ์ง ์๊ณ ๊ธ์ ์ผ๊ตฌ๋! ์ถ์๋ค.
๊ทธ๋์ ๋ฐ์์์ง๋ง ์ถ๊ฐ๋ฅผ ํ์๋ฉด ์์ ์ง๋ฌธ์ ์๋ ์ฝ๋์ ์๋ ์ฃผ์์ด์๋ค.
// ๋๋ฉ์ธ ๊ฐ์ฒด ์์ฑ์ ์ฌ๋ฌ ํ๋๊ฐ ํ์ํ๊ธฐ ๋๋ฌธ์ ๋ถ๊ฐํผ
@Suppress("LongParameterList")
@Table("users")
// POINT: ์ด ํด๋์ค๋ฅผ data class ๋ก ์ ์ธํ๊ณ , equals / hashCode ๋ฅผ ์ญ์ ํด๋ ๋ฌธ์ ๊ฐ ์์๊น์?
// POINT: Entity ์ Domain Model ์ ์ฐจ์ด๋ ๋ญ๊น์?
internal class UserEntity constructor(
@get:Id
var id: Long? = null,
override val uuid: UUID,
nickname: String,
profileImageUrl: String,
override var deletedAt: Instant?,
override var createdAt: Instant,
updatedAt: Instant,
override var version: Long,
) : User.Editor {
override var nickname: String = ""
set(value) {
field = value
this.updatedAt = Instant.now()
}
์๋ต ...
๊ทธ๋ฐ๋ฐ DDD์์ ๋งํ๋ Entity๊ฐ ๋ญ๊น? ๊ฐ์๊ธฐ ๊ถ๊ธํด์ ธ์ ๊ฒ์์ ํด๋ดค๋ค.
์ ๊ธ์ ์๋ฆญ ์๋ฐ์จ์ ๋๋ฉ์ธ ์ฃผ๋ ์ค๊ณ CH5์์ ๋ฐ์ท๋ ๊ธ์ด๋ผ๊ณ ํ๋ค. ์ฌ๊ธฐ์ ๋งํ๋ ์ํฐํฐ๋
- identity(ID)๋ก ์ฃผ๋ก ์ ์๋๋ ๊ฐ์ฒด์ด๊ณ
- ๋ผ์ดํ ์ฌ์ดํด์ ํตํด ์ฐ์์ฑ์ ๊ฐ๊ณ (?)
- ์ฑ ์ฌ์ฉ์๋ค์๊ฒ ์ค์ํ ํน์ฑ์ ๊ตฌ๋ณ๋๋ ๋ ๋ฆฝ์ ์ด์ด์ผ ํ๋ค๊ณ .
์ด๊ฒ ๋ญ ๊ฐ ํ ๋ฏ์ด ๋จน๋ ์๋ฆฌ์ง?
์คํ์ค๋ฒํ๋ก์ฐ์ ์ด๋ฐ ์์๊ฐ ์์๋ค.
๋๊ตฐ๊ฐ ์ด๋ค ์ง๋ฌธ๊ธ์ ๋ํด์ ์์ ๋ด์ฉ์ ๋ฐ๊พธ๊ฑด ๊ทธ ๊ธ์ ์ ๋ชฉ์ ๋ฐ๊พธ๊ฑด ๋ฐ๋ด ๋ฒํผ์ ๋๋ฌ์ฃผ๋ ๊ทธ๊ฑด ์ฌ์ ํ ๊ฐ์ ์ง๋ฌธ์ด๋ค. ๊ณผ๊ฑฐ์ ํ ์คํธ์์ ํ์ฌ์ ํ ์คํธ๋ก ์ฌ์ ํ ์งํ๋๊ณ ์๋ค. ํ ์คํธ๋ ์๊ฐ์ ๋ฐ๋ผ ๋ณํ๋ค.
๋๋ฉ์ธ ๋ชจ๋ธ์์์ ๊ฐ๋จํ ์ํฐํฐ๋ RDBMS์ ์ํฐํฐ์ ๋งคํ๋ ์๋ ์์ผ๋ ๊ผญ ๊ทธ๋ฐ ๊ฒ์ ์๋๋ค. ์ ํํ ์๊ธฐํ๋ฉด, ์ฐ๋ฆฌ๋ ๋ฐ๋์ ์ํฐํฐ์ ํ์ฌ ์ํ๋ฅผ ๋จ์ผ ํ์ ์ ์ฅํ๋ค. ํ์ง๋ง ํด๋น ์ํ์ ์ปฌ๋ ์ ์ด ํฌํจ๋๋ค๋ฉด ์ฌ๋ฌ ํ ์ด๋ธ์ ๋ค์์ ํ์ ํตํด ๋ถ์ฐ๋ ๊ฒ์ด๋ค.(์ฆ, ํ ์ํฐํฐ์๋ง ์ข ์๋์ง ์์ ์๋ ์๋ค ๋ผ๋ ์๊ธฐ์ธ ๋ฏ)
์ ์ด๊ฑธ ๋ด๋ ์ดํด๊ฐ ์ ๊ฐ์ง๋ง ์ฌ๊ธฐ์ ๋งํ๋ ์ํฐํฐ๋ ์๋ง๋ ๋ค์์ ํ ์ด๋ธ์ ์ํ๋ก ๋ถ์ฐ๋ ์ ์์ผ๋ ํ ์ํฐํฐ๋ก ๋ฐ๋์ ๋งคํ๋์ง ์์์ ์๋ฏธํ๋ ๊ฒ ๊ฐ๋ค.
์ข ๋ ๊ฒ์ํ๋ค๊ฐ ๋งํด ํ์ธ๋ฌ์ ๋ธ๋ก๊ทธ ๊ธ์ ๋ฐ๊ฒฌํ๋ค.
๐งโโ๏ธ Entity:
Objects that have a distinct identity that runs through time and different representations.
You also hear these called "reference objects".
์์์์ ๋น์ทํ ์ํฐํฐ ์ค๋ช ์ธ๋ฐ
- ์๊ฐ์ ๋ฐ๋ผ, ๋ค๋ฅธ ํํ์ ๋ฐ๋ผ ๊ณ ์ ์ ์ฒด์ฑ์ ๊ฐ์ง ๊ฐ์ฒด
- ์ฐธ์กฐ ๊ฐ์ฒด๋ผ๊ณ ๋ ๋ค์ด๋ดค์ง? ๊ทธ๋ ๊ฒ ๋ถ๋ฅด๊ธฐ๋ ํด.
์ ๊ธ์์ runs through time ์ ์ด๋ป๊ฒ ํด์ํด์ผ ํ๋๊ฑฐ์ง? ์๊ฐ์ ๋ฐ๋ผ ๋ฌ๋ฆฌ๋ ์๋
?
์น์ ํ ๋งํด ์์ ์จ๊ฐ ์์๋ฅผ ๋ค์ด์ฃผ์ ๋ค.
๐งโโ๏ธ
Entities are usually big things like Customer, Ship, Rental Agreement.
Values are usually little things like Date, Money, Database Query.
Services are usually accesses to external resources like Database Connection, Messaging Gateway, Repository, Product Factory.
์ํฐํฐ๋ ๋ณดํต ํฐ ๊ฒ๋ค์ธ๋ฐ ๊ณ ๊ฐ, ๋ฐฐ, ๋ ํ ๊ณ์ฝ ๊ฐ์๊ฑฐ์ผ.
๊ฐ์ ๋ณดํต ์์ ๊ฒ๋ค์ธ๋ฐ ๋ ์ง, ๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๊ฐ์๊ฑฐ์ผ.
์๋น์ค๋ ๋ณดํต ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ์ด๋ ๋ฉ์์ง ๊ฒ์ดํธ์จ์ด, ๋ ํฌ์งํฐ๋ฆฌ ๊ฐ์ ์ธ๋ถ ๋ฆฌ์์ค ์ ๊ทผ ๊ฐ์๊ฑฐ์ผ.
์ด์งธ Entity, Value Object(VO), Service๋ฅผ ํ๋ํ๋ ์น์ ํ ๊ตฌ๋ถํด์ฃผ์ ๋ค.
๊ทผ๋ฐ ๋ง์ง๋ง์ ์ถฉ๊ฒฉ์ ์ธ ์์์ ํ๋ ์ ๋ฌํด์ฃผ์ ๋ค.
๐งโโ๏ธ
One of the problems with this area is that this terminology, although evocative, gets terribly muddled up with other ideas.
Entity is often used to represent a database table or an object that corresponds to a database table.
So if I use these terms I have to make it clear I'm using them within the context of Domain Models and according to their meaning within Eric's book. S
o be wary of assuming people are using these words like this - they are heavily overloaded.
Sadly there's not much alternative.
DDD์ ์ํฐํฐ์ ๋ฌธ์ ๋ ๋์ฐํ๊ฒ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋งํ๋ ์ํฐํฐ์ ๊ฐ๋ ์ด ๋ค๋ฅด๋จ๋ค!
๊ทธ๋์ ๋๋ ์ด๊ฑธ ์ค๋ช ํ ๋ ๋งค๋ฒ ์๋ฆญ์ DDD์ ์ํฐํฐ๋ผ๊ณ ๋ฏธ๋ฆฌ ์ธ๊ธํ๊ณ ์๊ธฐํด ใ ใ .
์ด ๊ฐ๋ ์ ๋ค๋ฅด๊ฒ ์๊ฐํด์ผ ํด์ ๋จธ๋ฆฌ๊ฐ ํฐ์ง ๊ฑฐ ๊ฐ์ง?
๊ทผ๋ฐ ์ฌํ๊ฒ ๋์์ ์๋จ๋ค(?)
์ด๋ฐ ๋งํ
๊ฒฐ๋ก
DDD์์ ๋งํ๋ ์ํฐํฐ๋ ์์ฑ์ด ์๋ ID๋ก ๊ตฌ๋ณ๋๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ ๊ฒ ๊ฐ์๋ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฐํฐ์ 100%๋ก ์ผ์นํ๋ ๊ฐ๋ ์ด ์๋๋๋๋ค.
๋ณดํต ์ฐ๋ฆฌ๊ฐ๋ด๊ฐ ์๊ฐํ๋ Entity๋ ORM์์ ๋งํ๋ Entity์ธ๋ฐ DB ํ
์ด๋ธ๊ณผ ๋งคํํ๊ธฐ ์ํ ๊ฐ์ฒด๋ผ๊ณ ์๊ฐํ๋ฉด ๋ ๊ฑฐ ๊ฐ๋ค. ๊ทธ๋ฌ๋ค๋ณด๋ ๋ณดํต ๊ฐ์ฒด๊ฐ ์ธ์ , ์ด๋์, ์ด๋ป๊ฒ ์ ์ฅ๋๋์ง๋ฅผ ๊ด์ฌ์ ๋๊ณ ์๋ค.
DDD์ Entity๋ ์์์ฑ์ ๋ํด์๋ ๋ชจ๋ฅด๋ ๊ฐ์ฒด์ธ ๊ฑฐ ๊ฐ๋ค.(์ธํฐํ์ด์ค ์ ๋๋ง ์๊ณ ์๋๋ฏ) ์์์ฑ์ ๋ชจ๋ฅด๊ธฐ ๋๋ฌธ์ ORM์๋ ์ ํ ๊ด์ฌ์ด ์์ด ๊ฐ์ฒด๊ฐ ์ด๋์ ์ด๋ป๊ฒ ์ ์ฅ๋๋์ง์ ๊ด์ฌ์ด ์๋ค. ๊ฒฝ์ฐ์ ๋ฐ๋ผ ORM ๋งคํ๋๋ ๊ฐ์ฒด๊ฐ ๋๋ฉ์ธ ๋ชจ๋ธ์ผ ๋ ๊ฐ์ ๊ฐ๋
์ผ๋ก ์ฌ์ฉ๋ ์๋ ์๊ธด ํ ๊ฒ ๊ฐ๋ค.(๋ญ ์๋ฆฌ์ผ)
์ถ๊ฐํด์ ๋ ๊ณต๋ถํด๋ดค๋๋ฐ ๋ญ๊ฐ ๋๋ ๋ฏธ๊ถ ์์ผ๋ก ๋ค์ด๊ฐ ๋๋์ด๋ค. ํํ โฆ
์ User ์ํฐํฐ Editor ํ๊ณ ๊ฐ๋ค๊ฐ ๋ ์ง๋ฌธ ๋ฐ๊ฒฌํ๋ค. ์ด๊ฑด ๋ด์ผ ํ๋ ๊ฑธ๋กโฆ
// POINT: ์ User ๋๋ฉ์ธ ๋ชจ๋ธ์ mutable ๋ก ์ค๊ณํ์ง ์๊ณ , ์ด๋ฐ ํ์
์ ๋ณ๋๋ก ๋ง๋ค์์๊น์?
์ค๋ ์ ๊ฒ ๋ ๊ฒ
- ์๋ก ๋ณธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค!
- javax_inject
- jsr305
- kover(์ด๊ฑด ์ฝํ๋ฆฐ ๋ธ๋ก๊ทธ์์โฆ)
๋ผ์ด์ ์ค ์ ์ฑ
CC BY-NC-SA
- ๋์ค์ ๋ด๊ฐ ์ด๊ฑธ ์ง์ ํ์ดํํ ๋ ์ด ์ฌ๊น?- ์ค๋ก์ธ ์ฝ๋์๋ ์ง๋ฌธ์ด ์ฐ๋ค!(๊ทธ๊ฒ๋ ์์ฒญ ๋ง์ด!!)
๋ค์์ ํ ๊ฒ
User Domain ๋ชจ๋ธ์ ๋ฎคํฐ๋ธํ๊ฒ ์ค๊ณํ๋ฉด ๋น์ฐํ ์๋ฌด๋ฐ์๋ ์๋ฌด ๊ฐ๋ฐ์๊ฐ ์ด ํด๋์ค๋ฅผ ์ฐธ์กฐํด์ ๋ฐ๊ฟ ์ ์์ผ๋ ์ฝ๋๊ฐ ๊ฐํ๋ ๊ฐ๋ฅ์ฑ์ด ๋์์ง๊ฒ ์ง? ๊ทธ๋๊น ๋๋ฉ์ธ์์ fun์ ๋ฐ๋ก ๋ง๋ค์ด์ ํ๋๋ฅผ ์์ ํ๊ฑฐ๋ ์๋๋ฉด ์ฌ๊ธฐ ์๋ ์ฝ๋์ฒ๋ผ ์ธํฐํ์ด์ค๋ฅผ ๋ง๋ค ์๋ ์๊ฒ ๋ค. ์ด๋ ๊ฒ ์ธํฐํ์ด์ค ๋ง๋ ๊ฑฐ ์ฒ์ ๋ณด๋๋ฐ ์ธํฐํ์ด์ค๋ฅผ ํตํด์ ์์ ํ๊ฒ ๋ง๋๋ ๊ฒ๋ ์ฝ๋ ๋ถ๋ฆฌํ๋ ๋ฉด์์๋ ์ข๊ณ ๋ช ์ธ๋ก์๋ ์ข์ ๊ฑฐ ๊ฐ๊ธด ํ๋ค.
์ ๊ทธ๋ฆฌ๊ณ ์ค๋ก์ธ์ jvm lib๊ฐ ๋ฐ๋ก ์์ด์ ๊ทธ๊ฒ ๊ถ๊ธํด์ ๋ด์ผ ๋ณผ๊น ์ถ๋ค. ํ ๋ฏ
์๋ ์ค๋ ๊ทธ๊ฑฐ ๋ณด๋ คํ๋๋ฐ ๋ฌ๊ธ ์์ด ์ง๋ฌธ ๋ฐ๊ฒฌํด์ ์๊ฐ์ด ๋ง์ด ์ง๋๋ฒ๋ ธ๋ค.
๊ฒฐ๋ก
์ค๋๋ ์ฌ๋ฏธ๊ฐ ์์๋ค~!
(real mysql 1๊ถ ์ฝ๊ธฐ ์ซ๋ค!!)