์ํคํ ์ฒ
๐ ์ํคํ ์ฒ์ ์ ํ์ ์ต ์์ญ
- ํํ, ์์ฉ, ๋๋ฉ์ธ, ์ธํ๋ผ์คํธ๋ญ์ฒ
ํํ ์์ญ
- ์ฌ์ฉ์์ ์์ฒญ์ ๋ฐ์ ์์ฉ ์์ญ์ ์ ๋ฌํ๊ณ ์์ฉ ์์ญ์ ์ฒ๋ฆฌ ๊ฒฐ๊ณผ๋ฅผ ๋ค์ ์ฌ์ฉ์์๊ฒ ๋ณด์ฌ์ฃผ๋ ์ญํ
- ๋ํ์ ์ธ ํํ ์์ญ์ ์ฌ์ฉ์๋ ์น ๋ธ๋ผ์ฐ์ ์ด์ฉ์, REST API ๋ฅผ ํธ์ถํ๋ ์ธ๋ถ ์์คํ ๋ฑ
์์ฉ ์์ญ
- ์์คํ ์ด ์ฌ์ฉ์์๊ฒ ์ ๊ณตํด์ผ ํ ๊ธฐ๋ฅ์ ๊ตฌํํ๊ณ , ๊ทธ๋ฌ๊ธฐ ์ํด์ ๋๋ฉ์ธ ์์ญ์ ๋๋ฉ์ธ ๋ชจ๋ธ์ ์ฌ์ฉ
- ๋ก์ง์ ์ง์ ์ํํ๊ธฐ๋ณด๋ค๋ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๋ก์ง ์ํ์ ์์
public class CancelOrderService {
@Transactional
public void cancelOrder(String orderId) {
Order order = findOrderById(orderId);
if (order == null) throw new OrderNotFoundException(orderId);
order.cancel(); // ๋๋ฉ์ธ ๋ชจ๋ธ ๋ด๋ถ์ ์๋ ์ฃผ๋ฌธ ์ทจ์ ๋ก์ง์ ํด๋นํ๋ cancel() ์ฌ์ฉ
}
}
๋๋ฉ์ธ ์์ญ
- ๋๋ฉ์ธ ์์ญ์ ๋๋ฉ์ธ ๋ชจ๋ธ์ ๊ตฌํํ๊ณ , ๋๋ฉ์ธ์ ํต์ฌ ๋ก์ง์ ๊ตฌํ
- ex) ๋ฐฐ์ก์ง ๋ณ๊ฒฝ, ๊ฒฐ์ ์๋ฃ, ์ฃผ๋ฌธ ์ด์ก ๊ณ์ฐ
public class Order {
private OrderStatus status;
public void cancel() {
this.status = OrderStatus.CANCELED;
}
}
public enum OrderStatus {
...
CANCELED,
...
}
์ธํ๋ผ์คํธ๋ญ์ฒ ์์ญ
- RDBMS, MongoDB, HBase ๋ฑ ์ฐ๋์ ์ฒ๋ฆฌ
- Message Queue์ message ๋ฅผ ์ ์ก / ์์
- SMTP ๋ฉ์ผ ๋ฐ์ก
๊ณ์ธต ๊ตฌ์กฐ ์ํคํ ์ฒ
๐ ๋ค ์์ญ์ ๊ตฌ์ฑํ ๋ ๋ง์ด ์ฌ์ฉํ๋ ์ํคํ ์ฒ๊ฐ ์๋ ๊ทธ๋ฆผ๊ณผ ๊ฐ์ ๊ณ์ธต ๊ตฌ์กฐ
- ๊ณ์ธต ๊ตฌ์กฐ๋ ์์ ๊ณ์ธต์์ ํ์ ๊ณ์ธต์ผ๋ก์ ์์กด๋ง ์กด์ฌ
- ex) ์์ฉ ๊ณ์ธต์ด ๋๋ฉ์ธ ๊ณ์ธต์๋ ์์กดํ์ง๋ง, ๋๋ฉ์ธ ๊ณ์ธต์ด ์์ฉ ๊ณ์ธต์ ์์กดํ์ง๋ ์์
- ๊ตฌํ์ ํธ๋ฆฌํจ์ ์ํด ๊ณ์ธต ๊ตฌ์กฐ๋ฅผ ์ ์ฐํ๊ฒ๋ ์ ์ฉ ํ ์ ์์
- ex) ์์ฉ ๊ณ์ธต์ด ๋๋ฉ์ธ ๊ณ์ธต์๋ ์์กดํ๊ณ , ์ธ๋ถ ์์คํ ๊ณผ์ ์ฐ๋์ ์ํด ์ธํ๋ผ์คํธ๋ญ์ฒ ๊ณ์ธต์๋ ์์กดํ๊ธฐ๋ ํจ
๐ Rule Engine ์ด๋ ?
- ๋ฃฐ ์์ง์ ๋กค(Rule; ๊ท์น, ์ฆ ๋ก์ง)์ ๋ณ๋๋ก ์ ์ฅํด๋๊ณ ํ๋ก๊ทธ๋จ์์ ๋ฃฐ์ ๊ฐ์ ธ๋ค ์ธ ์ ์๋๋ก ํด ์ฃผ๋ ๊ธฐ๋ฅ์ ์ ๊ณต
Business Logic ์ด ๋งค์ฐ ๋น๋ฒํ๊ฒ ๋ณ๊ฒฝ๋๋ ๊ฒฝ์ฐ, ์ดํ๋ฆฌ์ผ์ด์ ์ ์์ ์ด ๋งค์ฐ ๋น๋ฒํ๊ฒ ๋ฐ์
๋ฐ๋ผ์, ํด๋น ๋ก์ง์ ๋ฃฐ ์์ง์ผ๋ก ์ฎ๊ฒจ๊ฐ๊ณ , ์ดํ๋ฆฌ์ผ์ด์ ์์๋ ๋กค ์์ง์ ํตํด์ ๋ฃฐ(๋ก์ง)์ ์คํํ๋๋ก ์ฒ๋ฆฌ
ex) ๋งค๋ ๊ณ์ํด์ ๋ณํ๋ ์ธ์จ์ ๋ฐ๋ฅธ ์ธ๊ธ ๊ณ์ฐ ๋ก์ง
DIP
๐ DIP ๋?
- ์์กด ์ญ์ ์์น(Dependency Inversion Principle) : ๊ณ ์์ค ๋ชจ๋์ ์ ์์ค ๋ชจ๋์ ๊ตฌํ์ ์์กดํด์๋ ์ ๋๋ฉฐ, ์ ์์ค ๋ชจ๋์ด ๊ณ ์์ค ๋ชจ๋์์ ์ ์ํ ์ถ์ ํ์ ์ ์์กดํด์ผ ํจ (์์ ๋ณด๋ค ๋ณํ๊ธฐ ์ฌ์ด ๊ฒ์ ์์กดํ์ง ๋ง๋ผ)
- Ex) DIP ๊ฐ ์ ์ฉ๋์ง ์์ ์ฃผ๋ฌธ ์ ํ ์ธ์จ ์ ์ฉ ์ฝ๋
class CalculateDiscountService {
private DroolsRuleEngine ruleEngine = new DroolsRuleEngine();
public Money calculateDiscount(List<OrderLine> orderLines, String customerId) {
Customer customer = findCustomer(customerId);
// ์ด๊ธฐ ๋
MutableMoney money = new MutableMoney(0);
// DroolsRulsEngine ์ฌ์ฉ์ ์ํ ์กฐ๊ฑด ์ถ๊ฐ
List<?> conditions = Arrays.asList(customer, money);
conditions.addAll(orderLines);
// DroolsRulsEngine์ ์ด์ฉํด ํ ์ธ์จ ์ ์ฉ
ruleEngine.evaluate("discountCalculation", conditions);
// ํ ์ธ์จ ์ ์ฉ ๋ ๋์ ๋ถ๋ณ์ผ๋ก ๋ณ๊ฒฝ
return money.toImmutableMoney();
}
}
์ ์ฝ๋๋ 2๊ฐ์ง ๋ฌธ์ ์ ์ ๊ฐ์ง๊ณ ์์
- ํ
์คํธํ๊ธฐ ์ด๋ ค์
- DroolsRuleEngine์ด ์๋ฒฝํ๊ฒ ๋์ํด์ผ๋ง CalculateDiscountService๋ฅผ ํ ์คํธ ๊ฐ๋ฅ
- ๊ตฌํ ๋ฐฉ์์ ๋ณ๊ฒฝํ๊ธฐ ์ด๋ ค์
- DroolsRuleEngine์ด ์๋๋ผ ๋ค๋ฅธ ์์ง์ ์ฌ์ฉํ๋๋ก ๋ณ๊ฒฝํ๊ณ ์ ํ๋ค๋ฉด ๋ง์ ๋ถ๋ถ์ด ๋ณ๊ฒฝ๋์ด์ผํจ
- Ex) DIP ๊ฐ ์ ์ฉ๋ ์ฃผ๋ฌธ ์ ํ ์ธ์จ ์ ์ฉ ์ฝ๋
interface RuleDiscounter {
public Money applyRules(Customer customer, List<OrderLine> orderLines);
}
class CalculateDiscountService {
private RuleDiscounter ruleDiscounter;
public CalculateDiscountService(RuleDiscounter ruleDiscounter) {
this.ruleDiscounter = ruleDiscounter;
}
public Money calculateDiscount(List<OrderLine> orderLines, String customerId) {
Customer customer = findCustomer(customerId);
return ruleDiscounter.applyRules(customer, orderLines);
}
}
class DroolsRuleDiscounter implements RuleDiscounter {
@Override
public Money calculateDiscount(List<OrderLine> orderLines, String customerId) {
...
}
}
์ ์์ค ๋ชจ๋์ด ๊ณ ์์ค ๋ชจ๋์ ์์กดํ๋๋ก ๋ณ๊ฒฝ
- CalculateDiscountService ์
์ฅ์์๋ ํ ์ธ์จ ๋ฃฐ ์ ์ฉ์ ์ด๋ค ์์ง์ ํตํด ๊ตฌํํ๋์ง ์ค์ํ์ง ์์
- ๊ณ ๊ฐ ์ ๋ณด์ ๊ตฌ๋งค ์ ๋ณด์ ํ ์ธ์จ ๋ฃฐ์ ์ ์ฉํด์ ํ ์ธ ๊ธ์ก์ ๊ตฌํ๋ค๋ ์ฌ์ค๋ง ์ค์
- CalculateDiscountService ๋ ๋ ์ด์ ๊ตฌํ ๊ธฐ์ ์ธ DroolsRuleDiscounter ์ ์์กดํ์ง ์๊ณ ์ถ์ํํ ๊ณ ์์ค ๋ชจ๋์ธ RuleDiscounter ์ ์์กด
์ 2๊ฐ์ง ๋ฌธ์ ๋ ํด๊ฒฐ ํ ์ ์์
- ํ
์คํธํ๊ธฐ ์ฌ์
- ํน์ ํด๋์ค๊ฐ ์๋๋ผ ์ธํฐํ์ด์ค์ ์์กดํ๋ฏ๋ก mockito๋ฅผ ์ฌ์ฉํ stub ๋ฑ์ ์ฌ์ฉํ๋ค๋ฉด ์ง์ ๊ตฌํ์ฒด๋ฅผ ๊ตฌํํ์ง ์๊ณ ๋ ํ ์คํธ๋ฅผ ์งํํ ์ ์๊ฒ ๋๋ค
public class CalculateDiscountServiceTest {
@Test(expected = NoCustomerException.class);
public void noCustomer_thenExceptionShouldBeThorwn() {
// ํ
์คํธ ๋ชฉ์ ์ ๋์ฉ ๊ฐ์ฒด๋ฅผ ์์ฑ
CustomerRepository stubRepo = mock(CustomerRepository.class);
when(stubRepo.findById("noCustomerId")).thenReturn(null);
RuleDiscounter stubRule = (customer, lines) -> null;
// ํ
์คํธ ๋ชฉ์ ์ ๋์ฉ ๊ฐ์ฒด๋ฅผ ์ฃผ์
๋ฐ์ ํ
์คํธ ์งํ
CalculateDiscountService calcDiscountService = new CalculateDiscountService(stubRepo, stubRule);
calcDiscountService.calculateDiscount(someLines, "noCustomerId");
}
}
- ๊ตฌํ ๋ฐฉ์์ ๋ณ๊ฒฝํ๊ธฐ ์ฌ์
- ์ ์์ค ๋ชจ๋์ ๊ฐํ๊ฒ ๊ฒฐํฉ๋์ด ์๋ ๊ตฌ์กฐ๊ฐ ์๋๊ธฐ ๋๋ฌธ์, ๊ตฌํ ๊ธฐ์ ์ ๋ณ๊ฒฝํ๋๋ผ๋ CalculateDiscountService๋ฅผ ์์ ํ ํ์๊ฐ ์์
// ์ฌ์ฉํ ์ ์์ค ๊ฐ์ฒด ์์ฑ (Drool ์์ง ์ฌ์ฉ)
RuleDiscounter ruleDiscounter = new DroolsRuleDiscounter();
// ์ฌ์ฉํ ์ ์์ค ๊ฐ์ฒด ๋ณ๊ฒฝ (๋๋ค๋ฅธ ์ ์์ค ๋ชจ๋ ์ฌ์ฉ)
RuleDiscounter ruleDiscounter = new SimpleRuleDiscounter();
// ์์ฑ์ ๋ฐฉ์์ผ๋ก ์ฃผ์
ํ๊ณ , ์ ์์ค ๋ชจ๋์ ์ ๊ฐ์ด ๋ณ๊ฒฝํ๋๋ผ๋ ๊ณ ์์ค ๋ชจ๋์ ์์ ํ ํ์ ์์
CalculateDiscountService discountService = new CalculateDiscountService(ruleDiscounter);
๋๋ฉ์ธ ์์ญ์ ์ฃผ์ ๊ตฌ์ฑ์์
- ์ํฐํฐ
- ๊ณ ์ ์ ์๋ณ์๋ฅผ ๊ฐ์ง๊ณ ์์ ์ ๋ผ์ดํ ์ฌ์ดํด์ ๊ฐ๋ ๊ฐ์ฒด
- ๋ฐ์ดํฐ์ ๋ฐ์ดํฐ์ ๊ด๋ จ๋ ๊ธฐ๋ฅ์ ํจ๊ป ์ ๊ณต
- ex) ์ฃผ๋ฌธ(Order), ํ์(Member), ์ํ(Product)
- ๋๋ฉ์ธ ๋ชจ๋ธ์ ์ํฐํฐ์ DB ๋ชจ๋ธ์ ์ํฐํฐ๋ ๋ค๋ฆ
- RDBMS๋ ๋ฐธ๋ฅ๋ฅผ ์ ๋๋ก ํํํ๊ธฐ ํ๋ฌ
- ORDER_NAME, ORDER_EMAIL ํ๋๋ก ํ์ํ๊ฑฐ๋ ๋๋ ORDER_ORDERER ํ ์ด๋ธ๋ก ํ์ํ๋๋ผ๋ ๋ฑํ ๋ฐธ๋ฅ ํ์ ์ ์๋ฏธ๊ฐ ๋๋ฌ๋์ง ์์
- ๋ฐธ๋ฅ
- ๊ณ ์ ์ ์๋ณ์๋ฅผ ๊ฐ์ง ์๊ณ ์ฃผ๋ก ๋๋ฉ์ธ ๊ฐ์ฒด์ ์์ฑ์ ํํํ ๋ ์ฌ์ฉ๋๋ ๊ฐ์ฒด
- ์ํฐํฐ์ ์์ฑ์ผ๋ก ๋ฟ๋ง ์๋๋ผ, ๋ค๋ฅธ ๋ฐธ๋ฅ ํ์ ์ ์์ฑ์ผ๋ก๋ ์ฌ์ฉ๋ ์ ์์
- ์ ๊ทธ๋ฆฌ๊ฑฐํธ
- ๊ด๋ จ๋ ์ํฐํฐ์ ๋ฐธ๋ฅ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ ์ ์ผ๋ก ํ๋๋ก ๋ฌถ์ ๊ฒ
- ๋๋ฉ์ธ์ด ์ปค์ง์๋ก ๊ฐ๋ฐํ ๋๋ฉ์ธ ๋ชจ๋ธ๋ ์ปค์ง๊ฒ ๋๊ณ , ๋ง์ ์ํฐํฐ์ ๋ฒจ๋ฅ๊ฐ ์๊ธฐ๋ฉด์ ๋ชจ๋ธ์ด ์ ์ ๋ ๋ณต์กํด์ง
-> ๊ฐ๋ฐ์๊ฐ ์ ์ฒด ๊ตฌ์กฐ๊ฐ ์๋ ํ๊ฐ ์ํฐํฐ์ ๋ฒจ๋ฅ์ ์ง์คํ๊ฒ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ - ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ฅผ ํตํด ๋๋ฉ์ธ ๋ชจ๋ธ์ ๊ฐ๋ณ ๊ฐ์ฒด๊ฐ ์๋๋ผ ์์ ์์ค์์ ๋ชจ๋ธ์ ๋ณผ ์ ์์ด์ผ ์ ์ฒด ๋ชจ๋ธ๊ณผ ๊ฐ๋ณ ๋ชจ๋ธ์ ์ดํดํ๋๋ฐ ๋์์ด ๋จ
- ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ ๊ตฐ์ง์ ์ํ ๊ฐ์ฒด๋ค์ ๊ด๋ฆฌํ๋ ๋ฃจํธ ์ํฐํฐ๋ฅผ ๊ฐ์ง
- ๋ฃจํธ ์ํฐํฐ๋ ์ ๊ทธ๋ฆฌ๊ฑฐํธ์ ์ํด ์๋ ์ํฐํฐ์ ๋ฐธ๋ฅ ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๊ฐ ๊ตฌํํด์ผ ํ ๊ธฐ๋ฅ์ ์ ๊ณต
- ex) Order ๋ฃจํธ ์ํฐํฐ, OrderLine ๋ฐธ๋ฅ, Orderer ๋ฐธ๋ฅ -> ์ฃผ๋ฌธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ
- ๋ฆฌํฌ์งํฐ๋ฆฌ
- ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์ง์์ ์ผ๋ก ์ฌ์ฉํ๋ ค๋ฉด RDBMS ๊ฐ์ ๋ฌผ๋ฆฌ์ ์ ์ฅ์์ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๋ณด๊ดํด์ผ ํ๊ณ , ์ด๋ฅผ ์ํ ๋๋ฉ์ธ ๋ชจ๋ธ
- ๋๋ฉ์ธ ๋ชจ๋ธ์ ์์์ฑ์ ์ฒ๋ฆฌํจ
- ๋ฆฌํฌ์งํฐ๋ฆฌ๋ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ์์ํํ๋๋ฐ ํ์ํ ๊ธฐ๋ฅ์ ์ถ์ํ ํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๊ณ ์์ค ๋ชจ๋์ ์ํ๊ณ , ์ค์ ๊ตฌํ ํด๋์ค๋ ์ธํ๋ผ์คํธ๋ญ์ณ ์์ญ์ ์ํจ
- ์์ฉ ์๋น์ค๋ ํ์ํ ๋๋ฉ์ธ ๊ฐ์ฒด๋ฅผ ๊ตฌํ๊ฑฐ๋ ์ ์ฅํ ๋ ๋ฆฌํฌ์งํฐ๋ฆฌ๋ฅผ ์ด์ฉ
- ๋๋ฉ์ธ ์๋น์ค
- ํน์ ์ํฐํฐ์ ์ํ์ง ์์ ๋๋ฉ์ธ ๋ก์ง์ ์ ๊ณตํจ
- ๋๋ฉ์ธ ๋ก์ง์ด ์ฌ๋ฌ ์ํฐํฐ์ ๋ฒจ๋ฅ๋ฅผ ํ์๋ก ํ ๊ฒฝ์ฐ ์ฌ๊ธฐ์์ ๋ก์ง์ ๊ตฌํํ๋ค
- ex) "ํ ์ธ ๊ธ์ก ๊ณ์ฐ" ์ ๊ตฌํํ๊ธฐ ์ํด์๋ ์ํ, ์ฟ ํฐ, ํ์ ๋ฑ๊ธ, ๊ตฌ๋งค ๊ธ์ก ๋ฑ ๋ค์ํ ์ํฐํฐ์ ๋ฐธ๋ฅ๊ฐ ํ์
๋ชจ๋ ๊ตฌ์ฑ
- ๊ธฐ๋ณธ์ ์ผ๋ก ์ฐ๋ฆฌ๋ ํญ์ ์ํคํ ์ณ๊ฐ ๊ฐ ์์ญ์ด ๋ณ๋ ํจํค์ง์ ์์นํ๋ ํํ๋ก ๊ตฌ์ฑ
com.myshop.interface
com.myshop.application
com.myshop.domain
com.myshop.infrastructure
- ๋๋ฉ์ธ์ด ํฌ๋ฉด ํ์ ๋๋ฉ์ธ๋ง๋ค ๋ณ๋ ํจํค์ง๋ฅผ ๊ตฌ์ฑ
// ํ์ ๋๋ฉ์ธ
com.myshop.member.interface
com.myshop.member.application
com.myshop.member.domain
com.myshop.member.infrastructure
// ์ฃผ๋ฌธ ๋๋ฉ์ธ
com.myshop.order.interface
com.myshop.order.application
com.myshop.order.domain
com.myshop.order.infrastructureโ
- ๋๋ฉ์ธ ๋ด๋ถ์์ ์๋ก๋ค๋ฅธ ์ ๊ทธ๋ฆฌ๊ฑฐํธ๋ก ๋๋ ์ง๋ ๊ฒฝ์ฐ ๋ถ๋ฆฌํ ์ ์์
com.myshop.order.interface
com.myshop.order.application
com.myshop.order.domain.product
com.myshop.order.domain.category
com.myshop.order.infrastructure
- ๋ง์ฝ ๋๋ฉ์ธ ์๋น์ค ๊ณ์ธต์ด ๋ฐ๋ก ์์ผ๋ฉด ์๋์ ๊ฐ์ด ๋๋ ์ ์์
com.myshop.order.domain.product
com.myshop.order.domain.category
com.myshop.order.domain.service
๋ชจ๋ ๊ตฌ์ฑ์ ์ ๋ต์ ์์ง๋ง ๊ฐ๋ฅํ๋ฉด ํ ํจํค์ง๋ด์ 10๊ฐ ๋ฏธ๋ง์ผ๋ก ๋๋ฉ์ธ ํ์
๊ฐ์๋ฅผ ์ ์งํ๋ ๊ฒ์ด GOOD
์ต๋ฒ๊ท ์๊ฐ๋์ DDD START! 2์ฅ์ ์์ฝํ์ต๋๋ค.
'Programming Books > DDD START!' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Chapter 1. ๋๋ฉ์ธ ๋ชจ๋ธ ์์ (0) | 2022.08.14 |
---|
๋๊ธ