Your SlideShare is downloading. ×

Domain Driven Design Ch7

2,766

Published on

Domain Driven Design Ch7

Domain Driven Design Ch7

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
2,766
On Slideshare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

Report content
Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
No notes for slide

Transcript

  • 1. Domain Driven Design 7장Using the Language:An Extended Example
    아꿈사스터디
    박일
  • 2. Cargo Shipping 시스템
    기본 요구사항
    customer 의 cargo 를 추적할 수 있어야 한다.
    미리 cargo를 예약할 수 있어야 한다.
    cargo가 특정 handling 상태가 되면 customer 에게 자동으로 invoice 를 보내야 한다.
    여기까지 요구사항만 놓고 design 을 만들어보자.
  • 3. 그림 7.1
  • 4. 그림 7.1
  • 5. model 에 나오는 객체들
    Handling Event
    Cargo 를 배에 싣고 내리는 등의 행위
    loading, unloading, being claimed 등의 상위클래스일 수 있음
    Delivery Specification
    목적지, 도착날짜
    Cargo 에게 맡기지 않고 따로 객체를 만든 이유
    Cargo 객체가 복잡해진다
    LoD(Level of Detail) 을 제공
    Cargo 의 목적이 Delivery Specification 이라는 걸 좀 더 분명하게 얘기할 수 있다.
  • 6. model 에 나오는 객체들
    role
    Customer 의 역할(shipper, receiver, payer…)
    한 Customer 는 특정 Cargo 에 대해서 하나의 role 만 맡는다(Qualified Association)
    string 또는 클래스로 구현
    Carrier Movement
    특정 Carrier(트럭, 화물선) 가 Cargo 를 하나의 Location 에서 다른 Location 으로 이동시키는 행위
  • 7. model 에 나오는 객체들
    Delivery History
    Cargo 에 어떤 일이 있었는지에 대한 기록
    Delivery History 는 마지막 Carrier Movement 로 Cargo 의 현재위치를 계산할 수 있다.
    각 객체를 어떻게 찾고 저장할지를 model 에서는 다루지 않지만 design 에서는 다뤄야 한다.
  • 8. Application 도입
    Applications
    Tracking Query
    Booking Application
    Incident Logging Application
    application 은 coordinator 이다. 질문에 대한 답을 하는 것은 domain layer 영역
  • 9. Entity,Value Object 구분
    Customer : 고객, 회사이므로 상식적으로 Entity
    TaxID는 ID 로 부적합. Customer 는 처음 sales contact 때 ID 를 부여하고 있더라.
    Cargo : Entity. 실제 각 물류회사에는 Cargo 별로 ID 부여
    Handling Event : Cargo 를 추적할 수 있어야 하므로 Entity
    Cargo ID, completion time, type 조합으로 ID 생성
    Carrier Movement : shipping schedule 코드로 identity 가능
    Location : 다른 지역이 이름만 같을 수 있으므로 unique ID 필요
    자동증가 id 정도면 충분
    Delivery History : 교환할 수 없으므로 entity.
    각 Cargo 별로 History 가 다르니까 Delivery History 는 Cargo 와 1:1 관계임.
    AGGREGATES 관계로 가자(Cargo 의 멤버변수)
    Delivery Specification 은 두 Cargo 가 같은 장소로 동시에 배송될 수 있으므로 VALUE OBJECTS
    Role 은 연계관계이지만, 지속성은 필요없음. VALUE OBJECT
    stamps, names 도 VALUE OBJECT
    모델에서 중요하지 않은 속성은 대문자를 부여받지 못함
    대문자를 받은 model language 는 위키페이지의 이름으로 쓸 수 있다
  • 10. Shipping 에서 association 디자인
    상호참조는 최대한 피하자
    Customer 가 Cargo 를 레퍼런스하면귀찮을 수 있음
    Customer 가 Cargo 한정으로 사용되는 것도 아님
    특정한 배(Carrier)의 인벤토리를 추적한다면 Carrier Movement -> Handling Event 가 중요할 수 있지만 지금은 Cargo 만 추적하면 되므로 Handling Event -> Carrier Movement 필요
    딱 필요한 만큼만 구현할 것
    환형 관계가 하나(Cargo -> Delivery History -> Handling Events -> Cargo) 있는데 가능하면 피해라.
    직접 레퍼런스가 싫다면 (DB 같이 query 가 가능한) REPOSITORY 를 이용하라.
  • 11.
  • 12. AGGREGATE 경계
    Customer, Location, Carrier Movement 는 Cargo 가 공유하므로 AGGREGATE root 여야 함
    Cargo 도 AGGREGATE 의 root 인데, 그 밑에 뭐가 들어갈 수 있을까?
    Delivery History 는 Cargo 를 통해서만 접근한다.
    Delivery Specification 는 VALUE OBJECT 니까 추가
    Handling Events
    collection 이든 DB 든 Delivery History 에 대한 Handling Events 를 찾을 수 있어야 하고
    특정 Carrier Movement 에 대해 load, unload 를 다 찾을 수 있어야 한다면, Handling Events 가 Cargo 에 독립적인 의미를 가지기 때문에 독자적인 AGGREGATE 의 root 가 되어야 한다.
    따로 빼면 low-contention transaction 으로 만들 수 있다.
  • 13.
  • 14. REPOSITORY 선택
    AGGREGATE root 가 아니면 REPOSITORY 가 필요없음(직접 접근할 일이 없으니까).
    Booking Application 에서는 여러 role (shipper, receiver, ...) 을 맡을 Customer 를 선택할 수 있어야 하므로 Customer Repository 가 필요하다.
    Cargo 의 도착지를 지정할 수 있어야 하므로 Location Repository 도 필요하다.
    Activity Logging Application 는 Cargo 를 실은 Carrier Movement 를 찾아볼 수 있어야 하므로 Carrier Movement Repository필요.
  • 15.
  • 16. Scenarios
    Customer 가 Cargo 의 목적지를 바꿀 수 있는가?
    Cargo 의 Delivery Specification 은 VALUE OBJECT 니까 덮어쓰면 된다.
    Repeat Business : 같은 Customer 에게 화물을 보낼 때 그전 정보를 prototype 으로 쓰고 싶다(yes24 의 이전배송정보 사용).
    Cargo 는 ENTITY 이자 AGGREGATE 의 root 이므로 주의
    Delivery History : 비어있는 새 객체 생성
    Customer Roles : Map (or collection) 을 key 와 함께 복사
    key : 역할, value : Customer
    Tracking ID : 새로운 Tracking ID 를 제공한다.
    Cargo AGGREGATE 영역 밖에는영향을 미치지 않는다
  • 17. 객체 생성 - Cargo
    public Cargo CopyPrototype(String newTrackingID)
    public Cargo newCargo(Cargo prototype, String newTrackingID)
    public Cargo newCargo(Cargo prototype)
    비어있는 Delivery History 와 Delivery Specification 가 null 인 Cargo 를리턴
    Delivery Specification 가 null 일 필요가 있을까?
    public Cargo(Stirng id) {
    trackingID = id;
    deliveryHistory = new DeliveryHistory(this);
    customerRoles = new HashMap();
  • 18. 객체 생성 - Handling Event 추가
    사용자는 Incident Logging Application 로 Handling Event 를 입력한다.
    Handling Event 는 ENTITY 이기 때문에 생성자에 identity 에 관련된 모든 attribute 가 다 들어와야 한다.
    Cargo ID + completion time + event type
    Handling Event 는 Cargo 를 handled 라는 멤버변수로 연관관계
    public HandlingEvent(Cargo c, String eventType, Date timeStamp) {
    handled = c; // const 변수감
    type = eventType; // const 변수감
    completionTime = timeStamp;
    }
    public static HandlingEventnewLoading(
    Cargo c, CarrierMovementloadedOnto, Date timeStamp) {
    HandlingEvent r = new HandlingEvent(c, LOADING_EVENT, timeStamp);
    r.setCarrierMovement(loadedOnto);
    return r;
    }
  • 19. Handling Event 추가하기 복잡함
  • 20. 잠깐, 다른 디자인은 없을까?
    Handling Event 를 추가할 때 Delivery History 를 업데이트하려면 Cargo AGGREGATE 를 transaction 걸어야 한다. 다른 user 가 같은 Cargo 를 동시에 고친다면 transaction이 실패(낙관적인 lock)하거나 지연(비관적인 lock)될 수 있다. Handling Event 를 경쟁없이추가하려면 design 을 고쳐야 한다.
    Handling Event 를 Delivery History 의 collection 대신 query 로 바꾸면 Handling Event 를 AGGREGATE 정합성 문제없이 추가 가능
    interference 없이 transaction 할 수 있다.
    Handling Event 의 입력이 많고 쿼리가 적다면 성능향상 가능.
    그래서 Handling Event Repository 를 추가한다.
    findByCargoIDTimeType, findByCargoTrackingID, findByScheduleID, findMostRecentCargoIDType
    Handling Event Repository 에서 원하는 history 를 query 할 수 있기 때문에 Delivery History 에 persistent state 가 없어지므로 쓸모없게 된다.
    다만, 하나의 Cargo 에 대한 전체 History 를 볼 일이 더 많을 경우라면 성능 trade-off 가 발생할 수 있다.
  • 21.
  • 22. 새로운 기능을 추가해보자
    화물의 'type, 출발지, 목적지에 따른 화물량 예측' 기능을 Booking Application 에 통합해, 새로 booking 할 때 적합성 여부를 알고 싶다.
    Booking Application 은 Cargo Repository 와 Sales Management System 의 정보가 필요하다.
  • 23. 두 시스템 연결
    Sale Management System 은 별도의 소프트웨어(시스템)
    Interface 로 wrap 하기 보다는
    중간에 번역 레이어를 두자
    Anti Corruption Layer
    번역
    DB -> 서버 -> 클라이언트 -> 엔진
    즐겨찾기DB -> XML 전송 -> IE, Firefox 변환
  • 24. Segmenting the Business
    Cargo 의 type 을 정의하지 않았다.
    ENTERPRISE SEGMENT(Analysis Patterns)
    a set of dimensions that define a way of breaking down a business
    Enterprise Segment 라는 클래스(VALUE OBJECT)가 등장
    날짜, 지역등으로구분짓는 데이터(일종의 where 절, 카테고리)
  • 25.
  • 26. 지역(국가/시/도/군/면,리)/날짜/제품군
  • 27. Allocation Checker
    Enterprise Segment 와 외부시스템의 카테고리 이름을 번역
    SERVICE
    Booking Application 에서 하던 business rule 작업(Cargo 배치)과 Enterprise Segment 생성 책임을 Allocation Checker 으로 넘긴다.
    Allocation Checker 가 Enterprise Segments 로 만들 수 없는 차원은 Sales Management System 에서 쓸 수 없다는 단점이 있다
  • 28. 성능 문제
    Sales Management System 이 외부에 있다면?
    Allocation Checker 에 cache 한다.
    COM+ 에서 interface query 하는 방식도 있다
  • 29. 새로운 기능 추가하기 - 정리
    Sales Management System 을 Booking Application, Cargo Repository 와 통합하면서 복잡해졌지만, ANTICORRUPTION LAYER, SERVICE, ENTERPRISE SEGMENTS 를 도입하므로서 정돈되면서 도메인을 더 풍부하게 만들 수 있었다.
  • 30. 정리
    DDD 의 모델은 요리법(recipe) 처럼 만들어야 한다.
    모델만 봐도 구현할 수 있게 하되, 모델을 있는 그대로 구현하는 것이 아니라 상황에 맞게 적용할 수 있는 유연함이 필요하다.
    DDD 의 모델은 패턴언어와 비슷하다. 모델은 계속 같은 언어로 표현되면서 다른 모델과 관계를 맺는다.

×