SlideShare ist ein Scribd-Unternehmen logo
1 von 70
짜친 세미나, DDD 쌩기초 이야기
- 거의 Final Version


최범균 (madvirus@madvirus.net)
자바캔 카페(http://cafe.daum.net/javacan)
자바캔 블로그(http://javacan.tistory.com)
TOC

• 객체와 연관
  – 객체와 연관
• DDD 쌩 기초
  – 레이어 구성
  – DDD 빌딩 블록
• DDD와 ORM
• DDD 구현 이야기
  – ORM 이용 구현하기
      • 도메인 모델 구현
      • 리포지토리의 구현
  – 어플리케이션 레이어 서비스 구현
  – UI 영역(컨트롤러) 구현
• 참고 자료

                        2
객체와 연관




         3
객체란?

                      객체는 기능 제공

              객체
                     객체


       객체


                     객체

                객체

                     객체
  다른 객체를 사용



                                  4
클래스: 객체의 정의

• 기능을 public 메서드로 정의
 – 데이터는 외부에 드러내지 않고 기능 정의만 제공
   • getter/setter 메서드의 최소화


• 다른 객체를 사용하는 방법
 – 필드를 이용해서 다른 객체를 레퍼런스로 참조
   • 연관(Association)이라고 표현
 – 메서드에서 필요한 시점에 객체를 생성해서 사용




                                5
객체 간 연관의 예

                                 필드
public class Employee {                             Organization org = new Organization(…);
  private String name;
  private Organization organization;                Employee e1 = new Employee(…);
  ...                                               Employee e2 = new Employee(…);
  public void setOrganization(Organization org) {
      this.organization = org;                      org.add(e1);
  }                                                 org.add(e2);
}
                                     필드
public class Organization {
  private String name;
  private List<Employee> employees;
  ...
  public void add(Employee emp) {
      this.employees.add(emp);
      emp.setOrganization(this);
  }
}




                                                                                         6
연관의 방향성

• 방향성의 종류
  – 단 방향: 두 객체 중 한 객체만 레퍼런스 가짐
  – 양 방향: 두 객체가 서로에 대한 레퍼런스 가짐
• 양 방향 예

  emp1:Employee          org1:Oragnization      rule1:Rule

 organization=org1   employees = [emp1, emp2]
                           rule = rule1


  emp2:Employee

 organization=org1




                                                         7
연관의 종류

• Many-To-One
  – 예, 다수의 Employee가 한 Organization과 연관
• One-To-Many
  – 예, 한 Organization이 다수의 Employee와 연관
  – 콜렉션으로 구현: Collection, Set, List, Map
• One-To-One
  – 예, 한 Oranization이 한 Rule과 연관
• Many-To-Many
  – 콜렉션




                                           8
모든 객체가 메모리 있다면… (1)

• 연관된 객체들을 이용해서 기능을 구현
• 예1, Rule의 교체: 연관된 객체 교환으로 구현
 Organization org = …; // 어딘가에서 구함    // Organization의 메서드
 Rule newRule = new Rule(…);          public void changeRule(Rule newRule) {
 org.changeRule(newRule);                this.rule = newRule;
                                      }




• 예2, 팀 이동: 양방향 연관을 처리
 Organization org2 = …; // 어딘가에서 구함   // Employee의 메서드
 Employee emp1 = …; // 어딘가에서 구함       public void transferTo(Organization org) {
 emp1.changeTeam(org2);                   Organization oldOrg = this.organization;
                                          this.organization = org;
                                          oldOrg.remove(this);
                                      }

                                      // Organization의 메서드
                                      public void remove(Employee e) {
                                         employees.remove(e);
                                      }
                                                                                     9
모든 객체가 메모리 있다면… (2)

• 연관된 객체들을 이용해서 기능을 구현
• 예3, Rule의 확인: 연관된 객체를 구해 확인
 Organization org = …; // 어딘가에서 구함    // Organization의 메서드
 Rule rule = org.getRule();           public Rule getRule() {
 if (rule != null) {                     return this.rule;
     rule.check(someData);            }
 }                                    // Rule의 메서드
                                      publiic void check(Data data) { … }


• 예4, Rule의 확인: 내부적으로 위임
 Organization org2 = …; // 어딘가에서 구함   // Organization의 메서드
 org.checkRule(someData);             public void checkRule(Data data) {
                                         if (rule == null) {
                                              return;
                                         }
                                         rule.check(data);
                                      }




                                                                            10
모든 객체가 메모리 있다면… (3)

• 객체를 메모리에 보관/검색 위한 방법 필요
 – 객체마다 고유 식별값 필요
   • 메모리 상의 레퍼런스 이용은 한계
   • 고유 식별 값을 갖는 객체를 Entity라 함
 – 객체 보관하고 제공해주는 기능 필요
   • DDD에서는 이를 Repository로 추상화
    public interface OrganizationRepository {
      public void save(Organization org);
      public Organization findById(Integer id);
    }


    Organization org = organizationRepository.findById(id);

    org.checkRule(…);



                                                              11
객체의 라이프사이클

• 객체 생성 - 사용 - 소멸
  – 동일 라이프사이클을 갖는 객체들의 군 존재


  emp1:Employee               org1:Oragnization            rule1:Rule

 organization=org1        employees = [emp1, emp2]
                                rule = rule1


  emp2:Employee

 organization=org1
                                                  org1이 삭제되면
                                                    rule1도 삭제


            org1이 삭제되도
           emp2는 삭제 안 됨


                                                                    12
DDD 쌩 기초




           13
DDD(Domain Driven Design)

• 도메인 모델로부터 디자인하기
• 도메인 모델의 중요성 강조
  – 도메인 모델을 최대한 설계에 반영
     • 예, Ubiquitous Language (용어 최대한 반영)
  – 모델이 깨지지 않는 방법 제시 (일관성 유지)
     • 예, Bounded Context, Anticorruption Layer 등
• 이를 위한 기본 설계 기법 제시
  – 레이어 구성
  – 도메인 레이어의 기본 빌딩 블록




                                                    14
DDD 구현 위한 필수 쌩 기초




                    발췌: Domain Driven Design (Eric Evans)
                                                            15
Layered Architecture

                        사용자에게 정보 출력
       User Intreface   사용자의 요청을 해석 하위 레이어에 전달




                        어플리케이션의 상태를 관리 / Thin Layer
        Application     비즈니스 로직/객체 상태를 포함하지 않음
                        실제 비즈니스 처리는 도메인에 요청



                        도메인에 대한 정보를 포함
         Domain         비즈니스 객체의 상태를 포함
                        비즈니스 로직을 제공


                        다른 레이어를 위한 지원 라이브러리
       Infrastructure   영속성 구현



                                                      16
도메인 모델의 기본 구성 요소

•   Entity
•   Value
•   Aggregate
•   Repository
•   Service




                   17
도메인 모델의 기본 구성 요소, Entity

• 주요 특징
  –   모델을 표현
  –   고유의 식별 값을 가짐
  –   모델과 관련된 비즈니스 로직을 수행
  –   자신만의 라이프 사이클을 가짐
• 예, 평가 시스템에서의 Entity
  – Employee(직원)
  – Organization(조직)




                            18
도메인 모델의 기본 구성 요소, Value

• 고유의 키 값을 갖지 않음
• 데이터를 표현하기 위한 용도로 주로 사용
  –   개념적으로 완전한 데이터 집합                 <<Entity>>

  –   (주로) Immutable 임                  Employee


      자신에게 알맞은 로직을 제공
                              -id : Integer
  –                           -name : String

  –   Entity의 속성으로 사용         -address : Address
                              -organization : Organization
      • 자신의 라이프사이클을 갖지 않음
      • 엔티티를 따름                                 1



• 예
  – Address(주소)                          1

                                       <<Value>>
      • 데이터: 우편번호, 주소1, 주소2               Address
  – Money(돈):                       -zipcode : String

      • 데이터: 금액, 화폐 단위              -address1 : String
                                    -address2 : String
      • 로직: 더하기, 곱하기 등

                                                             19
도메인 모델의 기본 구성 요소, Aggregate

• Aggregate
  – 관련된 객체들의 묶음
• Aggregate의 특징
  – 데이터 변경시 한 단위로 처리 됨
    • 비슷한 또는 거의 유사한 라이프사이클을 갖는 객체들
       – 특히, 삭제 시 함께 삭제됨
  – Aggregate는 경계를 가짐
    • 기본적으로, 한 Aggregate에 속한 객체는 다른 Aggregate에
      속하지 않음
• Aggregate 필요성
  – 많은 도메인 모델을 가능한 간단하고 이해가능한 수
    준으로 만들 필요
  – 연관의 개수를 줄임으로써 복잡도 감소

                                             20
Aggregate의 흔한 예, 주문-고객-상품

                              order
                                                                                       item


           <<Entity>>
                                          OrderLine                <<Entity>>                  <<Value>>
     <<Aggregate Root>>
                                      -product : Product    <<Aggregate Root>>                    Option
               Order
                                      -quantity : int                Product
   -id : Integer
                                                           -id : Integer
   -lines : List<OrderLine>                                                                    <<Value>>
                                                           -name : String
   -shippingAddress : Address                                                                      Price
                                                           -listPrice : Price
                                                                                              -value : int




                                                                    <<Value>>

            customer                                                 ItemDetail

                                                               -description : String

          <<Entity>>
            Customer

       -id : String
       -name : String
       -address : Address




                                                                                                             21
도메인 모델의 기본 구성 요소, Aggregate 루트

• Aggregate는 루트를 가짐
• Aggregate 루트 역할
  – Aggregate의 내부 객체들을 관리
  – Aggregate 외부에서 접근할 수 있는 유일한 객체
    • Aggregate의 내부 Entity/Value는 루트를 통해 접근
  – Aggregate에 대한 알맞은 기능을 수행
    • 예, 주문 관련 Aggregate 루트인 Order의 기능
       – 주문 취소, 배송지 주소 변경, 주문 상품 변경
    • 내부 객체들의 연관을 탐색해서 기능 구현




                                              22
Entity, Value, Aggregate 도출 예, 도메인 분석

• 도메인: 평가
  – 직원의 평가
  – 평가는 성과 평가와 역량 평가로 구성
  – 성과와 역량에 대해
     • 본인 평가, 1차 평가, 2차 평가 존재
  – 성과 평가 시,
     • 성과 항목 목록을 입력하고 각 항목에 대한 평가 내용을 입력
  – 역량 평가 시,
     • 미리 정의된 역량 항목에 대한 평가 내용을 입력




                                        23
Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표
성과   목적         결과           가중치   본인 평가    1차 평가    2차 평가
평가
     전산 고도화     위키 도입        30    의견 / A   의견 / A   의견 / B
                그룹웨어 구축
     보안 강화      DB 보안 강화     60    의견 / B   의견 / B   의견 / B
                보안 프로세스 도입
     팀역량강화      팀 세미나 5회     10    의견 / B   의견 / B   의견 / A
                영어 참여율 80%
역량   역량 항목                         본인 평가    1차 평가    2차 평가
평가
     성취 목표 지향                      의견 / A   의견 / A   의견 / B

     협동                            의견 / A   의견 / A   의견 / B

     학습 능력                         의견 / B   의견 / B   의견 / B

     고객 지향                         의견 / A   의견 / S   의견 / A




                                                              24
Entity, Value, Aggregate 도출 예
                        평가 Aggregate                                                             self
                                                                            <<Value>>                                <<Entity>>
                                                                            PerfEvalSet                             RaterPerfEval
                                                                                                 first
                                                                     -self : RaterPerfEval               -ratee : Employee
                                                                     -first : RaterPerfEval              -rater : Employee
                                                                     -second : RaterPerfEval     self    -itemEvals : List<PerfItemRaterEval>
                                                      1
                                                                                                         -done : boolean
                                <<Entity>>                      1

                          <<Aggregate Root>>
        <<Entity>>             PersonnelEval
   <<Aggregate Root>>                                                                                                <<Value>>
                        -id : Integer
         Employee                                                       PerfItem
                        -employee : Employee          1                                                           PerfItemRaterEval
  -name : String                                                     -goal : String
                        -perfEvalSet : PerfEvalSet            1..*                                              -grade : Grade
                                                                     -result : String
                        -perfItems : List<PerfItem>                                                             -comment : String
                                                                                                                -perfItem : PerfItem
                        +evaluatePerfBySelf()
                        +evaluatePerfByFirst()
                        +evaluatePerfBySecond()                 1
                                                                                                 self
                                                                            <<Value>>                               RaterCompeEval
                                                          1
                                                                           CompefEvalSet                 -ratee : Employee
                                                                                                 first
                                                                     -self : RaterCompeEval              -rater : Employee
                                                                     -first : RaterCompeEval             -itemEvals : List<CompeItemRaterEval>
                                                                     -second : RaterCompeEval   second   -done : boolean




                                                                                                                   CompeItemRaterEval

                                                                                                                  -grade : Grade
                                                                                                                  -comment : String



                                                                                                                                                 25
Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표
 perfEvalSet: PerfEvalSet                 self:PerfEv
                                          alSet


            성    목적         결과      가중치    본인평가          1차 평가                   2차 평가
            과
                 -----    -----     30     의견 / A        의견 / A                  의견 / B
                                                                                                                                         self

                  PerfItem
                                                                                                                    <<Value>>                                <<Entity>>
                                                                                                                    PerfEvalSet                             RaterPerfEval

                                           PerfItem                                                                                      first

                 -----      -----   60     의견 / B        의견 / B                  의견 / B
                                                                                                             -self : RaterPerfEval               -ratee : Employee

                                           RaterEval                                                         -first : RaterPerfEval              -rater : Employee
                                                                                                             -second : RaterPerfEval     self    -itemEvals : List<PerfItemRaterEval>

                 -----      -----   10     의견 / B        의견 / B                  의견 / A
                                                                                              1
                                                                                                                                                 -done : boolean
                                                                         <<Entity>>                     1

                                                                   <<Aggregate Root>>

            역    역량 항목                     본인평가          1차 평가 PersonnelEval 평가
                                                                     2차
            량                                                    -id : Integer                                                                               <<Value>>
                                                                                                                PerfItem
                 -----                     의견 / A        의견 / A : Employee / B
                                                            -employee 의견                      1
                                                                                                             -goal : String
                                                                                                                                                          PerfItemRaterEval

                                                                 -perfEvalSet : PerfEvalSet                                                             -grade : Grade
                                          CompeItem 의견 / A : List<PerfItem> B
                                                                                                      1..*

                 -----                    의견 / A                    의견 /
                                                                                                             -result : String
                                                       -perfItems                                                                                       -comment : String

                                          RaterEval    +evaluatePerfBySelf()
                                                                                                                                                        -perfItem : PerfItem

                 -----                     의견 / B        의견 / B
                                                            +evaluatePerfByFirst() / B
                                                                         의견
                                                                 +evaluatePerfBySecond()                1

                 -----                     의견 / A        의견 / S                  의견 / A                             <<Value>>
                                                                                                                                         self
                                                                                                                                                            RaterCompeEval
                                                                                                  1
                                                                                                                   CompefEvalSet                 -ratee : Employee
                                                                                                                                         first
                                                                                                             -self : RaterCompeEval              -rater : Employee
                                          self:CompeEv                                                       -first : RaterCompeEval             -itemEvals : List<CompeItemRaterEval>

                                          alSet                                                              -second : RaterCompeEval            -done : boolean
 compeEvalSet:CompeEvalSet
                                                                                                                                        second




PersonnelEval                                                                                                                                              CompeItemRaterEval

                                                                                                                                                          -grade : Grade
                                                                                                                                                          -comment : String




                                                                                                                                                                           26
도메인 기능 구현 예 - 본인 성과 평가 기능

• 본인 평가하기 기능 → 평가 Aggregate의 기능
 – 본인 평가하기를 구현하려면
   • PersonnelEval의 perfEvalSet 필드로 연결된
   • PerfEvalSet의 self 필드로 연결된
   • RaterPerfEval을 설정
       – 피평가자(ratee), 평가자(rater), 각 항목 평가(itemEvals)
                                                                        self
             <<Entity>>                              <<Value>>                              <<Entity>>
       <<Aggregate Root>>                            PerfEvalSet                           RaterPerfEval
                                   1                                    first
            PersonnelEval                     -self : RaterPerfEval             -ratee : Employee
     -id : Integer                     1      -first : RaterPerfEval            -rater : Employee
     -employee : Employee                     -second : RaterPerfEval   self    -itemEvals : List<PerfItemRaterEval>
     -perfEvalSet : PerfEvalSet                                                 -done : boolean
     -perfItems : List<PerfItem>

     +evaluatePerfBySelf()
     +evaluatePerfByFirst()        1               PerfItem
                                                                                            <<Value>>
     +evaluatePerfBySecond()           1..*     -goal : String
                                                                                         PerfItemRaterEval
                                                -result : String
                                                                                       -grade : Grade
                                                                                       -comment : String
                                                                                       -perfItem : PerfItem




                                                                                                                       27
도메인 기능 구현 예 - 본인 성과 평가 기능

public class PersonnelEval {
  private PerfEvalSet perfEvalSet;
  public void evaluatePerfBySelf(List<PerfItemRaterEval> evals, boolean done) {
      perfEvalSet.setSelf(employee, evals, done);
  }
  …
}                     Aggregate Root가 Aggregate의 다른 객체에 위임

public class PerfEvalSet {
  private RaterPerfEval self;

    public void setSelf(Employee ratee, List<PerfItemRaterEval> evals, boolean done) {
      if (self == null) {
          self = new RaterPerfEval(rater, ratee);
      }
      self.change(evals, done);
    }
    …
}


                                                                                         28
도메인 기능 구현 예 - 본인 성과 평가 기능

public class RaterPerfEval {
  private Employee ratee;
  private Employee rater;
  private List<PerfItemRaterEval> evals;
  private boolean done;

    public RaterPerfEval(Employee ratee, Employee rater) {
      this.ratee = ratee;
      this.rater = rater;
    }

    public void change(List<PerfItemRaterEval> evals, boolean done) {
      this.evals.clear();       PerfItemRaterEval은 Value이고 Immutable 임:
      this.evals.addAll(evals); 데이터 값 변경이 아닌, 기존 데이터 삭제 후 새로 추가
      this.done = done;
    }
    …
}




                                                                          29
도메인 기능 구현 예 - 본인 성과 평가 완료 여부

  • 본인 평가 완료 여부 → 평가 Aggregate의 기능
                – 본인 평가 완료 여부를 구현하려면
                             • PersonnelEval의 perfEvalSet 필드로 연결된
                             • PerfEvalSet의 self 필드로 연결된
                             • RaterPerfEval에게 문의
                                                                   self
        <<Entity>>                              <<Value>>                              <<Entity>>
  <<Aggregate Root>>                            PerfEvalSet                           RaterPerfEval
                              1                                    first
       PersonnelEval                     -self : RaterPerfEval             -ratee : Employee

                                                                                                   public class PersonnelEval {
-id : Integer                     1      -first : RaterPerfEval            -rater : Employee
-employee : Employee                     -second : RaterPerfEval           -itemEvals : List<PerfItemRaterEval>
                                                                                                      private PerfEvalSet perfEvalSet;
                                                                   self

-perfEvalSet : PerfEvalSet                                                 -done : boolean
-perfItems : List<PerfItem>                                                                           public boolean isSelfPerfEvaluationDone() {
+evaluatePerfBySelf()                                                                                    return perfEvalSet.isSelfDone();
                                              PerfItem
+evaluatePerfByFirst()
                                                                                                      }
                              1
                                                                                       <<Value>>
+evaluatePerfBySecond()                    -goal : String
                                                                                                   }
                                  1..*
                                                                                    PerfItemRaterEval
                                           -result : String
                                                                                  -grade : Grade
                                                                                  -comment : String
                                                                                  -perfItem : PerfItempublic class PerfEvalSet {
                                                                                                        public isSelfDone() {
                                                                                                            return self == null ? false : self.isDone();
                                                                                                        }
                                                                                                      }

                                                                                                                                                    30
도메인 모델의 기본 구성 요소, Repository

• Entity를 보관하는 장소
• 기본 규칙:
  – Aggregate 당 한 개의 Repository 인터페이스
  – Aggregate의 CRUD 기본 단위는 루트!
    • 예외, 성능 상 이유로 Aggregate에 속한 다른 엔티티에 직접
      접근할 필요가 있는 경우 별도 DAO 구현
       – 예, 리포트 집계 등
• Repository의 기본 인터페이스
  – save(루트): 한 Aggregate의 저장
  – List<루트> findByName(): 특정 조건으로 검색
  – delete(루트): 한 Aggregate의 삭제


                                          31
Specification을 통한 검색

• Specification
  – Repository에서 Entity를 검색하기 위한 필터
       • DDD에서의 Specification 구현의 모습
 public interface Specification<T> {
   public boolean satisfy(T entity);
 }


 public class SomeCustomerRepository implements CustomerRepository {
   public List<Customer> findBySpecification(Specification<Customer> spec) {
       List<Customer> all = findAll();
       List<Customer> result = new ArrayList<Customer>();
       for (Customer c : all) {
           if (spec.satisfy(c)) { 개념적으로는 맞지만,
               result.add(c);       모든 Entity 로딩 시,
           }                           성능 문제 발생
       }
       return result;
   }
 }
                                                                               32
Specification의 조합

• Specification은 서로 조합이 될 때 유용함
     – 다수의 Specification을 and/or로 연결

                                                 도메인에 맞는 검색 조건 표현
Specification<Customer> ageGtSpec = new AgeGraterThanSpec(20);
Specification<Customer> locationSpec = new LocationEqSpec(Location.SEOUL);


Specification<Customer> ageLocSpec = Specs.and(ageGtSpec, locationSpec);
                                                             검색 조건 조합

List<Customer> custmoers = customerRepository.findBy(ageLocSpec);

 Composite Pattern (또는 트리 구조) 이용하여 구현




                                                                             33
도메인 모델의 기본 구성 요소, 도메인 레이어의 Service

• 한 Entity나 Aggregate에 속하지 않은 도메인 기
  능을 도메인 서비스로 분리
  – 예, 계좌 이체
    • 계좌 이체는 한 계좌 엔티티 객체가 수행할 수 없는 도메인
      기능


• 도메인 서비스의 구현
  – 다른 도메인 구성 요소 이용해서 기능 구현


• 타 레이어의 서비스와 구분


                                         34
DDD 쌩기초의 접근법

• 도메인 모델 중심 접근 필요

• 객체 연관 중심 접근 필요
 – 도메인 기능 구현 시, 도메인 객체 간 연관으로 풀기
   • SQL을 머리에서 버릴 것 (특히, JOIN!)




                                   35
DDD와 ORM




           36
메모리는 영원하지 않음

• 안정적인 데이터 관리 위해 객체를 물리적인 기
  록 장치에 보관할 필요

• 객체 모델과 일치하는 물리적 데이터 저장소는
  흔치 않음
 – OODB는 시장에서 실패
 – RDBS는 딱 들어맞지 않음
 – 기타 NoSQL 역시 정확하게 OO와 일치하진 않음




                                  37
차이의 예: 객체 모델과 ER의 대표적인 차이

         객체 모델                     관계 모델


연관 방향성   양방향                       단방향
         레퍼런스(필드) 이용               Foreign Key 이용


콜렉션 연관   List, Set, Map 등 콜렉션 사용   Foreign Key 사용
                                   Join/Collection 테이블 사용


다형성      인터페이스/상속 사용               없음




                                                            38
ORM의 필요성

• DDD를 즐겁게 하려면
 – 객체를 이용한 모델링 뿐만 아니라,
 – 객체 모델과 데이터 모델 간 좋은 매핑 도구 필요


• 추천 프레임워크
 – JPA (자바의 ORM 표준 스펙)
   • 객체와 RDB 사이의 모든 매핑을 거의 소화
 – 또한, Spring Data 추천
      – DB 연동 코드 작성을 위한 노가다 감소
      – Spring Data MongoDB 등을 통한 NoSQL과의 매핑 처리




                                              39
DDD 구현 이야기




             40
전체 레이어 별 구성 요소




                 데이터 조회 목적
                 Repository 접근해서 도메인 객체 구함
                 도메인 모델을 DTO로 변환해서 제공
                 데이터 읽기 위한 트랜잭션 범위 지정
도메인 기능 실행 요청
 트랜잭션 범위 지정




                      도메인 모델 객체 제공




                    영속성 구현 제공

                                      41
전체 레이어 별 구현: Spring + JPA

Spring Bean
Spring MVC




                            Spring Bean
                            Spring TX

Spring Bean
Spring TX



         JPA                          Spring Data JPA




                                     Spring Bean
                                     JPA
                                                        42
도메인 레이어 구현




             43
ORM을 이용한 DB와의 매핑: Entity & Value

• Entity 당 한 개의 테이블 매핑
• Entity 간 참조
  – 대부분 단방향의 Foreign Key로 처리
  – 경우에 따라 Join 테이블 이용 구현
• Entity 간 참조는 최대한 단방향으로
  – 꼭 필요한 경우에만 양방향
• Value
  – 엔티티와 한 테이블에 함께 존재
     • Value 콜렉션의 경우 Collection 테이블로 Value 구현




                                                44
Entity & Value 테이블 매핑 예

• 엔티티 간 연관: Foreign Key
@Entity                                     @Entity
@Table(name = "EMPLOYEE")                   @Table(name = "ORGANIZATION")
public class Employee {                     public class Organization {
  @Id
  @Column(name = "EMPLOYEE_ID")                 @Id
  private String id;                            @Column(name = "ORGANIZATION_ID")
                                                private Integer id;
    @Column(name = "NAME")                      ...
    private String name;                    }

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ORGANIZATION_ID")
    private Organization organization;
    ...
}




                                                                             45
Entity & Value 테이블 매핑 예

• Entity와 같은 테이블 사용하는 Value
@Entity                             @Embeddable
@Table(name = "EMPLOYEE")           public class Address {
public class Employee {
                                        @Column(name = "ADDR_1")
    @Id                                 private String address1;
    @Column(name = "EMPLOYEE_ID")
    private String id;                   @Column(name = "ADDR_2")
                                         private String address2;
    @Column(name = "NAME")          }
    private String name;

    @Embedded
    private Address address;            EMPLOYEE
    ...
}                                   EMPLOYEE_ID

                                    NAME

                                    ORGANIZATION_ID
                                    ADDR1

                                    ADDR2



                                                                    46
Entity & Value 테이블 매핑 예

• Value의 List 콜렉션: 콜렉션 테이블 사용
@Entity                                               @Embeddable
@Table(name = "RATER_PERF_EVAL")                      public class PerformanceItemRaterEval {
public class RaterPerformanceEval {                     @Column(name = "GRADE_VALUE")
                                                        private String gradeValue;
  @Id
  @Column(name = "RATER_PERF_EVAL_ID")                    @Column(name = "COMMENT")
  private Integer id;                                     private String comment;
                                                          …
  @ElementCollection                                  }
  @CollectionTable(name = "RATER_PERF_ITEM_EVAL",
     joinColumns = @JoinColumn(
          name = "RATER_PERF_EVAL_ID"))
  @OrderColumn(name = "LIST_INDEX")
  private List<PerformanceItemRaterEval> itemEvals;




                                                                                        47
Repository의 구현

• 인터페이스로 Repository 정의
  – 각 ORM 구현체에 알맞게 구현
    • 구현 클래스는 Infrastructure 레이어에 위치
                 public interface PersonnelEvalRepository {
                   public PersonnelEval findByEmployee(Employee emp);
                   PersonnelEval save(PersonnelEval eval);
                 }


                 public class JpaPersonnelEvalRepository implements
                           PersonnelEvalRepository {
                   @PersistenceContext
                   private EntityManager em;

                     public PersonnelEval findByEmployee(Employee emp) {
                       TypedQuery<PersonnelEval> query = em.createQuery(
                             "select p from PersonnelEval p " +
                             "where p.employee = :emp", PersonnelEval.class);
                       query.setParameter("emp", emp);
                       return query.getSingleResult();
                     }
                     public PersonnelEval save(PersonnelEval eval) {
                       em.persist(eval);
                     }
                 }
                                                                                48
Specification의 실제 구현

• Specification으로부터 조건 생성 기능 필요
  – CriteriaQuery 생성 or JP QL의 where 절 생성
    public class JpaEmployeeRepository implements EmployeeRepository {
      @PersistenceContext
      private EntityManager em;

        public List<Employee> findBySpecification(Specification spec) {
          TypedQuery<Employee> query = em.createQuery(
                "select e from Employee e " + "where " + Specs.toJPQL(spec),
                Employee.class);
          spec.setParameters(query);
          return query.getResultList();
        }
    }



  – Specification을 직접 구현하는 데는 노력 필요



                                                                               49
Spring Data JPA


      Repository

       자동 생성


                     Spring Data

                        JPA
      Spcification

         지원




                                   50
Spring Data JPA 이용 Repository 구현

• Repository를 위한 메서드 Convention 정의
      – 인터페이스로부터 런타임 시, 구현 객체 자동 생성
public interface EmployeeRepository extends Repository<Employee, String> {

    Employee findById(String userId);

    Employee findByName(String name);

    @Query("select e from Employee e left join e.organization o "+
             "where e.rateeTypeValue <> 'NOT_RATEE' order by o.name asc, e.name asc")
    List<Employee> findAllRatees();

}




                                                                                 51
Spring Data JPA 이용 Repository 구현, Spec 지원

• Specification을 위한 기능 제공
    – 검색 조건 표현 위한 Specification 인터페이스 제공
public class EmployeeSpecs {
  public static Specification<Employee> rateeType(final RateeType e) {
      return new Specification<Employee>() {
          @Override
          public Predicate toPredicate(Root<Employee> root,
                CriteriaQuery<?> query, CriteriaBuilder cb) {
             return cb.equal(root.get(Employee_.rateeTypeValue), e.name());
          }
      };
  }                                                                조건을        도메인 용어로 표현
    public static Specification<Employee> nameLike(final String name) {
      return new Specification<Employee>() {
          @Override
          public Predicate toPredicate(Root<Employee> root,
                 CriteriaQuery<?> query, CriteriaBuilder cb) {
              return cb.like(root.get(Employee_.name), "%" + name + "%");
          }
      };
    }
}
                                                                                     52
Spring Data JPA 이용 Repository 구현, Spec 지원

• Specification을 위한 기능 제공
      – Repository 메서드에 Specificiation 지정 가능
public interface EmployeeRepository extends Repository<Employee, String> {

    List<Employee> findAll(Specification<Employee> spec);
}



public interface EmployeeRepository
  extends Repository<Employee, String>, JpaSpecificationExecutor<Employee> {
  // JpaSpecificationExecutor에 기본 메서드 정의
}




                                                                               53
Spring Data JPA 이용 Repository 구현, Spec 지원

• Specification과 Repository의 사용 예
  – Repository 메서드에 Specificiation 지정 가능
                                                    Criteria와 같은 유연함을 제공
                                                    영속 레이어에 대한 의존 제거
                                                 (QueryDSL은 EntityManager를 필요)
   Specifications<Employee> spec =
         Specifications.where(
             EmployeeSpecs.rateeType(RateeType.NOT_RATEE)).and(
             EmployeeSpecs.nameLike("김"));


   List<Employee> findAll = employeeRepository.findAll(spec);




                                                                             54
Lazy & Eager Loading

• Entity 간 연관에서 쓰임 고려한 설정 필요

                    Employee를 가져올 때, 연관된 Organization도 함께 로딩?
                                   Eager Loading



   Employee emp = employeeRepository.findById("madvirus");

   Organization org = emp.getOrganization();

   org.getName();



   이 때, Organization과 매핑된 테이블에서 데이터 로딩?
                     Lazy Loading



                                                             55
애플리케이션 레이어/UI 레이어 구현




                       56
전체 레이어 별 구성 요소




                 데이터 조회 목적
                 Repository 접근해서 도메인 객체 구함
                 도메인 모델을 DTO로 변환해서 제공
                 데이터 읽기 위한 트랜잭션 범위 지정
도메인 기능 실행 요청
 트랜잭션 범위 지정




                                      57
애플리케이션 레이어 구현

• 애플리케이션 서비스의 정의
 – 사용자에게 기능 제공 위한 인터페이스 정의
   • 기능명/기능정의 메서드/입력 파라미터/리턴 결과로 구성


• 도메인을 이용한 구현
 – Repository에서 Entity를 가져와
 – Entity에 기능을 요청 또는 Entity로부터 정보 조회


• 트랜잭션 범위 지정
 – 트랜잭션 시작/커밋/롤백 제어


                                       58
애플리케이션 레이어 구현 - 서비스 정의 예


public interface ReturnEvaluationService {

    public ReturnResult returnSelfPerfEval(String rateeId, String raterId);

}

    처리 결과를 표현                                           기능 실행에 필요한 입력


public interface SelfPerformanceEvaluationService {

    SelfPerEvalResult evaluate(SelfPerEvalRequest request);

}




                                                                              59
애플리케이션 레이어 구현 - 서비스 구현 예

public class DomainReturnEvaluationService implements ReturnEvaluationService {
  private PersonnelEvalRepository personnelEvalRepository;

    @Transactional          스프링 트랜잭션 기능 사용
    @Override
    public ReturnResult returnSelfPerfEval(String rateeId, String raterId) {
      PersonnelEval personnelEval = checkValidRaterAndGet(rateeId, raterId);
      personnelEval.returnSelfPerfEval();
      return new ReturnResult(rateeId, personnelEval.getEmployee().getName());
    }
                                                             도메인 객체 사용
    private PersonnelEval checkValidRaterAndGet(String rateeId, String raterId) {
       PersonnelEval personnelEval = personnelEvalRepository
               .findByEmployeeId(rateeId);
       if (!personnelEval.getEmployee().checkFirstRater(raterId)) {
            throw new RuntimeException("1차 평가자만 반려 가능");
       }
       return personnelEval;
    }
    …
}

                                                                                    60
UI 레이어의 구현

• UI 레이어의 역할 두 가지
 – 사용자의 기능 실행 요청을 애플리케이션 레이어에
   전달하기
   • 서비스가 요구하는 데이터를 전달하면 끝
   • 서비스의 처리 결과를 뷰에 보여주면 끝


 – 사용자에게 데이터 보여주기
   • 도메인 데이터를 어떻게 뷰에 전달할 것인가?




                                61
UI 레이어 구현, 역할 1 - 서비스에 요청 전달하기

• 컨트롤러에서 서비스에 실행 위임
      – 서비스의 입력 값 처리
            • 커맨드 객체로 받기 (입력 Form으로부터 요청 객체 생성)
            • 컨트롤러에서 직접 생성
@RequestMapping(method = RequestMethod.POST)
public String submit(ModelMap modelMap, SelfPerEvalRequest request) {
    SelfPerEvalResult result = evaluationService.evaluate(request);
    modelMap.addAttribute("result", result);                              커맨드 객체로 사용
    return "eval/self/selfPerfResult";
}


@RequestMapping("/review/returnSelfPerfEval")
public String returnPerfEval(@RequestParam("rateeId") String rateeId, ModelMap modelMap) {
  ReturnResult result = returnEvaluationService.returnSelfPerfEval(rateeId, SecurityUtil.getId());
  modelMap.addAttribute("result", result);
  return "review/returnPerfResult";
                                                                 컨트롤러에서 직접 생성
}


                                                                                               62
UI 레이어 구현, 역할 2 - 데이터 보여주기

• UI 레이어에 데이터를 가져오는 기능 구현
  – 읽어올 데이터가 많다면,
    • 컨트롤러와 분리된 별도 객체로 구현




                             63
DataLoadingService의 구현

• 도메인 레이어를 이용한 구현
  – Repository로부터 필요한 엔티티 구함
        • 검색 조건 조합 필요시 Specification을 이용
  – 엔티티로부터 UI에 필요한 데이터 추출
        • 방법 1, 엔티티를 그대로 리턴하기
        • 방법 2, DTO를 이용해서 데이터 전달
        • 방법에 따라 트랜잭션 경계가 달라짐
    public class DomainEmployeeDataLoader implements EmployeeDataLoader {
        @Transactional
        public SomeReturn load(String empId) {
            Employee emp = employeeRepository.findById(empId);
            checkNull(emp);
            return new SomeReturn(emp);
        }
        …
    }
                                                                            64
데이터 보여줄 때, 도메인 객체의 노출 문제!

• 도메인 객체를 그대로 UI 레이어에 노출 시 문제
  – 도메인 기능이 노출 → 안정성의 문제
      • UI 레이어에서 도메인 객체가 제공하는 기능을 실행하면….
          – 레이어를 두는 이유가 사라짐!!
  – 연관된 객체 접근 시
      • JPA의 영속성 컨텍스트 범위가 UI 레이어로 확장되어야 함
      • 또는 DataLoader에서 미리 읽어야 함 (연관이 Lazy인 경우)

<%-- 도메인 객체 노출 시, 문제 가능성 --%>                  organization이 Lazy면
                                               트랜잭션 범위 확장 필요
<%= employee.getOrganization().getName() %>

<% employee.changePassword("", "newPassword"); %>      OSIV, No!



                                                                   65
개인적 의견: DTO 내지 상위의 읽기 전용 인터페이스 사용

• UI에서 필요로 하는 데이터만 담고 있는 DTO
  – DataLoader에서 도메인 객체를 DTO로 변환처리
   // DataLoader
   PersonnelEval eval = personnelEvalRepository.findById(id);
   ViewDataDTO dto = convert(eval); // DTO: 기본 데이터 타입 사용, getter만 제공
   return dto;


• Getter만 갖는 상위 Interface
  – 리플렉션 통해서 메서드 실행이 가능하므로 비추
   // DataLoader
   public PersonnelEvalIF load() { // PersonnelEvalIF는 read only 메서드만 제공
       PersonnelEval eval = personnelEvalRepository.findById(id);
       return eval;
   }




                                                                           66
DTO를 만드는 방법

• 1, 도메인 객체에 getter를 만들어서 값 읽어오기
 – 구현 쉬움
 – 프로퍼티에 대한 getter 메서드 생성 필요
 – getter 메서드가 증가


• 2, 도메인 객체로부터 값을 받을 수 있는 Builder
  를 만들어서 DTO 객체 생성하기
 – 구현은 다소 복잡
 – 단일 Builder 인터페이스를 이용한 DTO 생성 가능
 – getter 메서드의 최소화


                                     67
정리




     68
Action!

• 도메인 모델 개발
   – 객체 간 연관으로 사고하는 연습
   – ORM(JPA) 이용 매핑 처리


• 레이어 간 명확한 역할 구분
   – 모든 도메인 로직은 도메인 레이어에 모이도록
      • 도메인 로직이 전 레이어에 퍼지지 않도록!


• 리포지토리 구현
   – Spring Data 이용하면 좀 더 편리
   – Spring Data의 Specification 활용

                                     69
Q&A

      70

Weitere ähnliche Inhalte

Was ist angesagt?

쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기Brian Hong
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Younghan Kim
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄현 수
 
서버 성능에 대한 정의와 이해
서버 성능에 대한 정의와 이해서버 성능에 대한 정의와 이해
서버 성능에 대한 정의와 이해중선 곽
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기beom kyun choi
 
4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴Terry Cho
 
Massive service basic
Massive service basicMassive service basic
Massive service basicDaeMyung Kang
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 Young-Ho Cho
 
REST API 설계
REST API 설계REST API 설계
REST API 설계Terry Cho
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?VMware Tanzu Korea
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기경원 이
 
Roles, Responsibilities, Collaborations
Roles, Responsibilities, CollaborationsRoles, Responsibilities, Collaborations
Roles, Responsibilities, CollaborationsYoung-Ho Cho
 
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!pyrasis
 
How to build massive service for advance
How to build massive service for advanceHow to build massive service for advance
How to build massive service for advanceDaeMyung Kang
 
서버학개론(백엔드 서버 개발자를 위한)
서버학개론(백엔드 서버 개발자를 위한)서버학개론(백엔드 서버 개발자를 위한)
서버학개론(백엔드 서버 개발자를 위한)수보 김
 
FIFA 온라인 3의 MongoDB 사용기
FIFA 온라인 3의 MongoDB 사용기FIFA 온라인 3의 MongoDB 사용기
FIFA 온라인 3의 MongoDB 사용기Jongwon Kim
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기Sang Heon Lee
 
[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영NAVER D2
 
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들Brian Hong
 
영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA경원 이
 

Was ist angesagt? (20)

쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기쿠키런 1년, 서버개발 분투기
쿠키런 1년, 서버개발 분투기
 
Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조Ksug2015 - JPA3, JPA 내부구조
Ksug2015 - JPA3, JPA 내부구조
 
Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄Domain-Driven-Design 정복기 1탄
Domain-Driven-Design 정복기 1탄
 
서버 성능에 대한 정의와 이해
서버 성능에 대한 정의와 이해서버 성능에 대한 정의와 이해
서버 성능에 대한 정의와 이해
 
DDD로 복잡함 다루기
DDD로 복잡함 다루기DDD로 복잡함 다루기
DDD로 복잡함 다루기
 
4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴4. 대용량 아키텍쳐 설계 패턴
4. 대용량 아키텍쳐 설계 패턴
 
Massive service basic
Massive service basicMassive service basic
Massive service basic
 
애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향 애플리케이션 아키텍처와 객체지향
애플리케이션 아키텍처와 객체지향
 
REST API 설계
REST API 설계REST API 설계
REST API 설계
 
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
MSA 전략 1: 마이크로서비스, 어떻게 디자인 할 것인가?
 
Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기Jpa 잘 (하는 척) 하기
Jpa 잘 (하는 척) 하기
 
Roles, Responsibilities, Collaborations
Roles, Responsibilities, CollaborationsRoles, Responsibilities, Collaborations
Roles, Responsibilities, Collaborations
 
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
도커 무작정 따라하기: 도커가 처음인 사람도 60분이면 웹 서버를 올릴 수 있습니다!
 
How to build massive service for advance
How to build massive service for advanceHow to build massive service for advance
How to build massive service for advance
 
서버학개론(백엔드 서버 개발자를 위한)
서버학개론(백엔드 서버 개발자를 위한)서버학개론(백엔드 서버 개발자를 위한)
서버학개론(백엔드 서버 개발자를 위한)
 
FIFA 온라인 3의 MongoDB 사용기
FIFA 온라인 3의 MongoDB 사용기FIFA 온라인 3의 MongoDB 사용기
FIFA 온라인 3의 MongoDB 사용기
 
[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기[NDC2016] TERA 서버의 Modern C++ 활용기
[NDC2016] TERA 서버의 Modern C++ 활용기
 
[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영[236] 카카오의데이터파이프라인 윤도영
[236] 카카오의데이터파이프라인 윤도영
 
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들
[DEVIEW 2021] 1000만 글로벌 유저를 지탱하는 기술과 사람들
 
영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA영속성 컨텍스트로 보는 JPA
영속성 컨텍스트로 보는 JPA
 

Andere mochten auch

Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven DesignYoung-Ho Cho
 
Spring boot + java 에코시스템 #1
Spring boot + java 에코시스템 #1Spring boot + java 에코시스템 #1
Spring boot + java 에코시스템 #1SeungHa Eom
 
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료수홍 이
 
Implementing DDD Concepts in PHP
Implementing DDD Concepts in PHPImplementing DDD Concepts in PHP
Implementing DDD Concepts in PHPSteve Rhoades
 
도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)Ashal aka JOKER
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장kukuman
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델명환 안
 
마이크로서비스 아키텍처로 개발하기
마이크로서비스 아키텍처로 개발하기마이크로서비스 아키텍처로 개발하기
마이크로서비스 아키텍처로 개발하기Jaewoo Ahn
 
Domain Driven Design Quickly
Domain Driven Design QuicklyDomain Driven Design Quickly
Domain Driven Design QuicklyMariam Hakobyan
 

Andere mochten auch (11)

DDD 산책
DDD 산책DDD 산책
DDD 산책
 
Domain Driven Design
Domain Driven DesignDomain Driven Design
Domain Driven Design
 
Spring boot + java 에코시스템 #1
Spring boot + java 에코시스템 #1Spring boot + java 에코시스템 #1
Spring boot + java 에코시스템 #1
 
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료
실전! 스프링과 함께하는 환경변수 관리 변천사 발표자료
 
Implementing DDD Concepts in PHP
Implementing DDD Concepts in PHPImplementing DDD Concepts in PHP
Implementing DDD Concepts in PHP
 
도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)도메인 주도 설계 (Domain Driven Design)
도메인 주도 설계 (Domain Driven Design)
 
Domain driven design 8장
Domain driven design 8장Domain driven design 8장
Domain driven design 8장
 
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
아꿈사 DDD(Domain-Driven Design) 5장 소프트웨어에서 표현되는 모델
 
Domain Driven Design 101
Domain Driven Design 101Domain Driven Design 101
Domain Driven Design 101
 
마이크로서비스 아키텍처로 개발하기
마이크로서비스 아키텍처로 개발하기마이크로서비스 아키텍처로 개발하기
마이크로서비스 아키텍처로 개발하기
 
Domain Driven Design Quickly
Domain Driven Design QuicklyDomain Driven Design Quickly
Domain Driven Design Quickly
 

Ähnlich wie DDD 구현기초 (거의 Final 버전)

Ksug2015 - JPA2, JPA 기초와매핑
Ksug2015 - JPA2, JPA 기초와매핑Ksug2015 - JPA2, JPA 기초와매핑
Ksug2015 - JPA2, JPA 기초와매핑Younghan Kim
 
불변객체 적용으로 리액트 성능 최적화
불변객체 적용으로 리액트 성능 최적화불변객체 적용으로 리액트 성능 최적화
불변객체 적용으로 리액트 성능 최적화Hun Yong Song
 
디자인패턴 1~13
디자인패턴 1~13디자인패턴 1~13
디자인패턴 1~13Shin heemin
 
Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준HoJun Sung
 
객체지향 프로그래밍 기본
객체지향 프로그래밍 기본객체지향 프로그래밍 기본
객체지향 프로그래밍 기본용호 최
 
좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVONYounghan Kim
 
[HaU] 신입 기술 면접 준비 java
[HaU] 신입 기술 면접 준비 java[HaU] 신입 기술 면접 준비 java
[HaU] 신입 기술 면접 준비 java유리 하
 
Sql 중심 코드 탈피
Sql 중심 코드 탈피Sql 중심 코드 탈피
Sql 중심 코드 탈피ssuser776e2d
 
3팀_객체지향 프로그래밍.pptx
3팀_객체지향 프로그래밍.pptx3팀_객체지향 프로그래밍.pptx
3팀_객체지향 프로그래밍.pptxssuser642b19
 
Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료ssuser776e2d
 
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"XpressEngine
 
Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3연우 김
 
객체지향 프로그래밍.pptx
객체지향 프로그래밍.pptx객체지향 프로그래밍.pptx
객체지향 프로그래밍.pptxssuser9eebcf
 
Object-Oriented Programming.pptx
 Object-Oriented Programming.pptx Object-Oriented Programming.pptx
Object-Oriented Programming.pptxssuserda17f6
 
파이썬 크롤링 모듈
파이썬 크롤링 모듈파이썬 크롤링 모듈
파이썬 크롤링 모듈Yong Joon Moon
 

Ähnlich wie DDD 구현기초 (거의 Final 버전) (20)

Ksug2015 - JPA2, JPA 기초와매핑
Ksug2015 - JPA2, JPA 기초와매핑Ksug2015 - JPA2, JPA 기초와매핑
Ksug2015 - JPA2, JPA 기초와매핑
 
불변객체 적용으로 리액트 성능 최적화
불변객체 적용으로 리액트 성능 최적화불변객체 적용으로 리액트 성능 최적화
불변객체 적용으로 리액트 성능 최적화
 
DDD Repository
DDD RepositoryDDD Repository
DDD Repository
 
Java script
Java scriptJava script
Java script
 
디자인패턴 1~13
디자인패턴 1~13디자인패턴 1~13
디자인패턴 1~13
 
Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준Head first디자인패턴 1~13_희민_호준
Head first디자인패턴 1~13_희민_호준
 
객체지향 프로그래밍 기본
객체지향 프로그래밍 기본객체지향 프로그래밍 기본
객체지향 프로그래밍 기본
 
Uml 세미나
Uml 세미나Uml 세미나
Uml 세미나
 
Java_05 class
Java_05 classJava_05 class
Java_05 class
 
Java class
Java classJava class
Java class
 
좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON좌충우돌 ORM 개발기 2012 DAUM DEVON
좌충우돌 ORM 개발기 2012 DAUM DEVON
 
[HaU] 신입 기술 면접 준비 java
[HaU] 신입 기술 면접 준비 java[HaU] 신입 기술 면접 준비 java
[HaU] 신입 기술 면접 준비 java
 
Sql 중심 코드 탈피
Sql 중심 코드 탈피Sql 중심 코드 탈피
Sql 중심 코드 탈피
 
3팀_객체지향 프로그래밍.pptx
3팀_객체지향 프로그래밍.pptx3팀_객체지향 프로그래밍.pptx
3팀_객체지향 프로그래밍.pptx
 
Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료Sql 중심 코드 탈피 발표자료
Sql 중심 코드 탈피 발표자료
 
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"
XE 오픈 세미나(2014-04-26) - 김동현 "XE 코어 구조론"
 
Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3Effective C++ 정리 chapter 3
Effective C++ 정리 chapter 3
 
객체지향 프로그래밍.pptx
객체지향 프로그래밍.pptx객체지향 프로그래밍.pptx
객체지향 프로그래밍.pptx
 
Object-Oriented Programming.pptx
 Object-Oriented Programming.pptx Object-Oriented Programming.pptx
Object-Oriented Programming.pptx
 
파이썬 크롤링 모듈
파이썬 크롤링 모듈파이썬 크롤링 모듈
파이썬 크롤링 모듈
 

Mehr von beom kyun choi

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개beom kyun choi
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나beom kyun choi
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)beom kyun choi
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀beom kyun choi
 
Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugbeom kyun choi
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초beom kyun choi
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유beom kyun choi
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰beom kyun choi
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료beom kyun choi
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)beom kyun choi
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개beom kyun choi
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해beom kyun choi
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개beom kyun choi
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개beom kyun choi
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기beom kyun choi
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)beom kyun choi
 

Mehr von beom kyun choi (20)

옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
옛날 웹 개발자가 잠깐 맛본 Vue.js 소개
 
TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나TDD 발담그기 @ 공감세미나
TDD 발담그기 @ 공감세미나
 
keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)keras 빨리 훑어보기(intro)
keras 빨리 훑어보기(intro)
 
DDD 준비 서문래
DDD 준비 서문래DDD 준비 서문래
DDD 준비 서문래
 
Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀Tensorflow regression 텐서플로우 회귀
Tensorflow regression 텐서플로우 회귀
 
Ddd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksugDdd start 부록 지앤선&ksug
Ddd start 부록 지앤선&ksug
 
MVP 패턴 소개
MVP 패턴 소개MVP 패턴 소개
MVP 패턴 소개
 
파이썬 언어 기초
파이썬 언어 기초파이썬 언어 기초
파이썬 언어 기초
 
Event source 학습 내용 공유
Event source 학습 내용 공유Event source 학습 내용 공유
Event source 학습 내용 공유
 
Spring Boot 소개
Spring Boot 소개Spring Boot 소개
Spring Boot 소개
 
모델링 연습 리뷰
모델링 연습 리뷰모델링 연습 리뷰
모델링 연습 리뷰
 
ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료ALS WS에 대한 이해 자료
ALS WS에 대한 이해 자료
 
Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)Ji 개발 리뷰 (신림프로그래머)
Ji 개발 리뷰 (신림프로그래머)
 
리뷰의 기술 소개
리뷰의 기술 소개리뷰의 기술 소개
리뷰의 기술 소개
 
스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해스프링 시큐리티 구조 이해
스프링 시큐리티 구조 이해
 
자바8 스트림 API 소개
자바8 스트림 API 소개자바8 스트림 API 소개
자바8 스트림 API 소개
 
자바8 람다식 소개
자바8 람다식 소개자바8 람다식 소개
자바8 람다식 소개
 
Zookeeper 소개
Zookeeper 소개Zookeeper 소개
Zookeeper 소개
 
하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기하둡2 YARN 짧게 보기
하둡2 YARN 짧게 보기
 
차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)차원축소 훑어보기 (PCA, SVD, NMF)
차원축소 훑어보기 (PCA, SVD, NMF)
 

DDD 구현기초 (거의 Final 버전)

  • 1. 짜친 세미나, DDD 쌩기초 이야기 - 거의 Final Version 최범균 (madvirus@madvirus.net) 자바캔 카페(http://cafe.daum.net/javacan) 자바캔 블로그(http://javacan.tistory.com)
  • 2. TOC • 객체와 연관 – 객체와 연관 • DDD 쌩 기초 – 레이어 구성 – DDD 빌딩 블록 • DDD와 ORM • DDD 구현 이야기 – ORM 이용 구현하기 • 도메인 모델 구현 • 리포지토리의 구현 – 어플리케이션 레이어 서비스 구현 – UI 영역(컨트롤러) 구현 • 참고 자료 2
  • 4. 객체란? 객체는 기능 제공 객체 객체 객체 객체 객체 객체 다른 객체를 사용 4
  • 5. 클래스: 객체의 정의 • 기능을 public 메서드로 정의 – 데이터는 외부에 드러내지 않고 기능 정의만 제공 • getter/setter 메서드의 최소화 • 다른 객체를 사용하는 방법 – 필드를 이용해서 다른 객체를 레퍼런스로 참조 • 연관(Association)이라고 표현 – 메서드에서 필요한 시점에 객체를 생성해서 사용 5
  • 6. 객체 간 연관의 예 필드 public class Employee { Organization org = new Organization(…); private String name; private Organization organization; Employee e1 = new Employee(…); ... Employee e2 = new Employee(…); public void setOrganization(Organization org) { this.organization = org; org.add(e1); } org.add(e2); } 필드 public class Organization { private String name; private List<Employee> employees; ... public void add(Employee emp) { this.employees.add(emp); emp.setOrganization(this); } } 6
  • 7. 연관의 방향성 • 방향성의 종류 – 단 방향: 두 객체 중 한 객체만 레퍼런스 가짐 – 양 방향: 두 객체가 서로에 대한 레퍼런스 가짐 • 양 방향 예 emp1:Employee org1:Oragnization rule1:Rule organization=org1 employees = [emp1, emp2] rule = rule1 emp2:Employee organization=org1 7
  • 8. 연관의 종류 • Many-To-One – 예, 다수의 Employee가 한 Organization과 연관 • One-To-Many – 예, 한 Organization이 다수의 Employee와 연관 – 콜렉션으로 구현: Collection, Set, List, Map • One-To-One – 예, 한 Oranization이 한 Rule과 연관 • Many-To-Many – 콜렉션 8
  • 9. 모든 객체가 메모리 있다면… (1) • 연관된 객체들을 이용해서 기능을 구현 • 예1, Rule의 교체: 연관된 객체 교환으로 구현 Organization org = …; // 어딘가에서 구함 // Organization의 메서드 Rule newRule = new Rule(…); public void changeRule(Rule newRule) { org.changeRule(newRule); this.rule = newRule; } • 예2, 팀 이동: 양방향 연관을 처리 Organization org2 = …; // 어딘가에서 구함 // Employee의 메서드 Employee emp1 = …; // 어딘가에서 구함 public void transferTo(Organization org) { emp1.changeTeam(org2); Organization oldOrg = this.organization; this.organization = org; oldOrg.remove(this); } // Organization의 메서드 public void remove(Employee e) { employees.remove(e); } 9
  • 10. 모든 객체가 메모리 있다면… (2) • 연관된 객체들을 이용해서 기능을 구현 • 예3, Rule의 확인: 연관된 객체를 구해 확인 Organization org = …; // 어딘가에서 구함 // Organization의 메서드 Rule rule = org.getRule(); public Rule getRule() { if (rule != null) { return this.rule; rule.check(someData); } } // Rule의 메서드 publiic void check(Data data) { … } • 예4, Rule의 확인: 내부적으로 위임 Organization org2 = …; // 어딘가에서 구함 // Organization의 메서드 org.checkRule(someData); public void checkRule(Data data) { if (rule == null) { return; } rule.check(data); } 10
  • 11. 모든 객체가 메모리 있다면… (3) • 객체를 메모리에 보관/검색 위한 방법 필요 – 객체마다 고유 식별값 필요 • 메모리 상의 레퍼런스 이용은 한계 • 고유 식별 값을 갖는 객체를 Entity라 함 – 객체 보관하고 제공해주는 기능 필요 • DDD에서는 이를 Repository로 추상화 public interface OrganizationRepository { public void save(Organization org); public Organization findById(Integer id); } Organization org = organizationRepository.findById(id); org.checkRule(…); 11
  • 12. 객체의 라이프사이클 • 객체 생성 - 사용 - 소멸 – 동일 라이프사이클을 갖는 객체들의 군 존재 emp1:Employee org1:Oragnization rule1:Rule organization=org1 employees = [emp1, emp2] rule = rule1 emp2:Employee organization=org1 org1이 삭제되면 rule1도 삭제 org1이 삭제되도 emp2는 삭제 안 됨 12
  • 14. DDD(Domain Driven Design) • 도메인 모델로부터 디자인하기 • 도메인 모델의 중요성 강조 – 도메인 모델을 최대한 설계에 반영 • 예, Ubiquitous Language (용어 최대한 반영) – 모델이 깨지지 않는 방법 제시 (일관성 유지) • 예, Bounded Context, Anticorruption Layer 등 • 이를 위한 기본 설계 기법 제시 – 레이어 구성 – 도메인 레이어의 기본 빌딩 블록 14
  • 15. DDD 구현 위한 필수 쌩 기초 발췌: Domain Driven Design (Eric Evans) 15
  • 16. Layered Architecture 사용자에게 정보 출력 User Intreface 사용자의 요청을 해석 하위 레이어에 전달 어플리케이션의 상태를 관리 / Thin Layer Application 비즈니스 로직/객체 상태를 포함하지 않음 실제 비즈니스 처리는 도메인에 요청 도메인에 대한 정보를 포함 Domain 비즈니스 객체의 상태를 포함 비즈니스 로직을 제공 다른 레이어를 위한 지원 라이브러리 Infrastructure 영속성 구현 16
  • 17. 도메인 모델의 기본 구성 요소 • Entity • Value • Aggregate • Repository • Service 17
  • 18. 도메인 모델의 기본 구성 요소, Entity • 주요 특징 – 모델을 표현 – 고유의 식별 값을 가짐 – 모델과 관련된 비즈니스 로직을 수행 – 자신만의 라이프 사이클을 가짐 • 예, 평가 시스템에서의 Entity – Employee(직원) – Organization(조직) 18
  • 19. 도메인 모델의 기본 구성 요소, Value • 고유의 키 값을 갖지 않음 • 데이터를 표현하기 위한 용도로 주로 사용 – 개념적으로 완전한 데이터 집합 <<Entity>> – (주로) Immutable 임 Employee 자신에게 알맞은 로직을 제공 -id : Integer – -name : String – Entity의 속성으로 사용 -address : Address -organization : Organization • 자신의 라이프사이클을 갖지 않음 • 엔티티를 따름 1 • 예 – Address(주소) 1 <<Value>> • 데이터: 우편번호, 주소1, 주소2 Address – Money(돈): -zipcode : String • 데이터: 금액, 화폐 단위 -address1 : String -address2 : String • 로직: 더하기, 곱하기 등 19
  • 20. 도메인 모델의 기본 구성 요소, Aggregate • Aggregate – 관련된 객체들의 묶음 • Aggregate의 특징 – 데이터 변경시 한 단위로 처리 됨 • 비슷한 또는 거의 유사한 라이프사이클을 갖는 객체들 – 특히, 삭제 시 함께 삭제됨 – Aggregate는 경계를 가짐 • 기본적으로, 한 Aggregate에 속한 객체는 다른 Aggregate에 속하지 않음 • Aggregate 필요성 – 많은 도메인 모델을 가능한 간단하고 이해가능한 수 준으로 만들 필요 – 연관의 개수를 줄임으로써 복잡도 감소 20
  • 21. Aggregate의 흔한 예, 주문-고객-상품 order item <<Entity>> OrderLine <<Entity>> <<Value>> <<Aggregate Root>> -product : Product <<Aggregate Root>> Option Order -quantity : int Product -id : Integer -id : Integer -lines : List<OrderLine> <<Value>> -name : String -shippingAddress : Address Price -listPrice : Price -value : int <<Value>> customer ItemDetail -description : String <<Entity>> Customer -id : String -name : String -address : Address 21
  • 22. 도메인 모델의 기본 구성 요소, Aggregate 루트 • Aggregate는 루트를 가짐 • Aggregate 루트 역할 – Aggregate의 내부 객체들을 관리 – Aggregate 외부에서 접근할 수 있는 유일한 객체 • Aggregate의 내부 Entity/Value는 루트를 통해 접근 – Aggregate에 대한 알맞은 기능을 수행 • 예, 주문 관련 Aggregate 루트인 Order의 기능 – 주문 취소, 배송지 주소 변경, 주문 상품 변경 • 내부 객체들의 연관을 탐색해서 기능 구현 22
  • 23. Entity, Value, Aggregate 도출 예, 도메인 분석 • 도메인: 평가 – 직원의 평가 – 평가는 성과 평가와 역량 평가로 구성 – 성과와 역량에 대해 • 본인 평가, 1차 평가, 2차 평가 존재 – 성과 평가 시, • 성과 항목 목록을 입력하고 각 항목에 대한 평가 내용을 입력 – 역량 평가 시, • 미리 정의된 역량 항목에 대한 평가 내용을 입력 23
  • 24. Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표 성과 목적 결과 가중치 본인 평가 1차 평가 2차 평가 평가 전산 고도화 위키 도입 30 의견 / A 의견 / A 의견 / B 그룹웨어 구축 보안 강화 DB 보안 강화 60 의견 / B 의견 / B 의견 / B 보안 프로세스 도입 팀역량강화 팀 세미나 5회 10 의견 / B 의견 / B 의견 / A 영어 참여율 80% 역량 역량 항목 본인 평가 1차 평가 2차 평가 평가 성취 목표 지향 의견 / A 의견 / A 의견 / B 협동 의견 / A 의견 / A 의견 / B 학습 능력 의견 / B 의견 / B 의견 / B 고객 지향 의견 / A 의견 / S 의견 / A 24
  • 25. Entity, Value, Aggregate 도출 예 평가 Aggregate self <<Value>> <<Entity>> PerfEvalSet RaterPerfEval first -self : RaterPerfEval -ratee : Employee -first : RaterPerfEval -rater : Employee -second : RaterPerfEval self -itemEvals : List<PerfItemRaterEval> 1 -done : boolean <<Entity>> 1 <<Aggregate Root>> <<Entity>> PersonnelEval <<Aggregate Root>> <<Value>> -id : Integer Employee PerfItem -employee : Employee 1 PerfItemRaterEval -name : String -goal : String -perfEvalSet : PerfEvalSet 1..* -grade : Grade -result : String -perfItems : List<PerfItem> -comment : String -perfItem : PerfItem +evaluatePerfBySelf() +evaluatePerfByFirst() +evaluatePerfBySecond() 1 self <<Value>> RaterCompeEval 1 CompefEvalSet -ratee : Employee first -self : RaterCompeEval -rater : Employee -first : RaterCompeEval -itemEvals : List<CompeItemRaterEval> -second : RaterCompeEval second -done : boolean CompeItemRaterEval -grade : Grade -comment : String 25
  • 26. Entity, Value, Aggregate 도출 예, 도메인 분석 - 실제표 perfEvalSet: PerfEvalSet self:PerfEv alSet 성 목적 결과 가중치 본인평가 1차 평가 2차 평가 과 ----- ----- 30 의견 / A 의견 / A 의견 / B self PerfItem <<Value>> <<Entity>> PerfEvalSet RaterPerfEval PerfItem first ----- ----- 60 의견 / B 의견 / B 의견 / B -self : RaterPerfEval -ratee : Employee RaterEval -first : RaterPerfEval -rater : Employee -second : RaterPerfEval self -itemEvals : List<PerfItemRaterEval> ----- ----- 10 의견 / B 의견 / B 의견 / A 1 -done : boolean <<Entity>> 1 <<Aggregate Root>> 역 역량 항목 본인평가 1차 평가 PersonnelEval 평가 2차 량 -id : Integer <<Value>> PerfItem ----- 의견 / A 의견 / A : Employee / B -employee 의견 1 -goal : String PerfItemRaterEval -perfEvalSet : PerfEvalSet -grade : Grade CompeItem 의견 / A : List<PerfItem> B 1..* ----- 의견 / A 의견 / -result : String -perfItems -comment : String RaterEval +evaluatePerfBySelf() -perfItem : PerfItem ----- 의견 / B 의견 / B +evaluatePerfByFirst() / B 의견 +evaluatePerfBySecond() 1 ----- 의견 / A 의견 / S 의견 / A <<Value>> self RaterCompeEval 1 CompefEvalSet -ratee : Employee first -self : RaterCompeEval -rater : Employee self:CompeEv -first : RaterCompeEval -itemEvals : List<CompeItemRaterEval> alSet -second : RaterCompeEval -done : boolean compeEvalSet:CompeEvalSet second PersonnelEval CompeItemRaterEval -grade : Grade -comment : String 26
  • 27. 도메인 기능 구현 예 - 본인 성과 평가 기능 • 본인 평가하기 기능 → 평가 Aggregate의 기능 – 본인 평가하기를 구현하려면 • PersonnelEval의 perfEvalSet 필드로 연결된 • PerfEvalSet의 self 필드로 연결된 • RaterPerfEval을 설정 – 피평가자(ratee), 평가자(rater), 각 항목 평가(itemEvals) self <<Entity>> <<Value>> <<Entity>> <<Aggregate Root>> PerfEvalSet RaterPerfEval 1 first PersonnelEval -self : RaterPerfEval -ratee : Employee -id : Integer 1 -first : RaterPerfEval -rater : Employee -employee : Employee -second : RaterPerfEval self -itemEvals : List<PerfItemRaterEval> -perfEvalSet : PerfEvalSet -done : boolean -perfItems : List<PerfItem> +evaluatePerfBySelf() +evaluatePerfByFirst() 1 PerfItem <<Value>> +evaluatePerfBySecond() 1..* -goal : String PerfItemRaterEval -result : String -grade : Grade -comment : String -perfItem : PerfItem 27
  • 28. 도메인 기능 구현 예 - 본인 성과 평가 기능 public class PersonnelEval { private PerfEvalSet perfEvalSet; public void evaluatePerfBySelf(List<PerfItemRaterEval> evals, boolean done) { perfEvalSet.setSelf(employee, evals, done); } … } Aggregate Root가 Aggregate의 다른 객체에 위임 public class PerfEvalSet { private RaterPerfEval self; public void setSelf(Employee ratee, List<PerfItemRaterEval> evals, boolean done) { if (self == null) { self = new RaterPerfEval(rater, ratee); } self.change(evals, done); } … } 28
  • 29. 도메인 기능 구현 예 - 본인 성과 평가 기능 public class RaterPerfEval { private Employee ratee; private Employee rater; private List<PerfItemRaterEval> evals; private boolean done; public RaterPerfEval(Employee ratee, Employee rater) { this.ratee = ratee; this.rater = rater; } public void change(List<PerfItemRaterEval> evals, boolean done) { this.evals.clear(); PerfItemRaterEval은 Value이고 Immutable 임: this.evals.addAll(evals); 데이터 값 변경이 아닌, 기존 데이터 삭제 후 새로 추가 this.done = done; } … } 29
  • 30. 도메인 기능 구현 예 - 본인 성과 평가 완료 여부 • 본인 평가 완료 여부 → 평가 Aggregate의 기능 – 본인 평가 완료 여부를 구현하려면 • PersonnelEval의 perfEvalSet 필드로 연결된 • PerfEvalSet의 self 필드로 연결된 • RaterPerfEval에게 문의 self <<Entity>> <<Value>> <<Entity>> <<Aggregate Root>> PerfEvalSet RaterPerfEval 1 first PersonnelEval -self : RaterPerfEval -ratee : Employee public class PersonnelEval { -id : Integer 1 -first : RaterPerfEval -rater : Employee -employee : Employee -second : RaterPerfEval -itemEvals : List<PerfItemRaterEval> private PerfEvalSet perfEvalSet; self -perfEvalSet : PerfEvalSet -done : boolean -perfItems : List<PerfItem> public boolean isSelfPerfEvaluationDone() { +evaluatePerfBySelf() return perfEvalSet.isSelfDone(); PerfItem +evaluatePerfByFirst() } 1 <<Value>> +evaluatePerfBySecond() -goal : String } 1..* PerfItemRaterEval -result : String -grade : Grade -comment : String -perfItem : PerfItempublic class PerfEvalSet { public isSelfDone() { return self == null ? false : self.isDone(); } } 30
  • 31. 도메인 모델의 기본 구성 요소, Repository • Entity를 보관하는 장소 • 기본 규칙: – Aggregate 당 한 개의 Repository 인터페이스 – Aggregate의 CRUD 기본 단위는 루트! • 예외, 성능 상 이유로 Aggregate에 속한 다른 엔티티에 직접 접근할 필요가 있는 경우 별도 DAO 구현 – 예, 리포트 집계 등 • Repository의 기본 인터페이스 – save(루트): 한 Aggregate의 저장 – List<루트> findByName(): 특정 조건으로 검색 – delete(루트): 한 Aggregate의 삭제 31
  • 32. Specification을 통한 검색 • Specification – Repository에서 Entity를 검색하기 위한 필터 • DDD에서의 Specification 구현의 모습 public interface Specification<T> { public boolean satisfy(T entity); } public class SomeCustomerRepository implements CustomerRepository { public List<Customer> findBySpecification(Specification<Customer> spec) { List<Customer> all = findAll(); List<Customer> result = new ArrayList<Customer>(); for (Customer c : all) { if (spec.satisfy(c)) { 개념적으로는 맞지만, result.add(c); 모든 Entity 로딩 시, } 성능 문제 발생 } return result; } } 32
  • 33. Specification의 조합 • Specification은 서로 조합이 될 때 유용함 – 다수의 Specification을 and/or로 연결 도메인에 맞는 검색 조건 표현 Specification<Customer> ageGtSpec = new AgeGraterThanSpec(20); Specification<Customer> locationSpec = new LocationEqSpec(Location.SEOUL); Specification<Customer> ageLocSpec = Specs.and(ageGtSpec, locationSpec); 검색 조건 조합 List<Customer> custmoers = customerRepository.findBy(ageLocSpec); Composite Pattern (또는 트리 구조) 이용하여 구현 33
  • 34. 도메인 모델의 기본 구성 요소, 도메인 레이어의 Service • 한 Entity나 Aggregate에 속하지 않은 도메인 기 능을 도메인 서비스로 분리 – 예, 계좌 이체 • 계좌 이체는 한 계좌 엔티티 객체가 수행할 수 없는 도메인 기능 • 도메인 서비스의 구현 – 다른 도메인 구성 요소 이용해서 기능 구현 • 타 레이어의 서비스와 구분 34
  • 35. DDD 쌩기초의 접근법 • 도메인 모델 중심 접근 필요 • 객체 연관 중심 접근 필요 – 도메인 기능 구현 시, 도메인 객체 간 연관으로 풀기 • SQL을 머리에서 버릴 것 (특히, JOIN!) 35
  • 37. 메모리는 영원하지 않음 • 안정적인 데이터 관리 위해 객체를 물리적인 기 록 장치에 보관할 필요 • 객체 모델과 일치하는 물리적 데이터 저장소는 흔치 않음 – OODB는 시장에서 실패 – RDBS는 딱 들어맞지 않음 – 기타 NoSQL 역시 정확하게 OO와 일치하진 않음 37
  • 38. 차이의 예: 객체 모델과 ER의 대표적인 차이 객체 모델 관계 모델 연관 방향성 양방향 단방향 레퍼런스(필드) 이용 Foreign Key 이용 콜렉션 연관 List, Set, Map 등 콜렉션 사용 Foreign Key 사용 Join/Collection 테이블 사용 다형성 인터페이스/상속 사용 없음 38
  • 39. ORM의 필요성 • DDD를 즐겁게 하려면 – 객체를 이용한 모델링 뿐만 아니라, – 객체 모델과 데이터 모델 간 좋은 매핑 도구 필요 • 추천 프레임워크 – JPA (자바의 ORM 표준 스펙) • 객체와 RDB 사이의 모든 매핑을 거의 소화 – 또한, Spring Data 추천 – DB 연동 코드 작성을 위한 노가다 감소 – Spring Data MongoDB 등을 통한 NoSQL과의 매핑 처리 39
  • 41. 전체 레이어 별 구성 요소 데이터 조회 목적 Repository 접근해서 도메인 객체 구함 도메인 모델을 DTO로 변환해서 제공 데이터 읽기 위한 트랜잭션 범위 지정 도메인 기능 실행 요청 트랜잭션 범위 지정 도메인 모델 객체 제공 영속성 구현 제공 41
  • 42. 전체 레이어 별 구현: Spring + JPA Spring Bean Spring MVC Spring Bean Spring TX Spring Bean Spring TX JPA Spring Data JPA Spring Bean JPA 42
  • 44. ORM을 이용한 DB와의 매핑: Entity & Value • Entity 당 한 개의 테이블 매핑 • Entity 간 참조 – 대부분 단방향의 Foreign Key로 처리 – 경우에 따라 Join 테이블 이용 구현 • Entity 간 참조는 최대한 단방향으로 – 꼭 필요한 경우에만 양방향 • Value – 엔티티와 한 테이블에 함께 존재 • Value 콜렉션의 경우 Collection 테이블로 Value 구현 44
  • 45. Entity & Value 테이블 매핑 예 • 엔티티 간 연관: Foreign Key @Entity @Entity @Table(name = "EMPLOYEE") @Table(name = "ORGANIZATION") public class Employee { public class Organization { @Id @Column(name = "EMPLOYEE_ID") @Id private String id; @Column(name = "ORGANIZATION_ID") private Integer id; @Column(name = "NAME") ... private String name; } @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "ORGANIZATION_ID") private Organization organization; ... } 45
  • 46. Entity & Value 테이블 매핑 예 • Entity와 같은 테이블 사용하는 Value @Entity @Embeddable @Table(name = "EMPLOYEE") public class Address { public class Employee { @Column(name = "ADDR_1") @Id private String address1; @Column(name = "EMPLOYEE_ID") private String id; @Column(name = "ADDR_2") private String address2; @Column(name = "NAME") } private String name; @Embedded private Address address; EMPLOYEE ... } EMPLOYEE_ID NAME ORGANIZATION_ID ADDR1 ADDR2 46
  • 47. Entity & Value 테이블 매핑 예 • Value의 List 콜렉션: 콜렉션 테이블 사용 @Entity @Embeddable @Table(name = "RATER_PERF_EVAL") public class PerformanceItemRaterEval { public class RaterPerformanceEval { @Column(name = "GRADE_VALUE") private String gradeValue; @Id @Column(name = "RATER_PERF_EVAL_ID") @Column(name = "COMMENT") private Integer id; private String comment; … @ElementCollection } @CollectionTable(name = "RATER_PERF_ITEM_EVAL", joinColumns = @JoinColumn( name = "RATER_PERF_EVAL_ID")) @OrderColumn(name = "LIST_INDEX") private List<PerformanceItemRaterEval> itemEvals; 47
  • 48. Repository의 구현 • 인터페이스로 Repository 정의 – 각 ORM 구현체에 알맞게 구현 • 구현 클래스는 Infrastructure 레이어에 위치 public interface PersonnelEvalRepository { public PersonnelEval findByEmployee(Employee emp); PersonnelEval save(PersonnelEval eval); } public class JpaPersonnelEvalRepository implements PersonnelEvalRepository { @PersistenceContext private EntityManager em; public PersonnelEval findByEmployee(Employee emp) { TypedQuery<PersonnelEval> query = em.createQuery( "select p from PersonnelEval p " + "where p.employee = :emp", PersonnelEval.class); query.setParameter("emp", emp); return query.getSingleResult(); } public PersonnelEval save(PersonnelEval eval) { em.persist(eval); } } 48
  • 49. Specification의 실제 구현 • Specification으로부터 조건 생성 기능 필요 – CriteriaQuery 생성 or JP QL의 where 절 생성 public class JpaEmployeeRepository implements EmployeeRepository { @PersistenceContext private EntityManager em; public List<Employee> findBySpecification(Specification spec) { TypedQuery<Employee> query = em.createQuery( "select e from Employee e " + "where " + Specs.toJPQL(spec), Employee.class); spec.setParameters(query); return query.getResultList(); } } – Specification을 직접 구현하는 데는 노력 필요 49
  • 50. Spring Data JPA Repository 자동 생성 Spring Data JPA Spcification 지원 50
  • 51. Spring Data JPA 이용 Repository 구현 • Repository를 위한 메서드 Convention 정의 – 인터페이스로부터 런타임 시, 구현 객체 자동 생성 public interface EmployeeRepository extends Repository<Employee, String> { Employee findById(String userId); Employee findByName(String name); @Query("select e from Employee e left join e.organization o "+ "where e.rateeTypeValue <> 'NOT_RATEE' order by o.name asc, e.name asc") List<Employee> findAllRatees(); } 51
  • 52. Spring Data JPA 이용 Repository 구현, Spec 지원 • Specification을 위한 기능 제공 – 검색 조건 표현 위한 Specification 인터페이스 제공 public class EmployeeSpecs { public static Specification<Employee> rateeType(final RateeType e) { return new Specification<Employee>() { @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { return cb.equal(root.get(Employee_.rateeTypeValue), e.name()); } }; } 조건을 도메인 용어로 표현 public static Specification<Employee> nameLike(final String name) { return new Specification<Employee>() { @Override public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> query, CriteriaBuilder cb) { return cb.like(root.get(Employee_.name), "%" + name + "%"); } }; } } 52
  • 53. Spring Data JPA 이용 Repository 구현, Spec 지원 • Specification을 위한 기능 제공 – Repository 메서드에 Specificiation 지정 가능 public interface EmployeeRepository extends Repository<Employee, String> { List<Employee> findAll(Specification<Employee> spec); } public interface EmployeeRepository extends Repository<Employee, String>, JpaSpecificationExecutor<Employee> { // JpaSpecificationExecutor에 기본 메서드 정의 } 53
  • 54. Spring Data JPA 이용 Repository 구현, Spec 지원 • Specification과 Repository의 사용 예 – Repository 메서드에 Specificiation 지정 가능 Criteria와 같은 유연함을 제공 영속 레이어에 대한 의존 제거 (QueryDSL은 EntityManager를 필요) Specifications<Employee> spec = Specifications.where( EmployeeSpecs.rateeType(RateeType.NOT_RATEE)).and( EmployeeSpecs.nameLike("김")); List<Employee> findAll = employeeRepository.findAll(spec); 54
  • 55. Lazy & Eager Loading • Entity 간 연관에서 쓰임 고려한 설정 필요 Employee를 가져올 때, 연관된 Organization도 함께 로딩? Eager Loading Employee emp = employeeRepository.findById("madvirus"); Organization org = emp.getOrganization(); org.getName(); 이 때, Organization과 매핑된 테이블에서 데이터 로딩? Lazy Loading 55
  • 57. 전체 레이어 별 구성 요소 데이터 조회 목적 Repository 접근해서 도메인 객체 구함 도메인 모델을 DTO로 변환해서 제공 데이터 읽기 위한 트랜잭션 범위 지정 도메인 기능 실행 요청 트랜잭션 범위 지정 57
  • 58. 애플리케이션 레이어 구현 • 애플리케이션 서비스의 정의 – 사용자에게 기능 제공 위한 인터페이스 정의 • 기능명/기능정의 메서드/입력 파라미터/리턴 결과로 구성 • 도메인을 이용한 구현 – Repository에서 Entity를 가져와 – Entity에 기능을 요청 또는 Entity로부터 정보 조회 • 트랜잭션 범위 지정 – 트랜잭션 시작/커밋/롤백 제어 58
  • 59. 애플리케이션 레이어 구현 - 서비스 정의 예 public interface ReturnEvaluationService { public ReturnResult returnSelfPerfEval(String rateeId, String raterId); } 처리 결과를 표현 기능 실행에 필요한 입력 public interface SelfPerformanceEvaluationService { SelfPerEvalResult evaluate(SelfPerEvalRequest request); } 59
  • 60. 애플리케이션 레이어 구현 - 서비스 구현 예 public class DomainReturnEvaluationService implements ReturnEvaluationService { private PersonnelEvalRepository personnelEvalRepository; @Transactional 스프링 트랜잭션 기능 사용 @Override public ReturnResult returnSelfPerfEval(String rateeId, String raterId) { PersonnelEval personnelEval = checkValidRaterAndGet(rateeId, raterId); personnelEval.returnSelfPerfEval(); return new ReturnResult(rateeId, personnelEval.getEmployee().getName()); } 도메인 객체 사용 private PersonnelEval checkValidRaterAndGet(String rateeId, String raterId) { PersonnelEval personnelEval = personnelEvalRepository .findByEmployeeId(rateeId); if (!personnelEval.getEmployee().checkFirstRater(raterId)) { throw new RuntimeException("1차 평가자만 반려 가능"); } return personnelEval; } … } 60
  • 61. UI 레이어의 구현 • UI 레이어의 역할 두 가지 – 사용자의 기능 실행 요청을 애플리케이션 레이어에 전달하기 • 서비스가 요구하는 데이터를 전달하면 끝 • 서비스의 처리 결과를 뷰에 보여주면 끝 – 사용자에게 데이터 보여주기 • 도메인 데이터를 어떻게 뷰에 전달할 것인가? 61
  • 62. UI 레이어 구현, 역할 1 - 서비스에 요청 전달하기 • 컨트롤러에서 서비스에 실행 위임 – 서비스의 입력 값 처리 • 커맨드 객체로 받기 (입력 Form으로부터 요청 객체 생성) • 컨트롤러에서 직접 생성 @RequestMapping(method = RequestMethod.POST) public String submit(ModelMap modelMap, SelfPerEvalRequest request) { SelfPerEvalResult result = evaluationService.evaluate(request); modelMap.addAttribute("result", result); 커맨드 객체로 사용 return "eval/self/selfPerfResult"; } @RequestMapping("/review/returnSelfPerfEval") public String returnPerfEval(@RequestParam("rateeId") String rateeId, ModelMap modelMap) { ReturnResult result = returnEvaluationService.returnSelfPerfEval(rateeId, SecurityUtil.getId()); modelMap.addAttribute("result", result); return "review/returnPerfResult"; 컨트롤러에서 직접 생성 } 62
  • 63. UI 레이어 구현, 역할 2 - 데이터 보여주기 • UI 레이어에 데이터를 가져오는 기능 구현 – 읽어올 데이터가 많다면, • 컨트롤러와 분리된 별도 객체로 구현 63
  • 64. DataLoadingService의 구현 • 도메인 레이어를 이용한 구현 – Repository로부터 필요한 엔티티 구함 • 검색 조건 조합 필요시 Specification을 이용 – 엔티티로부터 UI에 필요한 데이터 추출 • 방법 1, 엔티티를 그대로 리턴하기 • 방법 2, DTO를 이용해서 데이터 전달 • 방법에 따라 트랜잭션 경계가 달라짐 public class DomainEmployeeDataLoader implements EmployeeDataLoader { @Transactional public SomeReturn load(String empId) { Employee emp = employeeRepository.findById(empId); checkNull(emp); return new SomeReturn(emp); } … } 64
  • 65. 데이터 보여줄 때, 도메인 객체의 노출 문제! • 도메인 객체를 그대로 UI 레이어에 노출 시 문제 – 도메인 기능이 노출 → 안정성의 문제 • UI 레이어에서 도메인 객체가 제공하는 기능을 실행하면…. – 레이어를 두는 이유가 사라짐!! – 연관된 객체 접근 시 • JPA의 영속성 컨텍스트 범위가 UI 레이어로 확장되어야 함 • 또는 DataLoader에서 미리 읽어야 함 (연관이 Lazy인 경우) <%-- 도메인 객체 노출 시, 문제 가능성 --%> organization이 Lazy면 트랜잭션 범위 확장 필요 <%= employee.getOrganization().getName() %> <% employee.changePassword("", "newPassword"); %> OSIV, No! 65
  • 66. 개인적 의견: DTO 내지 상위의 읽기 전용 인터페이스 사용 • UI에서 필요로 하는 데이터만 담고 있는 DTO – DataLoader에서 도메인 객체를 DTO로 변환처리 // DataLoader PersonnelEval eval = personnelEvalRepository.findById(id); ViewDataDTO dto = convert(eval); // DTO: 기본 데이터 타입 사용, getter만 제공 return dto; • Getter만 갖는 상위 Interface – 리플렉션 통해서 메서드 실행이 가능하므로 비추 // DataLoader public PersonnelEvalIF load() { // PersonnelEvalIF는 read only 메서드만 제공 PersonnelEval eval = personnelEvalRepository.findById(id); return eval; } 66
  • 67. DTO를 만드는 방법 • 1, 도메인 객체에 getter를 만들어서 값 읽어오기 – 구현 쉬움 – 프로퍼티에 대한 getter 메서드 생성 필요 – getter 메서드가 증가 • 2, 도메인 객체로부터 값을 받을 수 있는 Builder 를 만들어서 DTO 객체 생성하기 – 구현은 다소 복잡 – 단일 Builder 인터페이스를 이용한 DTO 생성 가능 – getter 메서드의 최소화 67
  • 68. 정리 68
  • 69. Action! • 도메인 모델 개발 – 객체 간 연관으로 사고하는 연습 – ORM(JPA) 이용 매핑 처리 • 레이어 간 명확한 역할 구분 – 모든 도메인 로직은 도메인 레이어에 모이도록 • 도메인 로직이 전 레이어에 퍼지지 않도록! • 리포지토리 구현 – Spring Data 이용하면 좀 더 편리 – Spring Data의 Specification 활용 69
  • 70. Q&A 70