133
좌충우돌 ORM 개발기 Daum 김영한

좌충우돌 ORM 개발기 2012 DAUM DEVON

Embed Size (px)

Citation preview

Page 1: 좌충우돌 ORM 개발기 2012 DAUM DEVON

좌충우돌 ORM개발기Daum 김영한

Page 2: 좌충우돌 ORM 개발기 2012 DAUM DEVON

목차

• 프로젝트 구조와 모순

• Why ORM?

• DEMO 프로젝트

• ORM 적용시 고민할 2가지 구조

• Domain Model Everywhere

• DTO, Pure Domain Model

Page 3: 좌충우돌 ORM 개발기 2012 DAUM DEVON

프로젝트 구조와 모순

Page 4: 좌충우돌 ORM 개발기 2012 DAUM DEVON

화면 중심 프로젝트

• 화면 중심으로 프로젝트 구조를 구성

• View 단위로 개발자 투입

• Service, Dao, Entity를 각자 만들어 써야함, 공유하는 것은 허용하지 않음

Page 5: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원관리 화면 Package controller (MemberController) service (MemberService) dao (MemberDao) entity (Member)

상품 관리 화면 Package controller (ProductController) service (ProductService) dao (ProductDao) entity (Product)

Page 6: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원관리화면 상품관리화면 주문관리화면

A개발자 B개발자 C개발자

Page 7: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원관리화면

상품관리화면

주문관리화면

A개발자

B개발자

C개발자

MemberControll MemberServi MemberDa MemberEntit

ProductControlle ProductServi ProductDao ProductEntity

OrderController OrderService OrderDao OrderEntity

Page 8: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원관리화면

상품관리화면

주문관리화면

A개발자

B개발자

C개발자

MemberControll MemberServi MemberDa MemberEntit

MemberDa MemberEntit

MemberDa MemberEntit

ProductControlle ProductServi ProductDao ProductEntity

OrderController OrderService OrderDao OrderEntity

ProductDao ProductEntity

중복!!!

Page 9: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 프로젝트가 계속 진행되면...

Page 10: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 같거나 유사한 Query가 무수히 나타남

• 회원정보 조회의 경우 11번의 거의 동일한 쿼리 발견

• 수정이 아주 어려움

• 월화수목금금금... --;

Page 11: 좌충우돌 ORM 개발기 2012 DAUM DEVON

화면중심 프로젝트 구조는 수 많은 중복을 만든다.

Page 12: 좌충우돌 ORM 개발기 2012 DAUM DEVON

일반적인 프로젝트

• 데이터와 비지니스 로직을 중심으로프로젝트를 설계한다.

Page 13: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원관리, 상품관리controller - MemberController - ProductControllerservice - MemberService - ProductServicedao - MemberDao - ProductDaoentity - Member - Product

MemberController

ProductController

MemberService

ProductService

MemberDao

ProductDao

Member Product

Page 14: 좌충우돌 ORM 개발기 2012 DAUM DEVON

실전에선 멀티 프로젝트

FRONT

ADMIN

BATCH

A,B개발자

C,D개발자

E개발자

Page 15: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ADMIN

BATCH

FRONTMember

DaoMemberEntity

MemberDao

MemberEntity

MemberDao

MemberEntity

중복!!!

Page 16: 좌충우돌 ORM 개발기 2012 DAUM DEVON

MemberDao

MemberEntity

MemberDao

MemberEntity

MemberDao

MemberEntity

FRONT ADMIN BATCH

Page 17: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

멀티 모듈 프로젝트

MemberDao

MemberEntity

MemberDao

MemberEntity

MemberDao

MemberEntity

FRONT ADMIN BATCH

Page 18: 좌충우돌 ORM 개발기 2012 DAUM DEVON

사용되는 Member의 정보

FRONT

MemberEntity

회원이름

나이 성별

Page 19: 좌충우돌 ORM 개발기 2012 DAUM DEVON

MemberEntity

회원이름

나이 성별

주민번호

회원번호

전화번호

사용되는 Member의 정보

ADMIN

Page 20: 좌충우돌 ORM 개발기 2012 DAUM DEVON

사용되는 Member의 정보

BATCH

MemberEntity

회원이름

성별

주민번호

회원번호

Page 21: 좌충우돌 ORM 개발기 2012 DAUM DEVON

데이터 불일치

• CORE로 통합시 또 다른 문제 발생

• SQL의 Projection은 각 모듈의 비즈니스 로직과 View에 최적화

• findFrontMemberfindAdminMember ...???

Page 22: 좌충우돌 ORM 개발기 2012 DAUM DEVON

데이터 불일치 해결 방안

• Row단위로 전체 조회

• 특별한 경우만 최적화

• 파레토법칙(20/80법칙)

Page 23: 좌충우돌 ORM 개발기 2012 DAUM DEVON

하지만...

Page 24: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

회원 회원관리직원멤버십카드

Page 25: 좌충우돌 ORM 개발기 2012 DAUM DEVON

class Member { Card card; Manager manager;

Card getCard(); Manager getManager();

}

회원 회원관리직원멤버십카드

Page 26: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

회원 회원관리직원멤버십카드

Front

SQL : Member Join CardCode : member.getCard()

member.gerManager() ???

Page 27: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

NullPointException!!!NullPointException!!!NullPointException!!!NullPointException!!!

Page 28: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

회원 회원관리직원멤버십카드

Admin

SQL : Member Join ManagerCode : member.getManager()

member.getCard() ???

Page 29: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

NullPointException!!!NullPointException!!!NullPointException!!!NullPointException!!!

Page 30: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

회원 회원관리직원멤버십카드

Batch

SQL : Member Join Manager Join CardCode : member.getManager(), member.getCard()

불필요한 조인, 성능 낭비

Page 31: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

회원 회원관리직원멤버십카드

Front

Admin

Batch

Page 32: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Join의 경우

• Entity가 실행한 SQL에 데이터를 의존

• Entity에 구멍이남

• 결국 비즈니스 로직이 SQL에 의존

• 모든 데이터를 메모리에 올리는 것은 현실적이지 않음

Page 33: 좌충우돌 ORM 개발기 2012 DAUM DEVON

프로젝트 구조와 모순의 결론

• Entity가 SQL에 의존

• 구멍난 Entity

• 신뢰할 수 없는 Entity

• 진정한 의미의 계층 분할이 어려움

Page 34: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Why ORM?

Page 35: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM을 사용하는 이유

• Projection 문제

• Join 관련 데이터 연결 문제

• Entity 데이터에 대한 신뢰

• 제대로 된 프로젝트 구조

• CRUD SQL좀 알아서 해줬으면

• 진정한 객체 지향 개발 가능

• 도메인 주도 개발 가능

Page 36: 좌충우돌 ORM 개발기 2012 DAUM DEVON

SQL을 사용해야 하는 이유

• 우리가 사용 중인 DB는 RDB다!!!

• 통계 데이터

• 아주 복잡한 View

Page 37: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM을 사용하는 진짜 이유!

컴퓨터가 할 수 있는 일을 더이상 사람이 하지 말자 나는 SQL MAPPER가 아니다!

Page 38: 좌충우돌 ORM 개발기 2012 DAUM DEVON

JDBC xBatis

ORM

Page 39: 좌충우돌 ORM 개발기 2012 DAUM DEVON

여기서 잠깐!

Page 40: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : OBJECT DB같은 것 아닌가요? 이미 망한 기술로 알고 있는데요?

Page 41: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : 성능이 느리다.

Page 42: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : ORM을 사용하면 SQL을 못쓴다.

Page 43: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : SQL을 몰라도 되나요?

Page 44: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : 공부할 내용이 많으면 어쩌지...

Page 45: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM에 관한 오해

Q : 모두 iBatis, myBatis만 사용하는데요?

A : 진실은?

Page 46: 좌충우돌 ORM 개발기 2012 DAUM DEVON

2012년 8월 한국 구글 검색

myBatis iBatis Hibernate JPA

Page 47: 좌충우돌 ORM 개발기 2012 DAUM DEVON

2012년 8월 인도 구글 검색

myBatis iBatis Hibernate JPA

Page 48: 좌충우돌 ORM 개발기 2012 DAUM DEVON

2012년 8월 미국 구글 검색

myBatis iBatis Hibernate JPA

Page 49: 좌충우돌 ORM 개발기 2012 DAUM DEVON

2012년 8월 전세계 구글 검색

myBatis iBatis Hibernate JPA

Page 50: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM을 사용하고 싶은데 어떻게 시작하나요?

• 공부해야 합니다!

Page 51: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• JPA?

• Hibernate?

• SpringDataJPA

• QueryDSL

Page 52: 좌충우돌 ORM 개발기 2012 DAUM DEVON

DEMO 프로젝트

Page 53: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 사용된 기술 : JPA2, Hibernate, Spring-Data-JPA, QueryDSL, Spring, Maven

• source : https://github.com/holyeye/devon2012

멤버십 프로젝트

Page 54: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원

카드

회원카드

카드적립 포인트

1 : N N : 1

1:

N

적립률

도메인 모델

Create

Page 55: 좌충우돌 ORM 개발기 2012 DAUM DEVON

도메인 객체@Getter @Setter@Entitypublic class Member extends BaseEntity<Long>{

private String name;private int age;

@OneToMany(mappedBy="member")List<MemberCard> memberCards = new ArrayList<MemberCard>();

public void addMemberCard(MemberCard memberCard) {memberCards.add(memberCard);

}}

@Getter @Setter@Entitypublic class Card extends BaseEntity<Long>{

private String name;private int rate; //적립률

//createpublic CardPoint createCardPoint(int money) {

return new CardPoint(name,money,rate);}

}

Page 56: 좌충우돌 ORM 개발기 2012 DAUM DEVON

@Getter @Entitypublic class MemberCard extends BaseEntity<Long>{

@OneToMany(cascade=CascadeType.PERSIST) @JoinColumn(name="memberCard_id")private List<CardPoint> cardPoints = new ArrayList<CardPoint>();

@ManyToOne private Member member;@ManyToOne private Card card;

//BIZpublic void payMoney(int money) {

CardPoint createCardPoint = card.createCardPoint(money);addCardPoint(createCardPoint);

}

//VIEW Logicpublic int getTotalPoint() {

int totalPoint = 0;for (CardPoint cardPoint : cardPoints) {

totalPoint += cardPoint.getPoint();}return totalPoint;

}}

Page 57: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원 조회, QueryDSL

@RequestMapping("member/home")public String home(MemberCond cond, Model model) {

//QUERY DSLQMember qMember = QMember.member;BooleanExpression containsName = qMember.name.contains(cond.getName());BooleanExpression gtAge = qMember.age.gt(cond.getAge());

model.addAttribute("members",memberRepository.findAll(containsName.and(gtAge)));

return "member/home";} public interface MemberRepository extends

JpaRepository<Member, Long>, QueryDslPredicateExecutor<Member>{

}

select * from Member memberwhere (member.name like '%서%') and member.age > 26

Page 58: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원 등록, SpringDataJPA

@RequestMapping("member/saveMember")public String saveMenu(Member member) {

memberRepository.save(member);return "redirect:/member/home";

}

public interface MemberRepository extendsJpaRepository<Member, Long>, QueryDslPredicateExecutor<Member>{

}

`

Page 59: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원 수정, Web Binding

/member/memberUpdateForm?id=

@RequestMapping("member/memberUpdateForm")public String memberUpdateForm(@RequestParam("id") Member member, Model model) {

model.addAttribute("member", member);return "member/memberSaveForm";

}

1

Member

Page 60: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원카드 결제하기 = ORM 저장

10000만원 결제, 10% 적립

Page 61: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원카드

카드적립 포인트

Domain Driven Design 살짝 맛보기

Aggregate ROOT

Aggregate(집합)

MemberCardRepository

Page 62: 좌충우돌 ORM 개발기 2012 DAUM DEVON

회원카드 결제하기 = ORM 저장@RequestMapping("memberCard/payMoney")public String payMoney(

@RequestParam("memberCardId") MemberCard memberCard,@RequestParam("money") int money) {

memberCardService.payMoney(memberCard, money);return "redirect:/memberCard/home";

} @Service@Transactionalpublic class MemberCardService {

public void payMoney(MemberCard memberCard, int money) {memberCard.payMoney(money);

}} public class MemberCard {

@OneToMany(cascade=CascadeType.PERSIST) @JoinColumn(name="memberCard_id")private List<CardPoint> cardPoints = new ArrayList<CardPoint>();

public void payMoney(int money) {CardPoint createCardPoint = card.createCardPoint(money);cardPoints.add(createCardPoint);

}public class Card{

private String name;private int rate;public CardPoint createCardPoint(int money) {

return new CardPoint(name,money,rate);}

}

Auto SAVE

`

`

Page 63: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Spring-Data-JPA 소개

• interface로 Repository 자동 생성(CRUD, 조회)

• simple queriesex) findByName(String name) select * from member where name={name}

• pagination

• Web Binding

• Specifications, QueryDSL지원

Page 64: 좌충우돌 ORM 개발기 2012 DAUM DEVON

QueryDSL 소개

• type-safe JPA queries - 단단하다

• 단순하고 쉽다.

• 지속적인 버전업

• Spring Data에서도 사용가능

Page 65: 좌충우돌 ORM 개발기 2012 DAUM DEVON

ORM 적용시 고민할 2가지 구조

Page 66: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• ORM을 적용하는 방법은 크게 2가지

• Domain Model Everywhere

• Pure Domain Model

Page 67: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Domain Model Everywhere vs

Pure Domain Model

Page 68: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Domain Model Everywhere

Controller Service Repository

Entity+Getter,Setter

+BizLogic+ViewLogic

King

View

Page 69: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• Domain Model을 모든 Layer에서 적극 사용하자.

• OSIV(Open Session In View) 사용

• Getter, Setter 사용

• DTO는 중복 악마다!

Domain Model Everywhere

Page 70: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 장점• 개발하기에 빠르고 편리함

• 단점• 복잡한 View 표현 힘듬

• Domain Model의 Getter, Setter를 노출, View로직 추가

• Domain Model의 순수성이 떨어짐

• XML, JSON, 외부와의 통신API 위험 = 도메인 모델은 생각보다 자주 변함

Domain Model Everywhere

Page 71: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Domain Model Everywhere

Controller Service Repository

Entity+Getter,Setter

+BizLogic+ViewLogic

King

View

Page 72: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Pure Domain Model

Controller Service Repository

Entity+BizLogic

View

DTO+Getter,Setter

+ViewLogic

Converter

Page 73: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 도메인모델에 Getter, Setter는 지옥행

• 도메인모델에 View로직은 지옥행

• OSIV(Open Session In View)는 지옥행

• 도메인모델을 객체답게 만들어라!

Pure Domain Model

Page 74: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Pure Domain Model

Robert C. Martin(uncle bob) 필독서!!!

Page 75: 좌충우돌 ORM 개발기 2012 DAUM DEVON

OOP캡슐화, 다형성

내부 변수를 노출하지 않음

일반적으로 Getter, Setter 를 이용해서 내부 변수를 모두 노출사이비 캡슐화

Pure Domain Model

객체(Domain Model)

자료 구조(DTO)

Page 76: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Pure Domain Model

객체(Domain Model)

+

자료 구조(DTO)

Page 77: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Pure Domain Model

객체(Domain Model)

자료 구조(DTO)

+ =

잡종

Page 78: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Pure Domain Model

잡종

이런 잡종 구조는 새로운 함수는 물론이고 새로운 자료 구조도 추가하기 어렵다.

양쪽 세상에서 단점만 모아 놓은 구조다. 그러므로 잡종 구조는 되도록 피하는 편이 좋다.

- Clean Code, Chapter 6 객체와 자료구조 -

Page 79: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 그럼 어떻게 개발하라고요--;

Pure Domain Model

Page 80: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• CQRS Pattern, DTO 활용

• 도메인 모델 = 비즈니스 로직

• View는 DTO만 사용

Pure Domain Model

Page 81: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS

• Command Query Responsibility Segregation

• 등록,수정,삭제 같은 명령어와조회용 쿼리를 분리!

Page 82: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS

• QueryService

• CommandService

Page 83: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Command Query

변경 가끔 변경됨 자주 변경됨

검증 O X

비즈니스 로직수정

O X

Page 84: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 장점

• 순수한 Domain Model

• 단점

• DTO를 만드는 것은 귀찮다, 성가시다. 괴롭다.

• DTO는 또다른 중복이다.

• DTO와 Domain Model의 Convert를 고민해야 한다.

Pure Domain Model

Page 85: 좌충우돌 ORM 개발기 2012 DAUM DEVON

결론

Page 86: 좌충우돌 ORM 개발기 2012 DAUM DEVON

그럼 어떻게 해요?

Page 87: 좌충우돌 ORM 개발기 2012 DAUM DEVON

여기서 부턴 지극히 주관적입니다.

Page 88: 좌충우돌 ORM 개발기 2012 DAUM DEVON

순수한 객체No Getter, Setter!Law of Demeter

SRP, DIP, OCP, ISP, LSP

도메인 객체는 순수해야 한다!

Page 89: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Domain Model Everywhere

객체의 순수성을 파괴하는 사악한 방법!

Getter, Setter 필수 Entity = 자료구조+객체

Page 90: 좌충우돌 ORM 개발기 2012 DAUM DEVON

이라고 믿고 살았습니다... 직접 개발해 보기 전까진...

Page 91: 좌충우돌 ORM 개발기 2012 DAUM DEVON

진짜 ORM 개발을 해보신 분은 아시겠지만...

Page 92: 좌충우돌 ORM 개발기 2012 DAUM DEVON

도메인 모델만으로 모든 View를 표현하는 것은 한계가 있습니다.

Page 93: 좌충우돌 ORM 개발기 2012 DAUM DEVON

항상 DTO를 만드는 것은 실용적이지 않습니다.

Page 94: 좌충우돌 ORM 개발기 2012 DAUM DEVON

결론

Domain Model Everywhere 로 시작

Domain Model로 처리하기 힘든복잡하고 특별한 경우에는CQRS, DTO를 사용

Page 95: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• Domain Driven Design

• Pure Domain Model 을 유지하며 실용적으로 개발하는 방법

• DTO를 생성하는 방법, 활용법

• ex) http://modelmapper.org/

• ex) Builder Pattern

우리의 과제

Page 96: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• 이터너티님의 블로그(http://aeternum.egloos.com)

• 백기선님 블로그 (http://whiteship.me)

• 이미 2005년에 작성된 토비님의 아티클

Domain Model vs. DTO : http://toby.epril.com/?p=99

• 실전 코드가 있는 자바지기님의 DTO에 관한 최근 아티클 : http://www.slipp.net/wiki/pages/viewpage.action?pageId=2031636

• Javacan님의 DDD 발표자료 : http://javacan.tistory.com/entry/DDD-

%EC%8C%A9%EA%B8%B0%EC%B4%88-%EC%84%B8%EB%AF%B8%EB%82%98-%EB%B0%9C%ED%91%9C-%EC%9E%90%EB%A3%8C

좋은 자료

Page 97: 좌충우돌 ORM 개발기 2012 DAUM DEVON

• Clean Code (Chapter 6 객체와 자료 구조)

• http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/

• http://martinfowler.com/bliki/CQRS.html

참고

Page 98: 좌충우돌 ORM 개발기 2012 DAUM DEVON

감사합니다.

Page 99: 좌충우돌 ORM 개발기 2012 DAUM DEVON

시간이 부족해서 발표하지 못한 내용입니다. Domain Model Everywhere에서 DTO, CQRS를 사용해

Pure Domain Model로 리펙토링되는 상황을 연출해 보았습니다.

Page 100: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

• Entity는 비즈니스 로직을 위한 것이지 View를 위한 것이 아니다.

Page 101: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITY+BIZ LOGIC

Page 102: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITY+BIZ LOGIC+ViewA로직

View AView A

Page 103: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITY+BIZ LOGIC+ViewA로직+ViewB로직

View A

View B

Page 104: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITY+BIZ LOGIC+ViewA로직+ViewB로직+ViewC로직

.....

View A

View B

View C

그래 나 뚱뚱하다!

Page 105: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

• Entity가 View 로직 때문에 뚱뚱해진다.

• OSIV 사용

• JSON, XML 문제점

• 객체 그래프를 찾아 가는 것을 View개발자가 힘들어 한다. ex) member.getCard().getData()...

Page 106: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

• View를 위한 DTO 가 필요한 시점

Page 107: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITYBIZ LOGIC+ViewA로직+ViewB로직+ViewC로직

.....

View A

View B

View C

그래 나 뚱뚱하다!

Page 108: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITYBIZ LOGIC

View A

View B

View C

회원DTO+ViewA로직+ViewB로직+ViewC로직

Page 109: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

회원ENTITYBIZ LOGIC

View A

View B

View C

회원DTO+ViewA로직+ViewB로직+ViewC로직

View D 회원관리DTO+ViewD로직

Page 110: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Entity and View

• View와 비즈니스 로직의 요구사항 다름

• Entity = 비즈니스 로직

• DTO = VIEW

Page 111: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

• 이제는 Service가 뚱뚱해 진다.

Page 112: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC+ViewA로직+ViewB로직+ViewC로직

.....

View A

View B

View C

그래 나 뚱뚱하다!

Page 113: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC+ViewA로직+ViewB로직+ViewC로직

.....

View A

View B

View C

그래 나 뚱뚱하다!

회원Service+회원등록()+회원수정()+회원탈퇴()

+getMember()

Page 114: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC

회원DTO+ViewA로직+ViewB로직+ViewC로직

View A

View B

View C

회원Service+회원등록()+회원수정()+회원탈퇴()

+getMemberDTO()

Page 115: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC

View A

View B

View C

회원DTO+ViewA로직+ViewB로직+ViewC로직

View D 회원관리DTO+ViewD로직

회원Service+회원등록()+회원수정()+회원탈퇴()

+getMemberDTO()+getMemberManageDTO()

...DTO()

그래 나 뚱뚱하다!

Page 116: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

• 음... 이건 어떻게 하지?

Page 117: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

• 등록,수정,삭제 같은 명령어와 조회용 쿼리를 분리하자!

Page 118: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC

View A

View B

View C

회원DTO+ViewA로직+ViewB로직+ViewC로직

View D 회원관리DTO+ViewD로직

회원Service+회원등록()+회원수정()+회원탈퇴()

+getMemberDTO()+getMemberManageDTO()

...DTO()

그래 나 뚱뚱하다!

Page 119: 좌충우돌 ORM 개발기 2012 DAUM DEVON

뚱뚱한 Service

회원ENTITYBIZ LOGIC

View A

View B

View C

회원DTO+ViewA로직+ViewB로직+ViewC로직

View D 회원관리DTO+ViewD로직

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원QueryService+getMemberDTO

()+getMemberManageDTO()

...DTO()

Page 120: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS

• Command Query Responsibility Segregation

• 등록,수정,삭제 같은 명령어와조회용 쿼리를 분리!

Page 121: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS

• QueryService

• CommandService

Page 122: 좌충우돌 ORM 개발기 2012 DAUM DEVON

Command Query

변경 가끔 변경됨 자주 변경됨

검증 O X

비즈니스 로직수정

O X

Page 123: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS 적용 전

출처 : http://martinfowler.com/bliki/CQRS.html

Page 124: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CQRS 적용 후

출처 : http://martinfowler.com/bliki/CQRS.html

Page 125: 좌충우돌 ORM 개발기 2012 DAUM DEVON

멀티 모듈인 경우

• 멀티 모듈인 경우를 생각해보자

Page 126: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원Service+회원등록()+회원수정()+회원탈퇴()

+getMemberDTO()+getMemberManageDTO()

...DTO()

Page 127: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원QueryService+getMember

DTO()+getMemberManageDTO()

Page 128: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원QueryService+getMemberDTO

()+getMemberManageDTO()+getFrontMemberDTO()+getBatchMemberDTO()

Page 129: 좌충우돌 ORM 개발기 2012 DAUM DEVON

멀티 모듈인 경우

• 각각의 모듈에 특화된 Query

• Core에 두는 것이 옳은가?

Page 130: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원QueryService+getMemberDTO

()+getMemberManageDTO()+getFrontMemberDTO()+getBatchMemberDTO()

Page 131: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원QueryService+getMemberDTO

()회원FrontQueryService

회원BatchQueryService

회원AdminQueryService

Page 132: 좌충우돌 ORM 개발기 2012 DAUM DEVON

CORE

FRONT ADMIN BATCH

회원CommandService+회원등록()+회원수정()+회원탈퇴()

회원FrontQueryService 회원BatchQueryService회원AdminQueryService

Page 133: 좌충우돌 ORM 개발기 2012 DAUM DEVON

멀티 모듈인 경우

• 모듈에 특화된 조회서비스는 해당 모듈에서 관리

• Core모듈의 복잡성이 줄어듬

• 비즈니스 로직은 Core에서 관리