0606 ~ 0619
# 0606 ~ 0619
# 0610 - ํ ์คํธ ๋๋ธ (Test Double)
# ํ ์คํธ ๋๋ธ(Test Double)์ด๋?
xUnit Test Patterns์ ์ ์์ธ ์ ๋ผ๋ ๋ฉ์ค์๋ก์ค๊ฐ ๋ง๋ ์ฉ์ด๋ก ํ ์คํธ๋ฅผ ์งํํ๊ธฐ ์ด๋ ค์ด ๊ฒฝ์ฐ ์ด๋ฅผ ๋์ ํด ํ ์คํธ๋ฅผ ์งํํ ์ ์๋๋ก ๋ง๋ค์ด์ฃผ๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ค.
์๋ฅผ ๋ค์ด ์ฐ๋ฆฌ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก๋ถํฐ ์กฐํํ ๊ฐ์ ์ฐ์ฐํ๋ ๋ก์ง์ ๊ตฌํํ๋ค๊ณ ํ์. ํด๋น ๋ก์ง์ ํ ์คํธํ๊ธฐ ์ํด์ ํญ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํฅ์ ๋ฐ์ ๊ฒ์ด๊ณ , ์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ํ์ ๋ฐ๋ผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์ ๋ฐํ ์๋ ์๋ค.
์ด๋ ๊ฒ ํ ์คํธํ๋ ค๋ ๊ฐ์ฒด์ ์ฐ๊ด๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๊ธฐ๊ฐ ์ด๋ ต๊ณ ๋ชจํธํ ๋ ๋์ ํด์ค ์ ์๋ ๊ฐ์ฒด๋ฅผ ํ ์คํธ ๋๋ธ์ด๋ผ ํ๋ค.
# ํ ์คํธ ๋๋ธ์ ์ข ๋ฅ
ํ ์คํธ ๋๋ธ์ ํฌ๊ฒ Dummy, Fake, Stub, Spy, Mock์ผ๋ก ๋๋๋ค.
# 1. Dummy
- ๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํ ์คํธ ๋๋ธ์ด๋ค.
- ์ธ์คํด์คํ ๋ ๊ฐ์ฒด๊ฐ ํ์ํ์ง๋ง ๊ธฐ๋ฅ์ ํ์ํ์ง ์์ ๊ฒฝ์ฐ์ ์ฌ์ฉํ๋ค.
- Dummy ๊ฐ์ฒด์ ๋ฉ์๋๊ฐ ํธ์ถ๋์์ ๋ ์ ์ ๋์์ ๋ณด์ฅํ์ง ์๋๋ค.
- ๊ฐ์ฒด๋ ์ ๋ฌ๋์ง๋ง ์ฌ์ฉ๋์ง ์๋ ๊ฐ์ฒด์ด๋ค.
์ ๋ฆฌํ๋ฉด ์ธ์คํด์คํ๋ ๊ฐ์ฒด๊ฐ ํ์ํด์ ๊ตฌํํ ๊ฐ์ง ๊ฐ์ฒด์ผ ๋ฟ์ด๊ณ , ์์ฑ๋ Dummy ๊ฐ์ฒด๋ ์ ์์ ์ธ ๋์์ ๋ณด์ฅํ์ง ์๋๋ค.
public interface PringWarning {
void print();
}
public class PrintWarningDummy implements PrintWarning {
@Override
public void print() {
// ์๋ฌด๋ฐ ๋์์ ํ์ง ์๋๋ค.
}
}
์ค์ ๊ฐ์ฒด๋ PrintWarning ์ธํฐํ์ด์ค์ ๊ตฌํ์ฒด๋ฅผ ํ์ํ์ง๋ง, ํน์ ํ
์คํธ์์๋ ํด๋น ๊ตฌํ์ฒด์ ๋์์ด ์ ํ ํ์ํ์ง ์์ ์ ์๋ค. ์ค์ ๊ฐ์ฒด๊ฐ ๋ก๊ทธ์ฉ ๊ฒฝ๊ณ ๋ง ์ถ๋ ฅํ๋ค๋ฉด ํ
์คํธ ํ๊ฒฝ์์๋ ์ ํ ํ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฐ ๊ฒฝ์ฐ์๋ print()๊ฐ ์๋ฌด๋ฐ ๋์์ ํ์ง ์์๋ ํ
์คํธ์๋ ์ํฅ์ ๋ฏธ์น์ง ์๋๋ค.
์ด์ฒ๋ผ ๋์ํ์ง ์์๋ ํ
์คํธ์๋ ์ํฅ์ ๋ฏธ์น์ง ์๋ ๊ฐ์ฒด๋ฅผ Dummy ๊ฐ์ฒด๋ผ๊ณ ํ๋ค.
# 2. Fake
- ๋ณต์กํ ๋ก์ง์ด๋ ๊ฐ์ฒด ๋ด๋ถ์์ ํ์๋ก ํ๋ ๋ค๋ฅธ ์ธ๋ถ ๊ฐ์ฒด๋ค์ ๋์์ ๋จ์ํํ์ฌ ๊ตฌํํ ๊ฐ์ฒด์ด๋ค.
- ๋์์ ๊ตฌํ์ ๊ฐ์ง๊ณ ์์ง๋ง ์ค์ ํ๋ก๋์ ์๋ ์ ํฉํ์ง ์์ ๊ฐ์ฒด์ด๋ค.
์ ๋ฆฌํ๋ฉด ๋์์ ํ์ง๋ง ์ค์ ์ฌ์ฉ๋๋ ๊ฐ์ฒด์ฒ๋ผ ์ ๊ตํ๊ฒ ๋์ํ์ง๋ ์๋ ๊ฐ์ฒด๋ฅผ ๋งํ๋ค.
@Entity
public class User {
@Id
private Long id;
private String name;
protected User() {}
public User(Long id, String name) {
this.id = id;
this.name = name;
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
}
public interface UserRepository {
void save(User user);
User findById(long id);
}
public class FakeUserRepository implements UserRepository {
private Collection<User> users = new ArrayList<>();
@Override
public void save(User user) {
if (findById(user.getId()) == null) {
user.add(user);
}
}
@Override
public User findById(long id) {
for (User user : users) {
if (user.getId() == id) {
return user;
}
}
return null;
}
}
ํ ์คํธํด์ผ ํ๋ ๊ฐ์ฒด๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ฐ๊ด๋์ด ์๋ค๊ณ ๊ฐ์ ํ๋ค.
๊ทธ๋ด ๊ฒฝ์ฐ ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฐ๊ฒฐํด์ ํ ์คํธํด์ผ ํ์ง๋ง, ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋์ ๊ฐ์ง ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ์ ํ๋ FakeUserRepository๋ฅผ ๋ง๋ค์ด ํ ์คํธ๊ฐ์ฒด์ ์ฃผ์ ํ๋ ๋ฐฉ๋ฒ๋ ์๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ ์คํธ ๊ฐ์ฒด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์์กดํ์ง ์์ผ๋ฉด์๋ ๋์ผํ๊ฒ ๋์์ํ๋ ๊ฐ์ง ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ฐ์ง๊ฒ ๋๋ค.
# 3. Stub
- Dummy ๊ฐ์ฒด๊ฐ ์ค์ ๋ก ๋์ํ๋ ๊ฒ ์ฒ๋ผ ๋ณด์ด๊ฒ ๋ง๋ค์ด ๋์ ๊ฐ์ฒด์ด๋ค.
- ์ธํฐํ์ด์ค ๋๋ ๊ธฐ๋ณธ ํด๋์ค๊ฐ ์ต์ํ์ผ๋ก ๊ตฌํ๋ ์ํ์ด๋ค.
- ํ ์คํธ์์ ํธ์ถ๋ ์์ฒญ์ ๋ํด ๋ฏธ๋ฆฌ ์ค๋นํด๋ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ๋ค.
์ ๋ฆฌํ๋ฉด ํ ์คํธ๋ฅผ ์ํด ํ๋ก๊ทธ๋๋ฐ๋ ๋ด์ฉ์ ๋ํด์๋ง ์ค๋น๋ ๊ฒฐ๊ณผ๋ฅผ ์ ๊ณตํ๋ ๊ฐ์ฒด์ด๋ค.
public class StubUserRepository implements UserRepository {
// ...
@Override
public User findById(long id) {
return new User(id, "Test User");
}
}
์์ ์ฝ๋์ฒ๋ผ StubUserRepository๋ findByID() ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ฉด ์ธ์ ๋ ๋์ผํ id๊ฐ์ TestUser๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง User ์ธ์คํด์ค๋ฅผ ๋ฐํ๋ฐ๋๋ค.
ํ
์คํธ ํ๊ฒฝ์์ User ์ธ์คํด์ค์ name์ Test User๋ง ๋ฐ๊ธฐ๋ฅผ ์ํ๋ ๊ฒฝ์ฐ ์ด์ฒ๋ผ ๋์ํ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํ ์ ์๋ค.
๋ฌผ๋ก ์ด๋ฌํ ๋ฐฉ์์ ๋จ์ ์ ํ
์คํธ๊ฐ ์์ ๋ ๊ฒฝ์ฐ Stub ๊ฐ์ฒด๋ ํจ๊ป ์์ ํด์ผ ํ๋ ๋จ์ ์ด ์๋ค.
์ฐ๋ฆฌ๊ฐ ํ
์คํธ์์ ์์ฃผ ์ฌ์ฉํ๋ Mockito ํ๋ ์์ํฌ๋ Stub์ ๊ฐ์ ์ญํ ์ ํด์ค๋ค.
์ด์ฒ๋ผ ํ
์คํธ๋ฅผ ์ํด ์๋ํ ๊ฒฐ๊ณผ๋ง ๋ฐํ๋๋๋ก ํ๊ธฐ ์ํ ๊ฐ์ฒด๊ฐ Stub์ด๋ค.
# 4. Spy
- Stub์ ์ญํ ์ ๊ฐ์ง๋ฉด์ ํธ์ถ๋ ๋ด์ฉ์ ๋ํด ์ฝ๊ฐ์ ์ ๋ณด๋ฅผ ๊ธฐ๋กํ๋ค.
- ํ ์คํธ ๋๋ธ๋ก ๊ตฌํ๋ ๊ฐ์ฒด์ ์๊ธฐ ์์ ์ด ํธ์ถ ๋์์ ๋ ํ์ธ์ด ํ์ํ ๋ถ๋ถ์ ๊ธฐ๋กํ๋๋ก ๊ตฌํํ๋ค.
- ์ค์ฒด ๊ฐ์ฒด์ฒ๋ผ ๋์์ํฌ ์๋ ์๊ณ , ํ์ํ ๋ถ๋ถ์ ๋ํด์๋ Stub๋ก ๋ง๋ค์ด์ ๋์์ ์ง์ ํ ์๋ ์๋ค.
์ ๋ฆฌํ๋ฉด ์ค์ ๊ฐ์ฒด๋ก๋ ์ฌ์ฉํ ์ ์๊ณ Stub ๊ฐ์ฒด๋ก๋ ํ์ฉํ ์ ์์ผ๋ฉฐ ํ์ํ๊ฒฝ์ฐ ํน์ ๋ฉ์๋๊ฐ ์ ๋๋ก ํธ์ถ๋์๋์ง ์ฌ๋ถ๋ฅผ ํ์ธํ ์ ์๋ค.
public class MailingService {
private int sendMailCount = 0;
private Collection<Mail> mails = new ArrayList<>();
public void sendMail(Mail mail) {
sendMailCount++;
mails.add(mail);
}
public long getSendMailCount() {
return sendMailCount;
}
}
MailingService๋ sendMail์ ํธ์ถํ ๋๋ง๋ค ๋ณด๋ธ ๋ฉ์ผ์ ์ ์ฅํ๊ณ ๋ช ๋ฒ ๋ณด๋๋์ง๋ฅผ ์ฒดํฌํ๋ค. ๊ทธ๋ฆฌ๊ณ ๋์ค์ ๋ฉ์ผ์ ๋ณด๋ธ ํ์๋ฅผ ๋ฌผ์ด๋ณผ ๋ sendMailCount๋ฅผ ๋ฐํํ๋ค.
์ด์ฒ๋ผ ์๊ธฐ ์์ ์ด ํธ์ถ๋ ์ํฉ์ ํ์ธํ ์ ์๋ ๊ฐ์ฒด๊ฐ Spy์ด๋ค.
์ด ๋ํ Mockito ํ๋ ์์ํฌ์ verify() ๋ฉ์๋๊ฐ ๊ฐ์ ์ญํ ์ ํ๋ค.
# 5. Mock
- ํธ์ถ์ ๋ํ ๊ธฐ๋๋ฅผ ๋ช ์ธํ๊ณ ๋ด์ฉ์ ๋ฐ๋ผ ๋์ํ๋๋ก ํ๋ก๊ทธ๋๋ฐ ๋ ๊ฐ์ฒด.
- Mockito ํ๋ ์์ํฌ๊ฐ ๋ํ์ ์ธ Mock ํ๋ ์์ํฌ.
@ExtendWith(MockitoExtension.class)
public class UserServiceTest {
@Mock
private UserRepository userRepository;
@Test
void test() {
when(userRepository.findById(anyLong())).thenReturn(new User(1, "Test User"));
User actual = userService.findById(1);
assertThat(actual.getId()).isEqualTo(1);
assertThat(actual.getName()).isEqualTo("Test User");
}
}
# 0613 - orphanRemoval
๋ถ๋ชจ ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ๊ฐ ๋์ด์ง ์์ ์ํฐํฐ๋ฅผ ์๋์ผ๋ก ์ญ์ ํด์ฃผ๋ ๊ธฐ๋ฅ์ด๋ค.
@Entity
public class Parent {
@Id
@GeneratedValue
private Long id;
private String username;
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> childList = new ArrayList<>();
}
orphanRemoval๊ฐ true ์
Parent parent1 = em.find(Parent.class, parent.getId());
parent1.getChildList().remove(0); // delete ์ฟผ๋ฆฌ๋๊ฐ๋ค.
์๋์ผ๋ก delete ์ฟผ๋ฆฌ๊ฐ ๋๊ฐ๋ค.
- ์ด ์์ฑ์ ์ฐธ์กฐํ๋ ๊ณณ์ด ํ๋์ผ ๋๋ง ์ฌ์ฉํด์ผ ํ๋ค.
- ํน์ ์ํฐํฐ๊ฐ ๊ฐ์ธ ์์ ํ ๋๋ง ์ฌ์ฉํด์ผ ํ๋ค.
- @OneToOne๊ณผ @OneToMany์์๋ง ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
CascadeType.ALL + orphanRemovel=true
์ด ๋๊ฐ๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๊ฒ ๋๋ฉด ๋ถ๋ชจ ์ํฐํฐ๊ฐ ์์์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ๋ชจ๋ ๊ด๋ฆฌํ ์ ์๊ฒ ๋๋ค.
# 0615 - CQRS
# CQRS ์ํคํ ์ฒ๋?
๋ช ๋ น(์์คํ ๋ฐ์ดํฐ ๋ณ๊ฒฝ) ์ญํ ์ ์ํํ๋ ๊ตฌ์ฑ ์์์ ์ฟผ๋ฆฌ(์์คํ ๋ฐ์ดํฐ ์กฐํ) ์ญํ ์ ๊ตฌ์ํญํ๋ ๊ตฌ์ฑ ์์๋ฅผ ๋๋๋ ์ํคํ ์ฒ
์์คํ ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ๋ ์ฝ๋์ ์์คํ ๋ฐ์ดํฐ๋ฅผ ์กฐํํ๋ ์ฝ๋๋ฅผ ๋ฐ๋ก ๋ง๋๋ ๊ฒ, ๊ตฌํ๋ฐฉ์์ด๋ ์์คํ ๊ท๋ชจ์ ๋ฐ๋ผ์ DB๋ฅผ ๋๋๊ธฐ๋ํ๊ณ ํ๋ก์ธ์ค๋ฅผ ๋๋๊ธฐ๋ ํจ
- Command : ๋ช
๋ น
- ์์คํ ๋ฐ์ดํฐ ๋ณ๊ฒฝ
- ex) ์ฃผ๋ฌธ ์์ฑ, ์์ , ์ทจ์
- Query : ์กฐํ
- ์์คํ ๋ฐ์ดํฐ ์กฐํ
- ex) ์ฃผ๋ฌธ ์กฐํ
- Responsibility : ์ฑ
์
- ๊ตฌ์ฑ ์์์ ์ญํ
- ๊ตฌ์ฑ ์์ ex) ํด๋์ค, ํจ์, ๋ชจ๋, ํจํค์ง, ์น์๋ฒ, DB ๋ฑ
- Segregation : ์ญํ ์ ๋ฐ๋ผ ๊ตฌ์ฑ ์์ ๋๋๊ธฐ
# ๋จ์ผ ๋ชจ๋ธ์ ๋จ์
๋ช ๋ น๊ณผ ์ฟผ๋ฆฌ๋ฅผ ๊ตฌ๋ถํด ํผํ ์ ์๋ ๋ฌธ์ ๋ค
- ๊ธฐ๋ฅ ์ถ๊ฐ์ ๋ฐ๋ผ ์ฝ๋์ ์ฑ ์์ด ๋ชจํธํด์ง๊ณ , ๊ธฐ๋ฅ๋ง๋ค ๋ค๋ฅธ ํ ์ด๋ธ์ ์์กดํ๊ฒ ๋๋ค
- ๋ช ๋ น์ ํ ์์ญ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋๋ฐ ๋ฐํด ์ฟผ๋ฆฌ๋ ์ฌ๋ฌ ์์ญ์ ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ค.
- ๋ช ๋ น๊ณผ ์ฟผ๋ฆฌ๋ ์ฝ๋ ๋ณ๊ฒฝ ๋น๋์ ์ฌ์ฉ์๊ฐ ๋ค๋ฅด๋ค. ์๋ก ๋ค๋ฅธ ์ด์ ๋ก ๋ชจ๋ธ์ ์ฝ๋๊ฐ ๋ฐ๋๋ค๋ ๊ฒ์ ์ฑ ์์ ๋ถ๋ฆฌ๊ฐ ์ ์ ํ์ง ์๋ค๋ ๊ฒ์ด๋ค.
- ๊ธฐ๋ฅ๋ง๋ค ์๊ตฌ ์ฑ๋ฅ์ด ๋ค๋ฅด๋ค. ๋จ์ผ ๋ชจ๋ธ์ ๊ธฐ๋ฅ์ ๋ง๋ ๋ค์ํ ์ฑ๋ฅ ํฅ์ ๊ธฐ๋ฒ ์ ์ฉ์ด ์ด๋ ต๋ค.
- ex) ๋ช ๋ น : ์ฌ์ฉ์ ์ฃผ๋ฌธ ๊ธฐ๋ฅ, ์ฟผ๋ฆฌ : ๋ฐฑ์คํผ์ค ์ฃผ๋ฌธ ๋ชฉ๋ก ์กฐํ
# CQRS์ ๊ตฌํ
# ๊ฐ์ ํ๋ก์ธ์ค, ๊ฐ์ DBMS
- ์ฝ๋ ์์ค์์๋ง ๋ช ๋ น๊ณผ ์ฟผ๋ฆฌ๊ฐ ๋ถ๋ฆฌ๋๋ค
- ๋ฐ์ดํฐ์ ๋์ผ์ฑ์ด ๋ณด์ฅ๋๋ค
# ๊ฐ์ ํ๋ก์ธ์ค, ๊ฐ์ DBMS, ๋ค๋ฅธ ํ ์ด๋ธ
- ์ฟผ๋ฆฌ ์ ์ฉ ํ ์ด๋ธ์ ์ฌ์ฉํ๋ค
- ์ฝ๋ ์์ค, ๋ฐ์ดํฐ ์์ค์์ ๋ช ๋ น๊ณผ ์ฟผ๋ฆฌ๊ฐ ๋ถ๋ฆฌ๋๋ค
- ๋ช ๋ น์ด ๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ๋, ์ฟผ๋ฆฌ ์ ์ฉ ํ ์ด๋ธ๋ ์์ ํด์ผํ๋ค
# ๊ฐ์ ํ๋ก์ธ์ค, ๋ค๋ฅธ DBMS
- Redis๋ฅผ ์บ์๋ก ํ๊ณ ์ฟผ๋ฆฌ DB๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณผ ์ ์๋ค
# ๋ค๋ฅธ ํ๋ก์ธ์ค, ๋ค๋ฅธ DBMS
![image]
- MSA๋ฅผ ์๊ฐํด๋ณผ ์ ์๋ค
# 3๊ฐ์ง ๋ณ๊ฒฝ ์ ํ ์ ๋ต
CQRS ์ํคํ ์ฒ์์ ์ฌ๋ฌ DBMS๋ฅผ ์ฌ์ฉํ๊ฒ ๋๋ค๋ฉด ๋ณ๊ฒฝ ์ ํ ์ ๋ต๋ ์๋ฆฝํด์ผ ํ๋ค
# ๋ช ๋ น์ด ์ฟผ๋ฆฌ DBMS๋ฅผ ์์
- ๊ตฌํ์ด ๋จ์
- ์ฟผ๋ฆฌ DB ์ฅ์ ์ ๋ฐ์ดํฐ ์ ์ค ๊ฐ๋ฅ์ฑ์ด ์๋ค
- ๋ช ๋ น ๊ธฐ๋ฅ์ด ์ฟผ๋ฆฌ DB๊น์ง ์ ๊ทผํ๊ธฐ ๋๋ฌธ์ ๋ช ๋ น ๊ธฐ๋ฅ์ ์๋ฌ ๊ฐ๋ฅ์ฑ์ด ๋๋ค
# ๋ณ๊ฒฝ ๋ด์ฉ ๊ธฐ๋ก ํ, ์ ํ๊ธฐ ์ฌ์ฉ
- ๋ช ๋ น DB์ ๋ณ๊ฒฝ ๋ด์ฉ ํ ์ด๋ธ์ ๊ด๋ฆฌํด์ผํ๋ค
- ๋ฐ์ดํฐ ๋ณ๊ฒฝ๊ณผ ๋ณ๊ฒฝ ๋ด์ฉ์ ํ๋์ ํธ๋์ญ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ด ๋ฐ์ดํฐ ์ ์ค ๋ฐฉ์ง๊ฐ ๊ฐ๋ฅํ๋ค
- ์ ํ๊ธฐ๋ฅผ ๊ตฌํํด์ผํ๋ค
# DB๊ฐ ์ ๊ณตํ๋ CDC ์ฌ์ฉ
- CDC : ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์๋ ๋ฐ์ดํฐ์ ๋ณ๊ฒฝ์ ํ์ ํ๊ณ ์ถ์ ํ๋ ์ํํธ์จ์ด ํ๋ก์ธ์ค
- ๋ช ๋ น DB ๋ฐ์ด๋๋ฆฌ ๋ก๊ทธ๋ฅผ ์ฝ์ด ๋ณ๊ฒฝ์ ํ์ ํ๊ณ , ์ฟผ๋ฆฌ DB์ ์ ๋ฌํ ์ ์๋ค
- ๋ช ๋ น ์ฝ๋๊ฐ ๋ณ๊ฒฝ ๋ด์ฉ์ ๊ด๋ฆฌํ ํ์๊ฐ ์๋ค
# 0616 - MSA์ SOA์ ์ฐจ์ด
# SOA, MSA๋?
SOA๋ ์๋น์ค ์งํฅ ์ค๊ณ ๋ฐฉ์(Service Oriented Architecture)
SOA๋ ์๋น์ค ๋จ์๋ก ๊ฐ๋ฐ์ ํ๊ณ , ๊ฐ๋ฐ๋ ์๋น์ค๋ค์ ๊ณต์ ํจ์ผ๋ก์จ ์ฌ๊ฐ์ฉ์ฑ์ ๋๋ฆฌ๊ณ ์ ์ฐ์ฑ์ ํ๋ณดํ๋ ๊ฒ์ ๋ชฉํ
MSA๋ ๋ง์ดํฌ๋ก ์๋น์ค ์ค๊ณ ๋ฐฉ์(Micro Service Architecture)
MSA ๋ํ ์์ฃผ ์์ ๋จ์์ ์๋น์ค๋ก ์ํํธ์จ์ด๋ฅผ ๊ตฌ์ฑํจ์ผ๋ก์จ ๋ฏผ์ฒฉํ๊ณ ์ ์ฐํ ์ค๊ณํ๋ ๊ฒ์ ๋ชฉํ
# ๊ณต์ ์งํฅ์
SOA๋ ๋น์ง๋์ค ์ธก๋ฉด์์์ ์๋น์ค ์ฌ์ฌ์ฉ์ฑ์ ์ค์์ํ์ฌ ESB(Enterprise Service Bus)๋ผ๋ ์๋น์ค ์ฑ๋ ์ด์ฉ -> ์๋น์ค ๊ณต์ , ์ฌ์ฌ์ฉ
MSA๋ ํ ๊ฐ์ง ์์ ์๋น์ค์ ์ง์คํ์ฌ ์๋น์ค ๊ณต์ ํ์ง ์๊ณ ๋ ๋ฆฝ์ ์คํ
- SOA : ์ฌ์ฌ์ฉ์ ํตํ ๋น์ฉ ์ ๊ฐ
- MSA : ์๋น์ค ๊ฐ์ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ์ด ๋ณํ์ ๋ฅ๋์ ์ผ๋ก ๋์
# ๊ธฐ์ ๋ฐฉ์
- SOA๋ ๊ณตํต์ ์๋น์ค๋ฅผ esb์ ๋ชจ์ ์ฌ์ ์ธก๋ฉด์์ ๊ณตํต ์๋น์ค ํ์์ผ๋ก ์๋น์ค ์ ๊ณต
- MSA๋ ๊ฐ ๋ ๋ฆฝ๋ ์๋น์ค๊ฐ ๋ ธ์ถ๋ REST API๋ฅผ ์ฌ์ฉ
- SOA๋ ์๋น์ค๋ฅผ ๊ฐ๋ฐํ๊ณ ์ต๋ํ ์ฌ๊ฐ์ฉ
- MSA๋ ์๋น์ค๊ฐ ๊ณต์ ๋๊ธฐ ๋ณด๋ค ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๋ ๊ฒ์ ์งํฅ
# 0618 - ์๋ฐ ํ ์คํธ ๊ฒฉ๋ฆฌ
# ํ ์คํธ ๊ฒฉ๋ฆฌ๋?
ํ ์คํธ๋ ์์์ ์๊ด์์ด ๋ ๋ฆฝ์ ์ผ๋ก ์คํ๋๋ฉฐ ๊ฒฐ์ ์ ์ผ๋ก ์ํ๋์ด์ผ ํ๋ค. ํ ์คํธ๋ฅผ ์๋ก ๊ฒฉ๋ฆฌํ์ฌ ํ ํ ์คํธ๋ฅผ ์คํํ์ฌ๋ ๋ค๋ฅธ ํ ์คํธ์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ํด์ผํ๋ค.
# ๊ณ์ธต๋ณ ํ ์คํธ
๋ฐ์ดํฐ๋ค์ด ๊ณต์ ๋๊ธฐ ๋๋ฌธ์ ๋ถ์์ ํ ํ ์คํธ๋ฅผ ์์ฑํ๊ฒ ๋๋ค. ๋ฐ๋ผ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ผ๋ง๋ ์์กดํ์ง ์๊ณ ํ ์คํธ๋ฅผ ์์ฑํ ์ง ๋๋ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์ํ๋ฅผ ํ ์คํธ ์ด์ ์ผ๋ก ๋๋ฆด์ง์ ๋ํด์ ์ ๊ฒฝ์ ์จ์ผ ํ๋ค.
# - Domain(POJO) ๊ณ์ธต
- ์ ํ๋ฆฌ์ผ์ด์ ์ POJO(Model, Utils, etc...)๋ JUnit์ผ๋ก ํ ์คํธ
- ๊ฐ์ฒด๋ new ์ฐ์ฐ์(๋๋ ๋น๋)๋ก ๊ฐ๋จํ ์ธ์คํด์คํ
- ๊ฐ๊ฐ์ ํ ์คํธ๊ฐ ์คํ๋๊ธฐ ์ ์ @BeforeEach์์ ์ธ์คํด์ค ์ด๊ธฐํ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ฒฉ๋ฆฌ๋ฅผ ๊ฑฑ์ ํ ํ์ ์์
private Question question;
@BeforeEach
void setUp(){
question = Question.builder()
.userId(1L)
.title(TEST_QUETION_TITLE)
.content(TEST_QUESTION_CONTENT)
.build();
}
@DisplayName("์กฐํ์ ์ด๊ธฐ๊ฐ ํ์ธ")
@Test
void initValueOfVisits(){
assertThat(question.getVisits().getVisitCount()).isEqualTo(0L);
}
@DisplayName("์กฐํ์ ์ฆ๊ฐ")
@Test
void increaseVisits(){
question.increaseVisits();
assertThat(question.getVisits().getVisitCount()).isEqualTo(1L);
}
# - Service ๊ณ์ธต
- ์ค์ง์ ์ธ ๋น์ฆ๋์ค ๋ก์ง์ ์ํ
- ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ
- ํธ๋์ญ์ ์ด ๋๋๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ํ ๋ณ๊ฒฝ
- ํ ์คํธ ๊ฐ ๊ฒฉ๋ฆฌ๊ฐ ํ์
- ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๋ฉด์ ๊ณ์ธต๊ตฌ์กฐ๋ก ์ด๋ฃจ์ด์ ธ์๊ธฐ ๋๋ฌธ์ ์ฌ์ค์ ํตํฉ ํ ์คํธ๊ฐ ๋๋ฒ๋ฆผ
- @Transactional์ ์ฌ์ฉํด์ ํ ์คํธ๊ฐ ์ข ๋ฃ๋๋ฉด rollback๊ฐ๋ฅ
- Mockito๋ฅผ ์ด์ฉํ๋ฉด ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ธฐ ๋๋ฌธ์ ํ ์คํธ ๊ฒฉ๋ฆฌ๋ฅผ ๊ณ ๋ฏผํ ํ์๊ฐ ์๋ค.
# - Controller ๊ณ์ธต
- @SpringBootTest
- Spring IoC๋ก ์ค์ ์ปจํธ๋กค๋ฌ ๋น์ ์ฌ์ฉํด์ ํ ์คํธ
- ์ค์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฌ์ฉ
- ํตํฉ ํ ์คํธ
- @WebMvcTest
- MockMvc RestAPI ํด๋ผ์ด์ธํธ ํ ์คํธ ๋๊ตฌ ์ฌ์ฉ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋จ์ ํ ์คํธ ์ํ
# - Repository ๊ณ์ธต
- @DataJpaTest
- Slice Test ์งํ
- In Memory๋ก ํ ์คํธ ์ํ
- ์๋์ผ๋ก @Transactional(rollback=true)์ด ์ฌ์ฉ๋จ
# ์ธ์ ํ ์คํธ
- ์์คํ ์ด ์ค์ ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉ๋ ์ค๋น๊ฐ ๋์๋์ง ์ต์ข ์ ์ผ๋ก ํ์ธํ๋ ๋จ๊ณ
- ์ค์ ์ด์ํ๊ฒฝ์ ๋ง๊ฒ ์๋ฒ๋ฅผ ๋์ฐ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉ
- ํ ์คํธ ๊ฒฉ๋ฆฌ๋ฅผ ์ ๊ฒฝ์ฐ์ง ์์ผ๋ฉด ํ ์คํธ๊ฐ ์คํจํ๊ธฐ ์ฌ์
- ํ ์คํธ ๋จ์๊ฐ ์ปค์ ํ๋ฒ ์คํจํ๋ฉด ๋๋ฒ๊น ํ๊ธฐ ๊น๋ค๋ก์
- Mock ๊ฐ์ฒด๊ฐ ์๋ ์ค์ ๋น์ ์ฌ์ฉ
# ์ธ์ํ ์คํธ ๋ฐฉ๋ฒ
@Transactional : ์ธ์ ํ ์คํธ์์ ์ ๋๋ก ์๋ํ์ง ์์. ์์ฒญ์ ๋ณด๋ด๋ http client ์ชฝ๊ณผ ์ค์ ๋ก์ง์ ์ํํ๋ ์๋ฒ๋ก์ง์ด ์๋ก ๋ค๋ฅธ ์ฐ๋ ๋์์ ์คํ๋๋ค. ํ ์คํธ ์ฝ๋์์ ์ด๋ ธํ ์ด์ ์ ๋กค๋ฐฑ ์ ๋ต์ผ๋ก ํด๋์ด๋, ๋ค๋ฅธ ์ค๋ ๋์์ ์คํ๋๋ ์๋ฒ ์ฌ์ด๋ ํธ๋์ญ์ ์ ๊ทธ ํ ์คํธ ์ฝ๋์ ์ํฅ์ ๋ฐ์ง ์๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ณํ๊ฒ ๋๋ค.
๋งค๋ฒ ํ ์คํธ ์ข ๋ฃ์ ์์ฑํ ํฝ์ค์ฒ ๋ฐ ๋ฐ์ดํฐ ์ญ์
๋งค๋ฒ ํ ์คํธ ์ข ๋ฃ์ ํ ์ด๋ธ Truncate
Delete๋ณด๋ค Truncate๊ฐ ์ข์ ์ด์
- ํธ๋์ญ์ ๋ก๊ทธ ๊ณต๊ฐ์ ์ ๊ฒ ์ฐจ์ง
- ์ฟผ๋ฆฌ ์คํ์ ํ๋จ์๋ก ๋ฝ์ ๊ฑธ์ง ์์
3-1 @Sql๋ก SQL ํ์ผ ์คํ
3-2 EntityManager ์ด์ฉ
(๋ณด์ค๋ ๋์ด ์ถ์ฒํ๋ ๋ฐฉ์) ์ํฐํฐ ๋งค๋์ ๋ก ์ฟผ๋ฆฌ๋ฅผ ์ง์ ๋ง๋ค์ด์ ์คํํ๋ ๋ฐฉ์. ์ํฐํฐ์ ์๋ ํ ์ด๋ธ ์ด๋ฆ์ ๊ฐ์ง๊ณ ์จ ํ ๋ฆฌ์คํธ์ ์ ์ฅ
๋ฐ์ดํฐ ๋ฒ ์ด์ค๋ฅผ ์ฃผ์ ๋ฐ๊ณ ํ ์คํธ๋ฅผ ์คํํ๊ธฐ ์ง์ @BeforeEach์์ ํ ์ด๋ธ ์ด๋ฆ์ ์กฐ์ฌํ ํ Truncate๋ฅผ ์คํ. ์ด๋ ๊ฒ ๋ง๋ค์ด ๋๋ฉด ์ถํ ์ํฐํฐ๊ฐ ์ถ๊ฐ๋๊ฑฐ๋ ์ญ์ ๋ ๋ ๋์ ์ผ๋ก ํ ์ด๋ธ์ ์กฐ์ฌํ๊ธฐ ๋๋ฌธ์ ํ ์คํธ ๊ฒฉ๋ฆฌ์ ํฌ์ ๋๋ ๋น์ฉ์ ์ค์ผ ์ ์์
# ์ ๋ฆฌ
- ์๊ฒฉ๋ฆฌ๋ ํ ์คํธ๋ ์ ์ง๋ณด์๊ฐ ์์
- ๋์ฑ ์์ ํ ํ ์คํธ ์์ฑ์ผ๋ก ์ฝ๋์ ํ์ง ๋ณด์ฅ