SlideShare ist ein Scribd-Unternehmen logo
1 von 93
Downloaden Sie, um offline zu lesen
DOMAIN MODEL 패턴과 JPA의 조화

객체지향적인 도메인 레이어 구축하기
조영호
NHN 커머스개발센터
Eternity’s Chit-Chat(http://aeternum.egloos.com)
목차

1. 온라인 영화 예매 시스템 도메인



2. 임피던스 불일치Impedance Mismatch



3. JPAJava Persistence API



4. 결롞
1. 온라인 영화 예매 시스템 도메인
Domain Concept - 영화




             Movie




    4 / 객체지향적인 도메인 레이어 구축하기
Domain Concept - 상영

                                         2011-10-18 09:30 조조


          Showing                                   2011-10-21 20:30 5회

                              2011-12-01 14:20 4회




    5 / 객체지향적인 도메인 레이어 구축하기
Domain Concept – 할인 정책




         Discount                 Amount Discount
                                 8,000 - 800 = 7,200




                                   Percent Discount
                             8,000 – (8,000 * 0.1) = 7,200




   6 / 객체지향적인 도메인 레이어 구축하기
Domain Concept – 할인 규칙



                                 Sequence Rule
             Rule
                             조조 상영인 경우

                             10회 상영인 경우



                                    Time Rule
                             월요일 10:00 ~ 12:00 상영인 경우

                             화요일 18:00 ~ 21:00 상영인 경우



   7 / 객체지향적인 도메인 레이어 구축하기
Domain Concept –할인 정책 + 할인 규칙


                                                        조조 상영인 경우


                                                        10회 상영인 경우
               도가니                      Amount DC
               8000원                      800원
                                                        월요일 10:00 ~ 12:00 상영인 경우


                                                        화요일 18:00 ~ 21:00 상영인 경우




               Movie                     Discount                  Rule



                             1   0..1               1      1..*




   8 / 객체지향적인 도메인 레이어 구축하기
Domain Concept –예매




        Reservation
                              제   목   도가니


                                      2011년 10월 18일 (목)
                              상영 정보   7회 6:00(오후) – 8:00(오후)


                              인   원   2명

                              정   가   16,000원

                              결재 금액   14,400원




    9 / 객체지향적인 도메인 레이어 구축하기
Domain Model

        Showing                       Reservation



                       1       0..*


               0..*


               1




                       1       0..1                 1   1..*


          Movie                        Discount                Rule


    10 / 객체지향적인 도메인 레이어 구축하기
영화 예매 책임 수행을 위한 협력의 설계

 후보 객체Candidate, 책임Responsibility, 협력Collaboration 식별

                                                   Movie
  Showing                                          영화 정보를 알고 있다      Discount
                                                                     Strategy
                                                   가격을 계산한다
  상영 정보를 알고 있다           Movie
  예매 정보를 생성한다                                            DiscountStrategy
                                                         할인율 정책을 알고 있다       Rule
                                                         할인된 가격을 계산한다
                                                              Rule
                                                              할인 정책을 알고 있다          Showing
                                                              할인 여부를 판단한다



      11 / 객체지향적인 도메인 레이어 구축하기
도메인 레이어 객체 구현
                                                                                      User Interface


                                                                                      Service



                                                                 Reservation          Domain

                 Showing
                                         <<create>>                                   Infrastructure
  reserve(customer, count):Reservation

                                                                  Customer



                                                                  {abstract}                           {abstract}
                   Movie                                    DiscountStrategy                            Rule
  calculateFee(showing):Money                         calculateFee(showing):Money    isStatisfiedBy(showing):boolean




       Amount                            Percent                    NonDiscount     Sequence                        TimeOfDay
       Strategy                          Strategy                    Strategy         Rule                             Rule




   12 / 객체지향적인 도메인 레이어 구축하기
Domain Model

        Showing                       Reservation



                       1       0..*


               0..*


               1




                       1       0..1                 1   1..*


          Movie                        Discount                Rule


    13 / 객체지향적인 도메인 레이어 구축하기
Domain Layer Design & Domain Model

              Showing                                            Reservation

                                                                       Reservation
                 Showing
                                         1   <<create>>
                                                          0..*
  reserve(customer, count):Reservation

                                                                        Customer
                         0..*

                                                                        {abstract}                           {abstract}
                   Movie                                          DiscountStrategy                            Rule
                         1
  calculateFee(showing):Money                               calculateFee(showing):Money        isStatisfiedBy(showing):boolean




                                         1                0..1                            1   1..*
       Amount                                Percent                      NonDiscount         Sequence                    TimeOfDay
       Strategy                              Strategy                      Strategy             Rule                         Rule


                Movie                                               Discount                                     Rule


      14 / 객체지향적인 도메인 레이어 구축하기
아키텍처 패턴
                             User Interface


                             Service



                             Domain



                             Infrastructure




           Domain Model
  15 / 객체지향적인 도메인 레이어 구축하기
2. 임피던스 불일치Impedance Mismatch
임피던스 불일치Impedance Mismatch




    17 / 객체지향적인 도메인 레이어 구축하기
객체-관계 임피던스 불일치

 객체 모델과 DB 스키마 간의 불일치
 객체 패러다임Object Paradigm과 관계 패러다임Relational Paradigm 간의 불일치




                                                                                             RULE
                                                                             DISCOUNT
              DiscountStrategy                            Rule                               ID
                                                                             MOVIE_ID(FK)
                                                                                             DISCOUNT_ID(FK)
                                                                             DISCOUNT_TYPE   POSITION
                                                                             FEE_AMOUNT      RULE_TYPE
                                                                             FEE_CURRENCY    DAY_OF_WEEK
   Amount         Percent        NonDiscount   Sequence          TimeOfDay   PERCENT         START_TIME
   Strategy       Strategy        Strategy       Rule               Rule                     END_TUME
                                                                                             SEQUENCE




      18 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  19 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  20 / 객체지향적인 도메인 레이어 구축하기
Mismatch    구성 요소 크기Granularity의 불일치

                                                    MOVIE
                                                       ID(PK)

                                                       TITLE
                                                       RUNNING_TIME
           Movie                                       FEE_AMOUNT
                                                       FEE_CURRENCY

             제목
              하나와 앨리스


             시간
             135분
                                                                                   <<value object>>
                                                                      running        Duration
                                                                         Time
             요금                                                                 quantity
                                          <<entity>>
             8,000원
                                            Movie
                                 title                                            <<value object>>

                                 calculateFee(showing):Money
                                                                                       Money
                                                                                amount
                                                                                currency
                                                                          fee




    21 / 객체지향적인 도메인 레이어 구축하기
Entity & Value Object

   Identity                                                 Value




                                                    Value Object

                Entity                                           <<value object>>
                                                  running           Duration
                                                    Time
                                                             quantity
                              <<entity>>
                              Movie
                    title                                        <<value object>>

                    calculateFee(showing):Money                      Money
                                                             amount
                                                             currency
                                                      fee


     22 / 객체지향적인 도메인 레이어 구축하기
책임의 재사용



                             Money
                             금액과 환율을 알고 있다

       Movie                 금액을 +,-,*,/한다

      영화 정보를 알고 있다
      가격을 계산한다                     Duration
                                  기간을 알고 있다.
                                  기간의 합, 차를 계산한다




  23 / 객체지향적인 도메인 레이어 구축하기
Problem     코드 중복Code Duplication
                                                                                              RESERVATION
           MOVIE
                                                                                               ID(PK)
            ID(PK)
                                                                                               CUSTOMER_ID(FK)
            TITLE                                                                              SHOWING_ID(FK)
            RUNNING_TIME                                                                       FEE_AMOUNT
            FEE_AMOUNT                                                                         FEE_CURRENCY
            FEE_CURRENCY                                                                       AUDIENCE_COUNT


                           class Movie {
                            long plus(long fee, Currency currency) {
                             if (this.feeCurrency.equals(currency) {
                               return this.fee + fee;
                             }

                 Movie          throw new IllegalArgumentException();                            Reservation
                            }
          id               }                                                               id
          title                                                                            customerId
          runningTime                                                                      showingId
          fee                                   class Reservation {                        amount
                                                 long add(long amount, Currency currency) {
          feeCurrency                                                                      acmointCurrency
                                                  if (this.amountCurrency.equals(currency) {
                                                     return this.amount + fee;             audienceCount
          calculateFee()                             }
                                                                                             getFee()
                                                     throw new IllegalArgumentException();
                                                 }
                                                }

    24 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  25 / 객체지향적인 도메인 레이어 구축하기
Mismatch        데이터베이스 식별자Database Identity

 테이블 주키Primary Key


                제목                                        제목
                시간을                                        시간을
                달리는 소녀                                     달리는 소녀

                시간                                        시간
                95분                                       95분

                요금                                        요금
                8,000원                                    8,000원




      MOVIE

           ID               TITLE     RUNNING_TIME   FEE_AMOUNT     FEE_CURRENCY

           1             시간을 달리는 소녀        95          8,000            KRW

           2             시간을 달리는 소녀        95          8,000            KRW




     26 / 객체지향적인 도메인 레이어 구축하기
객체 식별자Object Identity

 Java == 연산자


                               제목                           제목
                                시간을                         시간을
                                달리는 소녀                      달리는 소녀

                               시간                           시간
                               95분                          95분

                               요금                           요금
                               8,000원                       8,000원




       address 1                         address 2
                   movie1 : Movie                    movie2 : Movie

            title = ‚시간을 달리는 소녀‛              title = ‚시간을 달리는 소녀‛
            runningTime = 95                  runningTime = 95
            Fee = 8000                       Fee = 8000




     27 / 객체지향적인 도메인 레이어 구축하기
Problem        데이터베이스-객체 식별자 불일치Identity Mismatch


     MOVIE

          ID                  TITLE   RUNNING_TIME   FEE_AMOUNT              FEE_CURRENCY

          1              시간을 달리는 소녀        95          8,000                      KRW

          2              시간을 달리는 소녀        95          8,000                      KRW




               movie1 : Movie                                      movie2 : Movie

           title = ‚시간을 달리는 소녀‛                                title = ‚시간을 달리는 소녀‛
           runningTime = 95                                    runningTime = 95
           Fee = 8000                                         Fee = 8000




    28 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  29 / 객체지향적인 도메인 레이어 구축하기
Mismatch    다형성Polymorphism


                                                                                    {abstract}
                                                         Movie              DiscountStrategy

           Movie               Discount           calculateFee(showing)    registerDate

                                                                           calculateFee(showing)


                       Amount Discount    800원



                                                       Amount                  Percent                   Non
                                                   DiscountStrategy       DiscountStrategy         DiscountStrategy
                       Percent Discount   10%
                                                   discountAmount         percent




                                                  public class Movie {
                         No Discount      0원(%)    private DiscountStrategy discountStrategy;

                                                   public Money calculateFee(Showing showing) {
                                                     return discountStrategy.calculateFee(showing);
                                                   }
                                                  }




    30 / 객체지향적인 도메인 레이어 구축하기
Problem     젃차적인 조건 분기Conditional Branch


                                                                                    {abstract}
                                                         Movie Movie                 DiscountStrategy
                                                                            DiscountStrategy
                                                          id                        movieId
          Movie                Discount           calculateFee(showing)
                                                          title
                                                                           registerDate
                                                                                    discountType
                                                         runningTime       calculateFee(showing)
                                                                                    amount
                                                         fee                         percent
                       Amount Discount    800원           feeCurrency                 registerDate
                                                         calculateFee()
                                                                                     calculateFee()

                                                       Amount                  Percent                        Non
                                                   DiscountStrategy       DiscountStrategy              DiscountStrategy
                       Percent Discount   10%
                                                   discountAmount         percent



                                                  public class ReservationService {
                                                  public class Movie {
                                                    public Money calculateFee(Movie movie,
                         No Discount      0원(%)     private DiscountStrategy discountStrategy) {
                                                             DiscountStrategy discountStrategy;
                                                      if (discountStrategy.isAmountType()) {
                                                          ...
                                                    public Money calculateFee(Showing showing) {
                                                      } else if (discountStrategy.isPercentType()) {
                                                      return discountStrategy.calculateFee(showing);
                                                    }     ...
                                                      } else {
                                                  }       ...
                                                      }
                                                      ...
                                                    }
                                                  }
    31 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  32 / 객체지향적인 도메인 레이어 구축하기
Mismatch    데이터베이스 외래키Foreign Key

                                              MOVIE                                 SHOWING
                                              ID(PK)                                ID(PK)

                                              TITLE                                 MOVIE_ID(FK)
                                              RUNNING_TIME                          SEQUENCE
           Movie               Showing        FEE_AMOUNT                            SHOWING_TIME
                                              FEE_CURRENCY

                        1회      10/18 10:00



                        2회     10/18 12:30
                                               MOVIE

                        3회                       ID              TITLE
                               10/18 15:00
                                                  1      하나와 앨리스

                        4회     10/18 17:30

                                              SHOWING

                                                 ID     MOVIE_ID         SEQUENCE            SHOWING_TIME

                                                  1          1              7            2010-12-23 18:00




    33 / 객체지향적인 도메인 레이어 구축하기
테이블 외래키Foreign Key - 양방향BiDirectional

                               MOVIE          SHOWING
                               ID(PK)         ID(PK)

                               TITLE          MOVIE_ID(FK)
                               RUNNING_TIME   SEQUENCE
                               FEE_AMOUNT     SHOWING_TIME
                               FEE_CURRENCY




               SELECT *
               FROM MOVIE as m LEFT JOIN SHOWING as s
               ON m.ID = s.MOVIE_ID


    34 / 객체지향적인 도메인 레이어 구축하기
객체 연관관계Association – 단방향UniDirectional

                                      MOVIE                      SHOWING
                                      ID(PK)                     ID(PK)

                                      TITLE                      MOVIE_ID(FK)
                                      RUNNING_TIME               SEQUENCE
                                      FEE_AMOUNT                 SHOWING_TIME
                                      FEE_CURRENCY




              Movie                            Showing
                                                                           showing.getMovie();
      calculateFee(showing)   1   *   reserve(customer, count)




              Movie                            Showing
                                                                           movie.getShowings();
      calculateFee(showing)   1   *   reserve(customer, count)




              Movie                            Showing                     movie.getShowings();
      calculateFee(showing)   1   *   reserve(customer, count)             showing.getMovie();

     35 / 객체지향적인 도메인 레이어 구축하기
객체 협력Collaboration을 통한 구현

   연관 관계는 책임 분배와 협력을 위한 핵심 메커니즘
  Showing
                                                           Showing
  상영 정보를 알고 있다           Movie
                                                      reserve()
  예매 정보를 생성한다
                                                                  *
       Movie
       영화 정보를 알고 있다              Discount
                                 Strategy
                                                                                  Movie
       가격을 계산한다                                                       1
                                                                          calculateFee()
                 DiscountStrategy                                                      1

               할인율 정책을 알고 있다            Rule
               할인된 가격을 계산한다
                                                                                                  DiscountStrategy
                                                                                           0..1
                                                                                                  calculateFee()




           public class Showing {
             private Movie movie;                     public class Movie {
                                                       private DiscountStrategy discountStrategy;
                 public Money calculateFee() {
                   return movie.calculateFee(this);       public Money calculateFee(Showing showing) {
                 }                                         return discountStrategy.calculateFee(showing);
                 ...                                      }
           }                                               ...
                                                      }

       36 / 객체지향적인 도메인 레이어 구축하기
Problem            Data + Process = 젃차적인Procedural 프로그래밍
                                          MOVIE                         SHOWING
                                           ID(PK)                       ID(PK)

                                           TITLE                        MOVIE_ID(FK)
                                           RUNNING_TIME                 SEQUENCE
                                           FEE_AMOUNT                   SHOWING_TIME
                                           FEE_CURRENCY

         Process
                                                    Movie                     Showing                  Data
                                             id                          id
   ReservationService                           Movie                            Showing
                                             title                       movieId
reserveShowing()                             runningTime                 title
                                             fee
                                      calculateFee(showing)
                                                              1     *    sequence
                                                                        reserve(customer, count)
                                             feeCurrency                 showingTime


                        public class ReservationService {
                          public Reservation reserveShowing(int customerId, int showingId, int audienceCount) {
                        public class Showing showingDAO.selectShowing(showingId);
                             Showing showing = {
                             Movie movie = movieDAO.selectMovie(showing.getMovieId());
                            private Movie movie;
                             long amount = calculateFee(movie.getFee(), showing, audienceCount);
                            public Money calculateFee() {
                             ...
                          } return movie.calculateFee(this);
                            }
                          private long calculateFee(long movieFee, Showing showing, int audientCount) {
                            ...
                        } ...
                          }
                        }


            37 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  38 / 객체지향적인 도메인 레이어 구축하기
Mismatch                캡슐화Encapsulation

                                                                                         Flat
          Hierarchical
                     Showing

              reserve(customer, count)



                       Movie

              calculateFee(showing):Money
                                     {abstract}
                               DiscountStrategy

                         calculateFee(showing):Money
                                                                {abstract}

                                                                 Rule


                                                       isStatisfiedBy(showing)


   Amount              Percent              NonDiscount
   Strategy            Strategy              Strategy
                                                  Sequence                   TimeOfDay
                                                    Rule                        Rule




        39 / 객체지향적인 도메인 레이어 구축하기
할인 규칙 등록
                                                                                           {abstract}                                {abstract}
          Showing                             Movie                                  DiscountStrategy                                 Rule
    reserve(customer, count)   1   *   calculateFee(showing)    1           0..1   calculateFee(showing)    1          0..*   calculateFee(showing)




                Movie                                          캡슐화 경계Boundary

                                             제          목           무지개여싞


                                             상영 시간                  116분                                요   금        8,000원



                                                                    AMOUNT
                                                                                                                                                  Discount
                                             할인 정책                  DISCOUNT                            할인 금액        9,000원




                                             할인 규칙                                                SEQUENCE RULE

                                                                                                                                                      Rule
                                             할인 대상                     1회                      1회               5회                 7회




  40 / 객체지향적인 도메인 레이어 구축하기
Problem     캡슐화 저해

               Flat                     불변식 위반Invariant Violation

                               Movie movie = movieDAO.selectMovie(1);
                               movie.setFee(8000);




                               DiscountStrategy strategy =
                                   new AmountDiscountStrategy(9000);
                               discountStrategyDAO.save(strategy);




                               DiscountRule rule = new SequenceRule(1);
                               discountRuleDAO.save(rule);




                               DiscountRule rule = new SequenceRule(1);
                               discountRuleDAO.save(rule);



    41 / 객체지향적인 도메인 레이어 구축하기
Conclusion     임피던스 불일치의 결과

 Anemic Domain Model & Fat Service Layer
        public class Movie {                     public class ReservationService {
         private Long id;                         public Money calculateFee(Movie movie,
         private String title;                                  DiscountStrategy strategy) {
                                                    if (strategy.isAmountType()) {
         public Long getId() {                         ...
           return id;                               } else if (strategy.isPercentType()) {
         }                                             ...
                                                    } else {
         public String getTitle() {                    ...
           return title;                            }
         }                                            ...
                                                  }


                public class ReservationService {
                 public Reservation reserveShowing(int customerId,
                         int showingId, int audienceCount) {
                  Showing showing = showingDAO.selectShowing(showingId);
                  Movie movie = movieDAO.selectMovie(showing.getMovieId());

                  long amount = calculateFee(movie.getFee(), showing, audienceCount);



      42 / 객체지향적인 도메인 레이어 구축하기
아키텍처 패턴
                             User Interface


                             Service



                             Domain



                             Infrastructure




    Transaction Script
  43 / 객체지향적인 도메인 레이어 구축하기
3. JPAJava Persistence API
DATA MAPPER

 객체 모델과 DB 스키마 간의 독립성 유지
 도메인 객체는 DB에 대해 독립적
 ORMObject-Relational Mapper

                                                               RULE
                                                               ID
                        Rule
                                                  RuleMapper   DISCOUNT_ID(FK)
                                                               POSITION
                                               insert          RULE_TYPE
                                               update          DAY_OF_WEEK
                                               delete          START_TIME
         SequenceRule          TimeOfDayRule
                                                               END_TUME
                                                               SEQUENCE




      45 / 객체지향적인 도메인 레이어 구축하기
JPAJava Persistence API

 Java ORM 표준 명세
 Annotation과 XML을 이용한 META DATA MAPPING 기능 제공
 Hibernate, EclipseLink

                                                             RULE
                                                             ID
                        Rule

                                                  JPA        DISCOUNT_ID(FK)
                                                             POSITION
                                               Hibernate     RULE_TYPE
                                                             DAY_OF_WEEK
                                               EclipseLink   START_TIME
         SequenceRule          TimeOfDayRule
                                                             END_TUME
                                                             SEQUENCE




      46 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  47 / 객체지향적인 도메인 레이어 구축하기
Mismatch    구성 요소 크기Granularity의 불일치

                                                                MOVIE
                                                                   ID(PK)

                                                                   TITLE
                                                                   RUNNING_TIME
           Movie                                                   FEE_AMOUNT
                                                                   FEE_CURRENCY

                           제목
                               하나와 앨리스

                                                                                       Value Object
                           시간
                           135분
                                         Entity                                                <<value object>>
                                                                                  running        Duration
                                                                                     Time
                           요금                                                               quantity
                                                      <<entity>>
                           8,000원
                                                        Movie
                                             title                                            <<value object>>

                                             calculateFee(showing):Money
                                                                                                   Money
                                                                                            amount
                                                                                            currency
                                                                                      fee




    48 / 객체지향적인 도메인 레이어 구축하기
Solution      @Embeddable
                                                                              Value Object

                              Entity                                                  <<value object>>   MOVIE
                                                                         running        Duration
                                                                            Time                         ID(PK)
                                                                                   quantity
                                           <<entity>>
                                             Movie                                                       TITLE
                                                                                                         RUNNING_TIME
                                  title                                              <<value object>>
                                                                                                         FEE_AMOUNT
                                  calculateFee(showing):Money
                                                                                          Money
                                                                                                         FEE_CURRENCY
                                                                                   amount
                                                                                   currency
                                                                             fee




                                                                @Embeddable
                                                                public class Duration {
                                                                  @Column(name="RUNNING_TIME", nullable=true)
                                                                  private long quantity;

           @Entity                                                 @Embeddable
           @Table(name="MOVIE")                                    public class Money {
           public class Movie {                                      @Column(name="FEE_AMOUNT", nullable=true)
             private Duration runningTime;                           private BigDecimal amount;
             private Money fee;
                                                                     @Column(name="FEE_CURRENCY", nullable=true)
                                                                     private Currency currency;



     49 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  50 / 객체지향적인 도메인 레이어 구축하기
Mismatch        식별자 불일치Identity Mismatch


      MOVIE

           ID                  TITLE   RUNNING_TIME   FEE_AMOUNT              FEE_CURRENCY

           1              시간을 달리는 소녀        95          8,000                      KRW

           2              시간을 달리는 소녀        95          8,000                      KRW




                 movie1 : Movie                                     movie2 : Movie

            title = ‚시간을 달리는 소녀‛                                title = ‚시간을 달리는 소녀‛
            runningTime = 95                                    runningTime = 95
            Fee = 8000                                         Fee = 8000




    51 / 객체지향적인 도메인 레이어 구축하기
Solution       영속 컨텍스트Persistence Context

                                                          Begin   Commit/
           User Interface                                  TX     Rollback

                                           UNIT OF WORK


           Service
                                IDENTITY
                                  MAP




           Domain




           Infrastructure




     52 / 객체지향적인 도메인 레이어 구축하기
영화 엔티티Entity 조회


    MOVIE

        ID                  TITLE   RUNNING_TIME   FEE_AMOUNT              FEE_CURRENCY

         1             시간을 달리는 소녀        95          8,000                      KRW

         2             시간을 달리는 소녀        95          8,000                      KRW




             movie1 : Movie                                      movie2 : Movie

         title = ‚시간을 달리는 소녀‛                                title = ‚시간을 달리는 소녀‛
         runningTime = 95                                    runningTime = 95
         Fee = 8000                                         Fee = 8000




   53 / 객체지향적인 도메인 레이어 구축하기
영속 컨텍스트Persistence Context

                                                                      Begin      Commit/
         User Interface                                                TX        Rollback

                                           UNIT OF WORK


         Service
                                IDENTITY
                                  MAP
                                                            movie1 : Movie
                                                          title = ‚시간을 달리는 소녀‛
                                ID   1                    runningTime = 95
                                                          Fee = 8000

         Domain
                                                            movie2 : Movie
                                ID   2                    title = ‚시간을 달리는 소녀‛
                                                          runningTime = 95
                                                          Fee = 8000




         Infrastructure




     54 / 객체지향적인 도메인 레이어 구축하기
첫 번째 영화 엔티티 다시 조회


    MOVIE

        ID                  TITLE   RUNNING_TIME   FEE_AMOUNT              FEE_CURRENCY

         1             시간을 달리는 소녀        95          8,000                      KRW

         2             시간을 달리는 소녀        95          8,000                      KRW




             movie1 : Movie                                      movie2 : Movie

         title = ‚시간을 달리는 소녀‛                                title = ‚시간을 달리는 소녀‛
         runningTime = 95                                    runningTime = 95
         Fee = 8000                                         Fee = 8000




   55 / 객체지향적인 도메인 레이어 구축하기
영속 컨텍스트Persistence Context

                                                                     Begin      Commit/
        User Interface                                                TX        Rollback

                                          UNIT OF WORK


        Service
                               IDENTITY
                                 MAP
                                                           movie1 : Movie
                                                         title = ‚시간을 달리는 소녀‛
                               ID   1                    runningTime = 95
                                                         Fee = 8000

        Domain
                                                           movie2 : Movie
                               ID   2                    title = ‚시간을 달리는 소녀‛
                                                         runningTime = 95
                                                         Fee = 8000




        Infrastructure




    56 / 객체지향적인 도메인 레이어 구축하기
식별자 일관성 보장

 데이터베이스 주키Primary Key와 객체 식별자Identity 간 일관성 유지
     MOVIE

         ID                  TITLE   RUNNING_TIME   FEE_AMOUNT              FEE_CURRENCY

          1             시간을 달리는 소녀        95          8,000                      KRW

          2             시간을 달리는 소녀        95          8,000                      KRW




              movie1 : Movie                                      movie2 : Movie

          title = ‚시간을 달리는 소녀‛                                title = ‚시간을 달리는 소녀‛
          runningTime = 95                                    runningTime = 95
          Fee = 8000                                         Fee = 8000




    57 / 객체지향적인 도메인 레이어 구축하기
식별자 일관성 보장


        movie1 = entityManager.load(Movie.class, 1);

        movie2 = entityManager.load(Movie.class, 1);

        assertSame(movie1, movie2);




  58 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  59 / 객체지향적인 도메인 레이어 구축하기
Mismatch    다형성Polymorphism

                                                                                {abstract}
                                                         Movie
                                                                            DiscountStrategy

                                                  calculateFee(showing)    registerDate              Movie                            DiscountStrategy
                                                                           calculateFee(showing)
                                                                                             id                                  movieId
                                                                                             title                               discountType
                                                                                             runningTime                         amount
                                                                                             fee                                 percent
           Movie               Discount                                                      feeCurrency                         registerDate

                                                        Amount                 Percent       calculateFee()         Non
                                                                                                                                 calculateFee()
                                                   DiscountStrategy       DiscountStrategy                    DiscountStrategy

                       Amount Discount    800원     discountAmount         percent




                       Percent Discount   10%
                                                           public class ReservationService {
                                                             public Money calculateFee(Movie movie,
                                                                     DiscountStrategy discountStrategy) {
                                                               if (discountStrategy.isAmountType()) {
                                                                   ...
                         No Discount      0원(%)
                                                               } else if (discountStrategy.isPercentType()) {
                                                                   ...
                                                               } else {
                                                                   ...
                                                               }
                                                               ...
                                                             }
                                                           }



    60 / 객체지향적인 도메인 레이어 구축하기
Solution        상속 매핑Inheritance Mapping
                                                           {abstract}
                                                    DiscountStrategy
                                                   registerDate

                                                   calculateFee(showing)




                                     Amount                                      Percent
                                 DiscountStrategy                           DiscountStrategy
                                discountAmount                             percent



            Single Table                Concrete Class                                                   Class Table
            Inheritance                  Inheritance                                                     Inheritance
           DISCOUNT                    AMOUNT_DISCOUNT                                             DISCOUNT
           MOVIE_ID(FK)                                                                               MOVIE_ID(FK)
                                        MOVIE_ID(FK)
           DISCOUNT_TYPE
                                        FEE_AMOUNT                                                    REGISTER_DATE
           FEE_AMOUNT
                                        FEE_CURRENCY
           FEE_CURRENCY
                                        REGISTER_DATE
           PERCENT
           REGISTER_DATE
                                      PERCENT_DISCOUNT                               AMOUNT_DISCOUN                   PERCENT_DISCOUN
                                                                                     T                                T
                                        MOVIE_ID(FK)                                   DISCOUNT_ID(FK)                 DISCOUNT_ID(FK)
                                        PERCENT                                        FEE_AMOUNT                      PERCENT
                                        REGISTER_DATE                                  FEE_CURRENCY



     61 / 객체지향적인 도메인 레이어 구축하기
Solution     다형성을 통한 조건 분기 제거


                                                                                     {abstract}
                                                          Movie              DiscountStrategy

           Movie                Discount           calculateFee(showing)    registerDate

                                                                            calculateFee(showing)


                        Amount Discount    800원



                                                        Amount                  Percent                   Non
                                                    DiscountStrategy       DiscountStrategy         DiscountStrategy
                        Percent Discount   10%
                                                    discountAmount         percent




                                                   public class Movie {
                          No Discount      0원(%)    private DiscountStrategy discountStrategy;

                                                    public Money calculateFee(Showing showing) {
                                                      return discountStrategy.calculateFee(showing);
                                                    }
                                                   }




     62 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  63 / 객체지향적인 도메인 레이어 구축하기
Mismatch         연관관계Association와 외래키Foreign Key

                                     MOVIE                      SHOWING
                                     ID(PK)                     ID(PK)

                                     TITLE                      MOVIE_ID(FK)
                                     RUNNING_TIME               SEQUENCE
                                     FEE_AMOUNT                 SHOWING_TIME
                                     FEE_CURRENCY




             Movie                            Showing
                                                                          showing.getMovie();
     calculateFee(showing)   1   *   reserve(customer, count)




             Movie                            Showing
                                                                          movie.getShowings();
     calculateFee(showing)   1   *   reserve(customer, count)




             Movie                            Showing                     movie.getShowings();
     calculateFee(showing)   1   *   reserve(customer, count)             showing.getMovie();

    64 / 객체지향적인 도메인 레이어 구축하기
Solution     외래키 맵핑Foreign Key Mapping

                                 MOVIE                          SHOWING
                                  ID(PK)                         ID(PK)

                                  TITLE                          MOVIE_ID(FK)
                                  RUNNING_TIME                   SEQUENCE
                                  FEE_AMOUNT                     SHOWING_TIME
                                  FEE_CURRENCY

                                                                Foreign Key
                            public class Showing {
                              @ManyToOne(optional=false)
                              @JoinColumn(name="MOVIE_ID")

                                private Movie movie;
                                public Money calculateFee() {
                                  return movie.calculateFee(this);
                                }
                            }


                                                                Association

                                        Movie                         Showing

                                calculateFee(showing)   1   *   reserve(customer, count)




     65 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치 유형


          구성 요소 크기Granularity의 불일치



          식별자Identity의 불일치



          다형성Polymorphism의 불일치



          연관 관계Association와 외래키Foreign Key의 불일치



          캡슐화 경계Encapsulation Boundary의 불일치


  66 / 객체지향적인 도메인 레이어 구축하기
Mismatch                               캡슐화Encapsulation

                                                                                    불변식 위반Invariant Violation

                                                                           Movie movie = movieDAO.selectMovie(1);
           Hierarchical                                             Flat   movie.setFee(8000);



                     Showing


           reserve(customer, count)
                                                                           DiscountStrategy strategy =
                                                                               new AmountDiscountStrategy(9000);
                      Movie
                                                                           discountStrategyDAO.save(strategy);

           calculateFee(showing):Money
                                 {abstract}
                             DiscountStrategy
                        calculateFee(showing):Mon
                        ey
                                                 {abstract}
                                                    Rule                   DiscountRule rule = new SequenceRule(1);
                                             isStatisfiedBy(sho
                                             wing)                         discountRuleDAO.save(rule);
Amount              Percent           NonDiscoun
                                           t
Strategy            Strategy
                                       Strategy            TimeOf
                                         Sequence            Day
                                             Rule
                                                            Rule


                                                                           DiscountRule rule = new SequenceRule(1);
                                                                           discountRuleDAO.save(rule);



                     67 / 객체지향적인 도메인 레이어 구축하기
Solution          페치 젂략Fetch Strategy

 지연 페치Lazy Fetch

           public class Movie {
             @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.LAZY)
             private DiscountStrategy discountStrategy;




           public class DiscountStrategy {
             @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
             @JoinColumn(name="DISCOUNTID")
             private Set<Rule> rules = new HashSet<Rule>();




                                                                                     {abstract}                        {abstract}
             Showing                             Movie                         DiscountStrategy                         Rule
                                                                                     Proxy                            Proxy
                                  1   *   calculateFee(showing)   1   0..1   calculateFee(showing)   1   0..*   calculateFee(showing)
       reserve(customer, count)




     68 / 객체지향적인 도메인 레이어 구축하기
Solution          페치 젂략Fetch Strategy

 선행 페치Eager Fetch

           public class Movie {
             @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.EAGER)
             private DiscountStrategy discountStrategy;




           public class DiscountStrategy {
             @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
             @JoinColumn(name="DISCOUNTID")
             private Set<Rule> rules = new HashSet<Rule>();




                                                                                     {abstract}                        {abstract}
             Showing                             Movie                         DiscountStrategy                         Rule
       reserve(customer, count)   1   *   calculateFee(showing)   1   0..1   calculateFee(showing)   1   0..*   calculateFee(showing)




     69 / 객체지향적인 도메인 레이어 구축하기
Solution     Aggregate = 캡슐화 경계Encapsulation Boundary

 예기치 못한 변경으로부터 보호
 객체 그룹의 불변성 보장


                          Showing
                 reserve(customer, count)



              Aggregate
                           Movie
                                                         {abstract}
                 calculateFee(showing):Money       DiscountStrategy

                                             calculateFee(showing):Money
                                                                                      {abstract}

                                                                                       Rule


                                                                             isStatisfiedBy(showing)



                         Amount             Percent             NonDiscount
                         Strategy           Strategy             Strategy
                                                                           Sequence                TimeOfDay
                                                                             Rule                     Rule




                                               Eager Fetch
                                                Lazy Fetch
     70 / 객체지향적인 도메인 레이어 구축하기
4. 결롞
DOMAIN MODEL PATTERN

 도메인을 구성하는 개념들을 따르는 도메인 레이어
 적젃한 책임의 분배와 협력을 통한 객체 지향적인 도메인 레이어




   72 / 객체지향적인 도메인 레이어 구축하기
임피던스 불일치

 맹목적으로 테이블의 구조를 따르는 객체 구조
 젃차적인 TRANSACTION SCRIPT로 향하는 한 가지 이유




    73 / 객체지향적인 도메인 레이어 구축하기
JPAJavaPersistece API

 임피던스 불일치를 해결할 수 있는 실용적인 솔루션
 풍부한 도메인 레이어Rich Domain Layer의 기반




      74 / 객체지향적인 도메인 레이어 구축하기
Domain Model에 초점을 맞춰라

              Showing                                            Reservation

                                                                       Reservation
                 Showing
                                         1   <<create>>
                                                          0..*
  reserve(customer, count):Reservation

                                                                        Customer
                         0..*

                                                                        {abstract}                           {abstract}
                   Movie                                          DiscountStrategy                            Rule
                         1
  calculateFee(showing):Money                               calculateFee(showing):Money        isStatisfiedBy(showing):boolean




                                         1                0..1                            1   1..*
       Amount                                Percent                      NonDiscount         Sequence                    TimeOfDay
       Strategy                              Strategy                      Strategy             Rule                         Rule


                Movie                                               Discount                                     Rule


      75 / 객체지향적인 도메인 레이어 구축하기
Data Model이 더 중요




   76 / 객체지향적인 도메인 레이어 구축하기
타협하라




                    Be Pragmatic
  데이터베이스가 하나의 객체 저장소로 보여진다면 매핑 도구의 기능과는 상관없이 데이터
  모델과 객체 모델이 서로 갈라지게 해서는 안 된다. 일부 객체 관계의 풍부함을 희생해서

  관계 모델에 밀접하게 한다. 객체 매핑을 단순화하는데 도움이 된다면 정규화와 같은 정형
  화된 관계 표준을 젃충한다.

                                            - Eric Evans

  77 / 객체지향적인 도메인 레이어 구축하기
Thank you.




78 / 객체지향적인 도메인 레이어 구축하기
Question?




79 / 객체지향적인 도메인 레이어 구축하기
참고자료

- Christian Bauer, Gavin King, Java Persistence with Hibernate, Manning, 2006.

- Michael Keith, Merrick Schincario, Pro JPA2 : Mastering the Java(TM) Persistence API, Apress, 2009.

- Chris Richardson, POJOs in Action : Developing Enterprise Applications with Lightweight Frameworks, Manning,
  2006.

- Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, 2002.


- Eric Evans, Domain-Driven Design, Addison-Wesley, 2003.

- Kent Beck and Ward Cunningham, ‚A Laboratory for Teaching Object Oriented Thinking,‛ OOPSLA ‘89 Conference
  Proceedings, SIGPLAN Notices, 24(10), pp. 1-6, New Orleans, Louisiana, October 1989.

- Rebecca Wirfs-Brock and Brian Wilkerson, ‚Object-Oriented Design: A Responsibility-Driven Approach,‛ OOPSLA ‘89
  Conference Proceedings, SIGPLAN Notices, 24(10), pp.71-76, New Orleans, Louisiana, October, 1989.

- Rebecca Wirfs-Brock, Alan McKean, Object Design : Roles, Responsibilities, and Collaborations ,
  Addison- Wesley, 2002.

       80 / 객체지향적인 도메인 레이어 구축하기
Appendix A.

  CRC Card
예매 생성 책임

 예매 생성에 필요한 정보의 EXPERT에게 할당Creator



 Showing
 상영 정보를 알고 있다
 예매 정보를 생성한다




    82 / 객체지향적인 도메인 레이어 구축하기
가격 계산 책임

 영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert

                                      Movie
 Showing                              영화 정보를 알고 있다
                                      가격을 계산한다
 상영 정보를 알고 있다          Movie
 예매 정보를 생성한다




    83 / 객체지향적인 도메인 레이어 구축하기
할인율 계산 책임

 할인율을 적용할 STRATEGY 객체 추가

                               Movie
 Showing                       영화 정보를 알고 있다     Discount
                                                Strategy
                               가격을 계산한다
 상영 정보를 알고 있다          Movie
 예매 정보를 생성한다                        DiscountStrategy
                                    할인율 정책을 알고 있다
                                    할인된 가격을 계산한다




    84 / 객체지향적인 도메인 레이어 구축하기
할인 여부를 판단할 책임

 할인 정책을 판단하기 위한 SPECIFICATION 객체 추가

                               Movie
 Showing                       영화 정보를 알고 있다        Discount
                                                   Strategy
                               가격을 계산한다
 상영 정보를 알고 있다          Movie
 예매 정보를 생성한다                           DiscountStrategy
                                       할인율 정책을 알고 있다      Rule
                                       할인된 가격을 계산한다
                                           Rule
                                           할인 정책을 알고 있다          Showing
                                           할인 여부를 판단한다



    85 / 객체지향적인 도메인 레이어 구축하기
Appendix B.

  Domain Model Pattern Implementation
Domain Layer Collaboration


public class Showing {
  public Reservation reserve(Customer customer, int audienceCount) {
    return new Reservation(customer, this, audienceCount);
  }
}
    public class Reservation {
      public Reservation(Customer customer, Showing showing, int audienceCount) {
        this.customer = customer;
        this.showing = showing;
        this.fee = showing.calculateFee().times(audienceCount);
        this.audienceCount = audienceCount;
      }
    }   public class Showing {
            public Money calculateFee() {
              return movie.calculateFee(this);
            }
        }
               public class Movie {
                 public Money calculateFee(Showing showing) {
                   return discountStrategy.calculateFee(showing);
                 }
               }




       87 / 객체지향적인 도메인 레이어 구축하기
Domain Layer Collaboration

public abstract class DiscountStrategy {
  public Money calculateFee(Showing showing) {
    for(Rule each : rules) {
      if (each.isStatisfiedBy(showing)) {
        return getDiscountedFee(showing);
      }
    }

      return showing.getFixedFee();
  }

  abstract protected Money getDiscountedFee(Showing showing);

      public abstract class Rule {
        abstract public boolean isStatisfiedBy(Showing showing);
      }
            public class SequenceRule extends Rule {
              public boolean isStatisfiedBy(Showing showing) {
                return showing.isSequence(sequence);
              }
            }
                public class TimeOfDayRule extends Rule {
                  public boolean isStatisfiedBy(Showing showing) {
                    return showing.isPlayingOn(dayOfWeek) &&
                      Interval.closed(startTime, endTime)
                          .includes(showing.getPlayngInterval());
                  }
                }

         88 / 객체지향적인 도메인 레이어 구축하기
Domain Layer Collaboration

public abstract class DiscountStrategy {
  public Money calculateFee(Showing showing) {
    for(Rule each : rules) {
      if (each.isStatisfiedBy(showing)) {
        return getDiscountedFee(showing);
      }
    }

      return showing.getFixedFee();
  }

  abstract protected Money getDiscountedFee(Showing showing);
      public class AmountDiscountStrategy extends DiscountStrategy {
        protected Money getDiscountedFee(Showing showing) {
          return showing.getFixedFee().minus(discountAmount);
        }
      }
            public class NonDiscountStrategy extends DiscountStrategy {
              protected Money getDiscountedFee(Showing showing) {
                return showing.getFixedFee();
              }
            }
                public class PercentDiscountStrategy extends DiscountStrategy {
                  protected Money getDiscountedFee(Showing showing) {
                    return showing.getFixedFee().minus(showing.getFixedFee().times(percent));
                  }
                }


         89 / 객체지향적인 도메인 레이어 구축하기
Domain Layer Collaboration


               :Showing               :Reservation                    :Movie                    :DiscountStrategy                  :Rule


   reserve()

                             new



                          calculateFee()

                                                     calculateFee()
                                                                               calculateFee()
                                                                                                              *
                                                                                                                  isStatisfied()




      90 / 객체지향적인 도메인 레이어 구축하기
Data Model

     RESERVATION               CUSTOMER
      ID                        ID

      CUSTOMER_ID(FK)           CUSTOMER_ID
      SHOWING_ID(FK)            NAME
      FEE_AMOUNT
      FEE_CURRENCY
      AUDIENCE_COUNT




                                                              RULE
     SHOWING                   MOVIE          DISCOUNT
                                                              ID
      ID                       ID             MOVIE_ID(FK)
                                                              DISCOUNT_ID(FK)
      MOVIE_ID(FK)             TITLE          DISCOUNT_TYPE   POSITION
      SEQUENCE                 RUNNING_TIME   FEE_AMOUNT      RULE_TYPE
      SHOWING_TIME             FEE_AMOUNT     FEE_CURRENCY    DAY_OF_WEEK
                               FEE_CURRENCY   PERCENT         START_TIME
                                              REGISTER_DATE   END_TUME
                                                              SEQUENCE



    91 / 객체지향적인 도메인 레이어 구축하기
Appendix C.

  Impedance Mismatch Summary
임피던스 불일치Impedance Mismatch
                                                              MOVIE
                                    running
                                                  Duration
                                       Time                    ID(PK)
                                                quantity
           Movie                                               TITLE
                                                               RUNNING_TIME
   title
                                                   Money       FEE_AMOUNT
                                                               FEE_CURRENCY
                                                amount
                                          fee   currency




           Movie                                  Showing     MOVIE                             SHOWING
                    1       *                                  ID(PK)                            ID(PK)


           Movie                                  Showing      TITLE                             MOVIE_ID(FK)
                                                                                                 SEQUENCE
                    1       *                                  RUNNING_TIME
                                                               FEE_AMOUNT                        SHOWING_TIME
                                                               FEE_CURRENCY

           Movie                                  Showing
                    1       *
                                                                               AMOUNT_
                             {abstract}                                        DISCOUNT                     DISCOUNT
                        DiscountStrategy                                        MOVIE_ID(FK)                  MOVIE_ID(FK)

                    registerDate                              DISCOUNT                                        REGISTER_DATE
                                                                                FEE_AMOUNT
                                                               MOVIE_ID(FK)     FEE_CURRENCY
                                                                                REGISTER_DATE
                                                               DISCOUNT_TYPE
     Amount                Percent                   Non       FEE_AMOUNT
                                                                               PERCENT_            AMOUNT_                   PERCENT_
                                                               FEE_CURRENCY
     Discount              Discount                Discount    PERCENT         DISCOUNT            DISCOUNT                  DISCOUNT
     Strategy              Strategy                Strategy    REGISTER_DATE
                                                                                MOVIE_ID(FK)        DISCOUNT_ID(FK)           DISCOUNT_ID(FK)
   discountAmount         percent
                                                                                PERCENT             FEE_AMOUNT                PERCENT
                                                                                REGISTER_DATE       FEE_CURRENCY


       93 / 객체지향적인 도메인 레이어 구축하기

Weitere ähnliche Inhalte

Mehr von NAVER D2

Mehr von NAVER D2 (20)

[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기[244]로봇이 현실 세계에 대해 학습하도록 만들기
[244]로봇이 현실 세계에 대해 학습하도록 만들기
 
[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning[243] Deep Learning to help student’s Deep Learning
[243] Deep Learning to help student’s Deep Learning
 
[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications[234]Fast & Accurate Data Annotation Pipeline for AI applications
[234]Fast & Accurate Data Annotation Pipeline for AI applications
 
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load BalancingOld version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
Old version: [233]대형 컨테이너 클러스터에서의 고가용성 Network Load Balancing
 
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
[226]NAVER 광고 deep click prediction: 모델링부터 서빙까지
 
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
[225]NSML: 머신러닝 플랫폼 서비스하기 & 모델 튜닝 자동화하기
 
[224]네이버 검색과 개인화
[224]네이버 검색과 개인화[224]네이버 검색과 개인화
[224]네이버 검색과 개인화
 
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
[216]Search Reliability Engineering (부제: 지진에도 흔들리지 않는 네이버 검색시스템)
 
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
[214] Ai Serving Platform: 하루 수 억 건의 인퍼런스를 처리하기 위한 고군분투기
 
[213] Fashion Visual Search
[213] Fashion Visual Search[213] Fashion Visual Search
[213] Fashion Visual Search
 
[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화[232] TensorRT를 활용한 딥러닝 Inference 최적화
[232] TensorRT를 활용한 딥러닝 Inference 최적화
 
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
[242]컴퓨터 비전을 이용한 실내 지도 자동 업데이트 방법: 딥러닝을 통한 POI 변화 탐지
 
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
[212]C3, 데이터 처리에서 서빙까지 가능한 하둡 클러스터
 
[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?[223]기계독해 QA: 검색인가, NLP인가?
[223]기계독해 QA: 검색인가, NLP인가?
 
[231] Clova 화자인식
[231] Clova 화자인식[231] Clova 화자인식
[231] Clova 화자인식
 
[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화[232]TensorRT를 활용한 딥러닝 Inference 최적화
[232]TensorRT를 활용한 딥러닝 Inference 최적화
 
[222]누구나 만드는 내 목소리 합성기 (부제: 그게 정말 되나요?)
[222]누구나 만드는 내 목소리 합성기 (부제: 그게 정말 되나요?)[222]누구나 만드는 내 목소리 합성기 (부제: 그게 정말 되나요?)
[222]누구나 만드는 내 목소리 합성기 (부제: 그게 정말 되나요?)
 
Old Version: [211] 인공지능이 인공지능 챗봇을 만든다
Old Version: [211] 인공지능이 인공지능 챗봇을 만든다Old Version: [211] 인공지능이 인공지능 챗봇을 만든다
Old Version: [211] 인공지능이 인공지능 챗봇을 만든다
 
[241] AI 칩 개발에 사용되는 엔지니어링
[241] AI 칩 개발에 사용되는 엔지니어링[241] AI 칩 개발에 사용되는 엔지니어링
[241] AI 칩 개발에 사용되는 엔지니어링
 
[246]QANet: Towards Efficient and Human-Level Reading Comprehension on SQuAD
[246]QANet: Towards Efficient and Human-Level Reading Comprehension on SQuAD[246]QANet: Towards Efficient and Human-Level Reading Comprehension on SQuAD
[246]QANet: Towards Efficient and Human-Level Reading Comprehension on SQuAD
 

A6 객체지향적인 도메인 레이어 구축하기

  • 1. DOMAIN MODEL 패턴과 JPA의 조화 객체지향적인 도메인 레이어 구축하기 조영호 NHN 커머스개발센터 Eternity’s Chit-Chat(http://aeternum.egloos.com)
  • 2. 목차 1. 온라인 영화 예매 시스템 도메인 2. 임피던스 불일치Impedance Mismatch 3. JPAJava Persistence API 4. 결롞
  • 3. 1. 온라인 영화 예매 시스템 도메인
  • 4. Domain Concept - 영화 Movie 4 / 객체지향적인 도메인 레이어 구축하기
  • 5. Domain Concept - 상영 2011-10-18 09:30 조조 Showing 2011-10-21 20:30 5회 2011-12-01 14:20 4회 5 / 객체지향적인 도메인 레이어 구축하기
  • 6. Domain Concept – 할인 정책 Discount Amount Discount 8,000 - 800 = 7,200 Percent Discount 8,000 – (8,000 * 0.1) = 7,200 6 / 객체지향적인 도메인 레이어 구축하기
  • 7. Domain Concept – 할인 규칙 Sequence Rule Rule 조조 상영인 경우 10회 상영인 경우 Time Rule 월요일 10:00 ~ 12:00 상영인 경우 화요일 18:00 ~ 21:00 상영인 경우 7 / 객체지향적인 도메인 레이어 구축하기
  • 8. Domain Concept –할인 정책 + 할인 규칙 조조 상영인 경우 10회 상영인 경우 도가니 Amount DC 8000원 800원 월요일 10:00 ~ 12:00 상영인 경우 화요일 18:00 ~ 21:00 상영인 경우 Movie Discount Rule 1 0..1 1 1..* 8 / 객체지향적인 도메인 레이어 구축하기
  • 9. Domain Concept –예매 Reservation 제 목 도가니 2011년 10월 18일 (목) 상영 정보 7회 6:00(오후) – 8:00(오후) 인 원 2명 정 가 16,000원 결재 금액 14,400원 9 / 객체지향적인 도메인 레이어 구축하기
  • 10. Domain Model Showing Reservation 1 0..* 0..* 1 1 0..1 1 1..* Movie Discount Rule 10 / 객체지향적인 도메인 레이어 구축하기
  • 11. 영화 예매 책임 수행을 위한 협력의 설계  후보 객체Candidate, 책임Responsibility, 협력Collaboration 식별 Movie Showing 영화 정보를 알고 있다 Discount Strategy 가격을 계산한다 상영 정보를 알고 있다 Movie 예매 정보를 생성한다 DiscountStrategy 할인율 정책을 알고 있다 Rule 할인된 가격을 계산한다 Rule 할인 정책을 알고 있다 Showing 할인 여부를 판단한다 11 / 객체지향적인 도메인 레이어 구축하기
  • 12. 도메인 레이어 객체 구현 User Interface Service Reservation Domain Showing <<create>> Infrastructure reserve(customer, count):Reservation Customer {abstract} {abstract} Movie DiscountStrategy Rule calculateFee(showing):Money calculateFee(showing):Money isStatisfiedBy(showing):boolean Amount Percent NonDiscount Sequence TimeOfDay Strategy Strategy Strategy Rule Rule 12 / 객체지향적인 도메인 레이어 구축하기
  • 13. Domain Model Showing Reservation 1 0..* 0..* 1 1 0..1 1 1..* Movie Discount Rule 13 / 객체지향적인 도메인 레이어 구축하기
  • 14. Domain Layer Design & Domain Model Showing Reservation Reservation Showing 1 <<create>> 0..* reserve(customer, count):Reservation Customer 0..* {abstract} {abstract} Movie DiscountStrategy Rule 1 calculateFee(showing):Money calculateFee(showing):Money isStatisfiedBy(showing):boolean 1 0..1 1 1..* Amount Percent NonDiscount Sequence TimeOfDay Strategy Strategy Strategy Rule Rule Movie Discount Rule 14 / 객체지향적인 도메인 레이어 구축하기
  • 15. 아키텍처 패턴 User Interface Service Domain Infrastructure Domain Model 15 / 객체지향적인 도메인 레이어 구축하기
  • 17. 임피던스 불일치Impedance Mismatch 17 / 객체지향적인 도메인 레이어 구축하기
  • 18. 객체-관계 임피던스 불일치  객체 모델과 DB 스키마 간의 불일치  객체 패러다임Object Paradigm과 관계 패러다임Relational Paradigm 간의 불일치 RULE DISCOUNT DiscountStrategy Rule ID MOVIE_ID(FK) DISCOUNT_ID(FK) DISCOUNT_TYPE POSITION FEE_AMOUNT RULE_TYPE FEE_CURRENCY DAY_OF_WEEK Amount Percent NonDiscount Sequence TimeOfDay PERCENT START_TIME Strategy Strategy Strategy Rule Rule END_TUME SEQUENCE 18 / 객체지향적인 도메인 레이어 구축하기
  • 19. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 19 / 객체지향적인 도메인 레이어 구축하기
  • 20. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 20 / 객체지향적인 도메인 레이어 구축하기
  • 21. Mismatch 구성 요소 크기Granularity의 불일치 MOVIE ID(PK) TITLE RUNNING_TIME Movie FEE_AMOUNT FEE_CURRENCY 제목 하나와 앨리스 시간 135분 <<value object>> running Duration Time 요금 quantity <<entity>> 8,000원 Movie title <<value object>> calculateFee(showing):Money Money amount currency fee 21 / 객체지향적인 도메인 레이어 구축하기
  • 22. Entity & Value Object Identity Value Value Object Entity <<value object>> running Duration Time quantity <<entity>> Movie title <<value object>> calculateFee(showing):Money Money amount currency fee 22 / 객체지향적인 도메인 레이어 구축하기
  • 23. 책임의 재사용 Money 금액과 환율을 알고 있다 Movie 금액을 +,-,*,/한다 영화 정보를 알고 있다 가격을 계산한다 Duration 기간을 알고 있다. 기간의 합, 차를 계산한다 23 / 객체지향적인 도메인 레이어 구축하기
  • 24. Problem 코드 중복Code Duplication RESERVATION MOVIE ID(PK) ID(PK) CUSTOMER_ID(FK) TITLE SHOWING_ID(FK) RUNNING_TIME FEE_AMOUNT FEE_AMOUNT FEE_CURRENCY FEE_CURRENCY AUDIENCE_COUNT class Movie { long plus(long fee, Currency currency) { if (this.feeCurrency.equals(currency) { return this.fee + fee; } Movie throw new IllegalArgumentException(); Reservation } id } id title customerId runningTime showingId fee class Reservation { amount long add(long amount, Currency currency) { feeCurrency acmointCurrency if (this.amountCurrency.equals(currency) { return this.amount + fee; audienceCount calculateFee() } getFee() throw new IllegalArgumentException(); } } 24 / 객체지향적인 도메인 레이어 구축하기
  • 25. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 25 / 객체지향적인 도메인 레이어 구축하기
  • 26. Mismatch 데이터베이스 식별자Database Identity  테이블 주키Primary Key 제목 제목 시간을 시간을 달리는 소녀 달리는 소녀 시간 시간 95분 95분 요금 요금 8,000원 8,000원 MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW 26 / 객체지향적인 도메인 레이어 구축하기
  • 27. 객체 식별자Object Identity  Java == 연산자 제목 제목 시간을 시간을 달리는 소녀 달리는 소녀 시간 시간 95분 95분 요금 요금 8,000원 8,000원 address 1 address 2 movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 27 / 객체지향적인 도메인 레이어 구축하기
  • 28. Problem 데이터베이스-객체 식별자 불일치Identity Mismatch MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 28 / 객체지향적인 도메인 레이어 구축하기
  • 29. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 29 / 객체지향적인 도메인 레이어 구축하기
  • 30. Mismatch 다형성Polymorphism {abstract} Movie DiscountStrategy Movie Discount calculateFee(showing) registerDate calculateFee(showing) Amount Discount 800원 Amount Percent Non DiscountStrategy DiscountStrategy DiscountStrategy Percent Discount 10% discountAmount percent public class Movie { No Discount 0원(%) private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } } 30 / 객체지향적인 도메인 레이어 구축하기
  • 31. Problem 젃차적인 조건 분기Conditional Branch {abstract} Movie Movie DiscountStrategy DiscountStrategy id movieId Movie Discount calculateFee(showing) title registerDate discountType runningTime calculateFee(showing) amount fee percent Amount Discount 800원 feeCurrency registerDate calculateFee() calculateFee() Amount Percent Non DiscountStrategy DiscountStrategy DiscountStrategy Percent Discount 10% discountAmount percent public class ReservationService { public class Movie { public Money calculateFee(Movie movie, No Discount 0원(%) private DiscountStrategy discountStrategy) { DiscountStrategy discountStrategy; if (discountStrategy.isAmountType()) { ... public Money calculateFee(Showing showing) { } else if (discountStrategy.isPercentType()) { return discountStrategy.calculateFee(showing); } ... } else { } ... } ... } } 31 / 객체지향적인 도메인 레이어 구축하기
  • 32. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 32 / 객체지향적인 도메인 레이어 구축하기
  • 33. Mismatch 데이터베이스 외래키Foreign Key MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE Movie Showing FEE_AMOUNT SHOWING_TIME FEE_CURRENCY 1회 10/18 10:00 2회 10/18 12:30 MOVIE 3회 ID TITLE 10/18 15:00 1 하나와 앨리스 4회 10/18 17:30 SHOWING ID MOVIE_ID SEQUENCE SHOWING_TIME 1 1 7 2010-12-23 18:00 33 / 객체지향적인 도메인 레이어 구축하기
  • 34. 테이블 외래키Foreign Key - 양방향BiDirectional MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE FEE_AMOUNT SHOWING_TIME FEE_CURRENCY SELECT * FROM MOVIE as m LEFT JOIN SHOWING as s ON m.ID = s.MOVIE_ID 34 / 객체지향적인 도메인 레이어 구축하기
  • 35. 객체 연관관계Association – 단방향UniDirectional MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE FEE_AMOUNT SHOWING_TIME FEE_CURRENCY Movie Showing showing.getMovie(); calculateFee(showing) 1 * reserve(customer, count) Movie Showing movie.getShowings(); calculateFee(showing) 1 * reserve(customer, count) Movie Showing movie.getShowings(); calculateFee(showing) 1 * reserve(customer, count) showing.getMovie(); 35 / 객체지향적인 도메인 레이어 구축하기
  • 36. 객체 협력Collaboration을 통한 구현  연관 관계는 책임 분배와 협력을 위한 핵심 메커니즘 Showing Showing 상영 정보를 알고 있다 Movie reserve() 예매 정보를 생성한다 * Movie 영화 정보를 알고 있다 Discount Strategy Movie 가격을 계산한다 1 calculateFee() DiscountStrategy 1 할인율 정책을 알고 있다 Rule 할인된 가격을 계산한다 DiscountStrategy 0..1 calculateFee() public class Showing { private Movie movie; public class Movie { private DiscountStrategy discountStrategy; public Money calculateFee() { return movie.calculateFee(this); public Money calculateFee(Showing showing) { } return discountStrategy.calculateFee(showing); ... } } ... } 36 / 객체지향적인 도메인 레이어 구축하기
  • 37. Problem Data + Process = 젃차적인Procedural 프로그래밍 MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE FEE_AMOUNT SHOWING_TIME FEE_CURRENCY Process Movie Showing Data id id ReservationService Movie Showing title movieId reserveShowing() runningTime title fee calculateFee(showing) 1 * sequence reserve(customer, count) feeCurrency showingTime public class ReservationService { public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { public class Showing showingDAO.selectShowing(showingId); Showing showing = { Movie movie = movieDAO.selectMovie(showing.getMovieId()); private Movie movie; long amount = calculateFee(movie.getFee(), showing, audienceCount); public Money calculateFee() { ... } return movie.calculateFee(this); } private long calculateFee(long movieFee, Showing showing, int audientCount) { ... } ... } } 37 / 객체지향적인 도메인 레이어 구축하기
  • 38. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 38 / 객체지향적인 도메인 레이어 구축하기
  • 39. Mismatch 캡슐화Encapsulation Flat Hierarchical Showing reserve(customer, count) Movie calculateFee(showing):Money {abstract} DiscountStrategy calculateFee(showing):Money {abstract} Rule isStatisfiedBy(showing) Amount Percent NonDiscount Strategy Strategy Strategy Sequence TimeOfDay Rule Rule 39 / 객체지향적인 도메인 레이어 구축하기
  • 40. 할인 규칙 등록 {abstract} {abstract} Showing Movie DiscountStrategy Rule reserve(customer, count) 1 * calculateFee(showing) 1 0..1 calculateFee(showing) 1 0..* calculateFee(showing) Movie 캡슐화 경계Boundary 제 목 무지개여싞 상영 시간 116분 요 금 8,000원 AMOUNT Discount 할인 정책 DISCOUNT 할인 금액 9,000원 할인 규칙 SEQUENCE RULE Rule 할인 대상 1회 1회 5회 7회 40 / 객체지향적인 도메인 레이어 구축하기
  • 41. Problem 캡슐화 저해 Flat 불변식 위반Invariant Violation Movie movie = movieDAO.selectMovie(1); movie.setFee(8000); DiscountStrategy strategy = new AmountDiscountStrategy(9000); discountStrategyDAO.save(strategy); DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); 41 / 객체지향적인 도메인 레이어 구축하기
  • 42. Conclusion 임피던스 불일치의 결과  Anemic Domain Model & Fat Service Layer public class Movie { public class ReservationService { private Long id; public Money calculateFee(Movie movie, private String title; DiscountStrategy strategy) { if (strategy.isAmountType()) { public Long getId() { ... return id; } else if (strategy.isPercentType()) { } ... } else { public String getTitle() { ... return title; } } ... } public class ReservationService { public Reservation reserveShowing(int customerId, int showingId, int audienceCount) { Showing showing = showingDAO.selectShowing(showingId); Movie movie = movieDAO.selectMovie(showing.getMovieId()); long amount = calculateFee(movie.getFee(), showing, audienceCount); 42 / 객체지향적인 도메인 레이어 구축하기
  • 43. 아키텍처 패턴 User Interface Service Domain Infrastructure Transaction Script 43 / 객체지향적인 도메인 레이어 구축하기
  • 45. DATA MAPPER  객체 모델과 DB 스키마 간의 독립성 유지  도메인 객체는 DB에 대해 독립적  ORMObject-Relational Mapper RULE ID Rule RuleMapper DISCOUNT_ID(FK) POSITION insert RULE_TYPE update DAY_OF_WEEK delete START_TIME SequenceRule TimeOfDayRule END_TUME SEQUENCE 45 / 객체지향적인 도메인 레이어 구축하기
  • 46. JPAJava Persistence API  Java ORM 표준 명세  Annotation과 XML을 이용한 META DATA MAPPING 기능 제공  Hibernate, EclipseLink RULE ID Rule JPA DISCOUNT_ID(FK) POSITION Hibernate RULE_TYPE DAY_OF_WEEK EclipseLink START_TIME SequenceRule TimeOfDayRule END_TUME SEQUENCE 46 / 객체지향적인 도메인 레이어 구축하기
  • 47. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 47 / 객체지향적인 도메인 레이어 구축하기
  • 48. Mismatch 구성 요소 크기Granularity의 불일치 MOVIE ID(PK) TITLE RUNNING_TIME Movie FEE_AMOUNT FEE_CURRENCY 제목 하나와 앨리스 Value Object 시간 135분 Entity <<value object>> running Duration Time 요금 quantity <<entity>> 8,000원 Movie title <<value object>> calculateFee(showing):Money Money amount currency fee 48 / 객체지향적인 도메인 레이어 구축하기
  • 49. Solution @Embeddable Value Object Entity <<value object>> MOVIE running Duration Time ID(PK) quantity <<entity>> Movie TITLE RUNNING_TIME title <<value object>> FEE_AMOUNT calculateFee(showing):Money Money FEE_CURRENCY amount currency fee @Embeddable public class Duration { @Column(name="RUNNING_TIME", nullable=true) private long quantity; @Entity @Embeddable @Table(name="MOVIE") public class Money { public class Movie { @Column(name="FEE_AMOUNT", nullable=true) private Duration runningTime; private BigDecimal amount; private Money fee; @Column(name="FEE_CURRENCY", nullable=true) private Currency currency; 49 / 객체지향적인 도메인 레이어 구축하기
  • 50. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 50 / 객체지향적인 도메인 레이어 구축하기
  • 51. Mismatch 식별자 불일치Identity Mismatch MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 51 / 객체지향적인 도메인 레이어 구축하기
  • 52. Solution 영속 컨텍스트Persistence Context Begin Commit/ User Interface TX Rollback UNIT OF WORK Service IDENTITY MAP Domain Infrastructure 52 / 객체지향적인 도메인 레이어 구축하기
  • 53. 영화 엔티티Entity 조회 MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 53 / 객체지향적인 도메인 레이어 구축하기
  • 54. 영속 컨텍스트Persistence Context Begin Commit/ User Interface TX Rollback UNIT OF WORK Service IDENTITY MAP movie1 : Movie title = ‚시간을 달리는 소녀‛ ID 1 runningTime = 95 Fee = 8000 Domain movie2 : Movie ID 2 title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 Infrastructure 54 / 객체지향적인 도메인 레이어 구축하기
  • 55. 첫 번째 영화 엔티티 다시 조회 MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 55 / 객체지향적인 도메인 레이어 구축하기
  • 56. 영속 컨텍스트Persistence Context Begin Commit/ User Interface TX Rollback UNIT OF WORK Service IDENTITY MAP movie1 : Movie title = ‚시간을 달리는 소녀‛ ID 1 runningTime = 95 Fee = 8000 Domain movie2 : Movie ID 2 title = ‚시간을 달리는 소녀‛ runningTime = 95 Fee = 8000 Infrastructure 56 / 객체지향적인 도메인 레이어 구축하기
  • 57. 식별자 일관성 보장  데이터베이스 주키Primary Key와 객체 식별자Identity 간 일관성 유지 MOVIE ID TITLE RUNNING_TIME FEE_AMOUNT FEE_CURRENCY 1 시간을 달리는 소녀 95 8,000 KRW 2 시간을 달리는 소녀 95 8,000 KRW movie1 : Movie movie2 : Movie title = ‚시간을 달리는 소녀‛ title = ‚시간을 달리는 소녀‛ runningTime = 95 runningTime = 95 Fee = 8000 Fee = 8000 57 / 객체지향적인 도메인 레이어 구축하기
  • 58. 식별자 일관성 보장 movie1 = entityManager.load(Movie.class, 1); movie2 = entityManager.load(Movie.class, 1); assertSame(movie1, movie2); 58 / 객체지향적인 도메인 레이어 구축하기
  • 59. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 59 / 객체지향적인 도메인 레이어 구축하기
  • 60. Mismatch 다형성Polymorphism {abstract} Movie DiscountStrategy calculateFee(showing) registerDate Movie DiscountStrategy calculateFee(showing) id movieId title discountType runningTime amount fee percent Movie Discount feeCurrency registerDate Amount Percent calculateFee() Non calculateFee() DiscountStrategy DiscountStrategy DiscountStrategy Amount Discount 800원 discountAmount percent Percent Discount 10% public class ReservationService { public Money calculateFee(Movie movie, DiscountStrategy discountStrategy) { if (discountStrategy.isAmountType()) { ... No Discount 0원(%) } else if (discountStrategy.isPercentType()) { ... } else { ... } ... } } 60 / 객체지향적인 도메인 레이어 구축하기
  • 61. Solution 상속 매핑Inheritance Mapping {abstract} DiscountStrategy registerDate calculateFee(showing) Amount Percent DiscountStrategy DiscountStrategy discountAmount percent Single Table Concrete Class Class Table Inheritance Inheritance Inheritance DISCOUNT AMOUNT_DISCOUNT DISCOUNT MOVIE_ID(FK) MOVIE_ID(FK) MOVIE_ID(FK) DISCOUNT_TYPE FEE_AMOUNT REGISTER_DATE FEE_AMOUNT FEE_CURRENCY FEE_CURRENCY REGISTER_DATE PERCENT REGISTER_DATE PERCENT_DISCOUNT AMOUNT_DISCOUN PERCENT_DISCOUN T T MOVIE_ID(FK) DISCOUNT_ID(FK) DISCOUNT_ID(FK) PERCENT FEE_AMOUNT PERCENT REGISTER_DATE FEE_CURRENCY 61 / 객체지향적인 도메인 레이어 구축하기
  • 62. Solution 다형성을 통한 조건 분기 제거 {abstract} Movie DiscountStrategy Movie Discount calculateFee(showing) registerDate calculateFee(showing) Amount Discount 800원 Amount Percent Non DiscountStrategy DiscountStrategy DiscountStrategy Percent Discount 10% discountAmount percent public class Movie { No Discount 0원(%) private DiscountStrategy discountStrategy; public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } } 62 / 객체지향적인 도메인 레이어 구축하기
  • 63. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 63 / 객체지향적인 도메인 레이어 구축하기
  • 64. Mismatch 연관관계Association와 외래키Foreign Key MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE FEE_AMOUNT SHOWING_TIME FEE_CURRENCY Movie Showing showing.getMovie(); calculateFee(showing) 1 * reserve(customer, count) Movie Showing movie.getShowings(); calculateFee(showing) 1 * reserve(customer, count) Movie Showing movie.getShowings(); calculateFee(showing) 1 * reserve(customer, count) showing.getMovie(); 64 / 객체지향적인 도메인 레이어 구축하기
  • 65. Solution 외래키 맵핑Foreign Key Mapping MOVIE SHOWING ID(PK) ID(PK) TITLE MOVIE_ID(FK) RUNNING_TIME SEQUENCE FEE_AMOUNT SHOWING_TIME FEE_CURRENCY Foreign Key public class Showing { @ManyToOne(optional=false) @JoinColumn(name="MOVIE_ID") private Movie movie; public Money calculateFee() { return movie.calculateFee(this); } } Association Movie Showing calculateFee(showing) 1 * reserve(customer, count) 65 / 객체지향적인 도메인 레이어 구축하기
  • 66. 임피던스 불일치 유형 구성 요소 크기Granularity의 불일치 식별자Identity의 불일치 다형성Polymorphism의 불일치 연관 관계Association와 외래키Foreign Key의 불일치 캡슐화 경계Encapsulation Boundary의 불일치 66 / 객체지향적인 도메인 레이어 구축하기
  • 67. Mismatch 캡슐화Encapsulation 불변식 위반Invariant Violation Movie movie = movieDAO.selectMovie(1); Hierarchical Flat movie.setFee(8000); Showing reserve(customer, count) DiscountStrategy strategy = new AmountDiscountStrategy(9000); Movie discountStrategyDAO.save(strategy); calculateFee(showing):Money {abstract} DiscountStrategy calculateFee(showing):Mon ey {abstract} Rule DiscountRule rule = new SequenceRule(1); isStatisfiedBy(sho wing) discountRuleDAO.save(rule); Amount Percent NonDiscoun t Strategy Strategy Strategy TimeOf Sequence Day Rule Rule DiscountRule rule = new SequenceRule(1); discountRuleDAO.save(rule); 67 / 객체지향적인 도메인 레이어 구축하기
  • 68. Solution 페치 젂략Fetch Strategy  지연 페치Lazy Fetch public class Movie { @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.LAZY) private DiscountStrategy discountStrategy; public class DiscountStrategy { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY) @JoinColumn(name="DISCOUNTID") private Set<Rule> rules = new HashSet<Rule>(); {abstract} {abstract} Showing Movie DiscountStrategy Rule Proxy Proxy 1 * calculateFee(showing) 1 0..1 calculateFee(showing) 1 0..* calculateFee(showing) reserve(customer, count) 68 / 객체지향적인 도메인 레이어 구축하기
  • 69. Solution 페치 젂략Fetch Strategy  선행 페치Eager Fetch public class Movie { @OneToOne(cascade=CascadeType.ALL, optional=true, fetch=FetchType.EAGER) private DiscountStrategy discountStrategy; public class DiscountStrategy { @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER) @JoinColumn(name="DISCOUNTID") private Set<Rule> rules = new HashSet<Rule>(); {abstract} {abstract} Showing Movie DiscountStrategy Rule reserve(customer, count) 1 * calculateFee(showing) 1 0..1 calculateFee(showing) 1 0..* calculateFee(showing) 69 / 객체지향적인 도메인 레이어 구축하기
  • 70. Solution Aggregate = 캡슐화 경계Encapsulation Boundary  예기치 못한 변경으로부터 보호  객체 그룹의 불변성 보장 Showing reserve(customer, count) Aggregate Movie {abstract} calculateFee(showing):Money DiscountStrategy calculateFee(showing):Money {abstract} Rule isStatisfiedBy(showing) Amount Percent NonDiscount Strategy Strategy Strategy Sequence TimeOfDay Rule Rule Eager Fetch Lazy Fetch 70 / 객체지향적인 도메인 레이어 구축하기
  • 72. DOMAIN MODEL PATTERN  도메인을 구성하는 개념들을 따르는 도메인 레이어  적젃한 책임의 분배와 협력을 통한 객체 지향적인 도메인 레이어 72 / 객체지향적인 도메인 레이어 구축하기
  • 73. 임피던스 불일치  맹목적으로 테이블의 구조를 따르는 객체 구조  젃차적인 TRANSACTION SCRIPT로 향하는 한 가지 이유 73 / 객체지향적인 도메인 레이어 구축하기
  • 74. JPAJavaPersistece API  임피던스 불일치를 해결할 수 있는 실용적인 솔루션  풍부한 도메인 레이어Rich Domain Layer의 기반 74 / 객체지향적인 도메인 레이어 구축하기
  • 75. Domain Model에 초점을 맞춰라 Showing Reservation Reservation Showing 1 <<create>> 0..* reserve(customer, count):Reservation Customer 0..* {abstract} {abstract} Movie DiscountStrategy Rule 1 calculateFee(showing):Money calculateFee(showing):Money isStatisfiedBy(showing):boolean 1 0..1 1 1..* Amount Percent NonDiscount Sequence TimeOfDay Strategy Strategy Strategy Rule Rule Movie Discount Rule 75 / 객체지향적인 도메인 레이어 구축하기
  • 76. Data Model이 더 중요 76 / 객체지향적인 도메인 레이어 구축하기
  • 77. 타협하라 Be Pragmatic 데이터베이스가 하나의 객체 저장소로 보여진다면 매핑 도구의 기능과는 상관없이 데이터 모델과 객체 모델이 서로 갈라지게 해서는 안 된다. 일부 객체 관계의 풍부함을 희생해서 관계 모델에 밀접하게 한다. 객체 매핑을 단순화하는데 도움이 된다면 정규화와 같은 정형 화된 관계 표준을 젃충한다. - Eric Evans 77 / 객체지향적인 도메인 레이어 구축하기
  • 78. Thank you. 78 / 객체지향적인 도메인 레이어 구축하기
  • 79. Question? 79 / 객체지향적인 도메인 레이어 구축하기
  • 80. 참고자료 - Christian Bauer, Gavin King, Java Persistence with Hibernate, Manning, 2006. - Michael Keith, Merrick Schincario, Pro JPA2 : Mastering the Java(TM) Persistence API, Apress, 2009. - Chris Richardson, POJOs in Action : Developing Enterprise Applications with Lightweight Frameworks, Manning, 2006. - Martin Fowler, Patterns of Enterprise Application Architecture, Addison-Wesley, 2002. - Eric Evans, Domain-Driven Design, Addison-Wesley, 2003. - Kent Beck and Ward Cunningham, ‚A Laboratory for Teaching Object Oriented Thinking,‛ OOPSLA ‘89 Conference Proceedings, SIGPLAN Notices, 24(10), pp. 1-6, New Orleans, Louisiana, October 1989. - Rebecca Wirfs-Brock and Brian Wilkerson, ‚Object-Oriented Design: A Responsibility-Driven Approach,‛ OOPSLA ‘89 Conference Proceedings, SIGPLAN Notices, 24(10), pp.71-76, New Orleans, Louisiana, October, 1989. - Rebecca Wirfs-Brock, Alan McKean, Object Design : Roles, Responsibilities, and Collaborations , Addison- Wesley, 2002. 80 / 객체지향적인 도메인 레이어 구축하기
  • 81. Appendix A. CRC Card
  • 82. 예매 생성 책임  예매 생성에 필요한 정보의 EXPERT에게 할당Creator Showing 상영 정보를 알고 있다 예매 정보를 생성한다 82 / 객체지향적인 도메인 레이어 구축하기
  • 83. 가격 계산 책임  영화 가격 정보를 알고 있는 EXPERT에 할당Information Expert Movie Showing 영화 정보를 알고 있다 가격을 계산한다 상영 정보를 알고 있다 Movie 예매 정보를 생성한다 83 / 객체지향적인 도메인 레이어 구축하기
  • 84. 할인율 계산 책임  할인율을 적용할 STRATEGY 객체 추가 Movie Showing 영화 정보를 알고 있다 Discount Strategy 가격을 계산한다 상영 정보를 알고 있다 Movie 예매 정보를 생성한다 DiscountStrategy 할인율 정책을 알고 있다 할인된 가격을 계산한다 84 / 객체지향적인 도메인 레이어 구축하기
  • 85. 할인 여부를 판단할 책임  할인 정책을 판단하기 위한 SPECIFICATION 객체 추가 Movie Showing 영화 정보를 알고 있다 Discount Strategy 가격을 계산한다 상영 정보를 알고 있다 Movie 예매 정보를 생성한다 DiscountStrategy 할인율 정책을 알고 있다 Rule 할인된 가격을 계산한다 Rule 할인 정책을 알고 있다 Showing 할인 여부를 판단한다 85 / 객체지향적인 도메인 레이어 구축하기
  • 86. Appendix B. Domain Model Pattern Implementation
  • 87. Domain Layer Collaboration public class Showing { public Reservation reserve(Customer customer, int audienceCount) { return new Reservation(customer, this, audienceCount); } } public class Reservation { public Reservation(Customer customer, Showing showing, int audienceCount) { this.customer = customer; this.showing = showing; this.fee = showing.calculateFee().times(audienceCount); this.audienceCount = audienceCount; } } public class Showing { public Money calculateFee() { return movie.calculateFee(this); } } public class Movie { public Money calculateFee(Showing showing) { return discountStrategy.calculateFee(showing); } } 87 / 객체지향적인 도메인 레이어 구축하기
  • 88. Domain Layer Collaboration public abstract class DiscountStrategy { public Money calculateFee(Showing showing) { for(Rule each : rules) { if (each.isStatisfiedBy(showing)) { return getDiscountedFee(showing); } } return showing.getFixedFee(); } abstract protected Money getDiscountedFee(Showing showing); public abstract class Rule { abstract public boolean isStatisfiedBy(Showing showing); } public class SequenceRule extends Rule { public boolean isStatisfiedBy(Showing showing) { return showing.isSequence(sequence); } } public class TimeOfDayRule extends Rule { public boolean isStatisfiedBy(Showing showing) { return showing.isPlayingOn(dayOfWeek) && Interval.closed(startTime, endTime) .includes(showing.getPlayngInterval()); } } 88 / 객체지향적인 도메인 레이어 구축하기
  • 89. Domain Layer Collaboration public abstract class DiscountStrategy { public Money calculateFee(Showing showing) { for(Rule each : rules) { if (each.isStatisfiedBy(showing)) { return getDiscountedFee(showing); } } return showing.getFixedFee(); } abstract protected Money getDiscountedFee(Showing showing); public class AmountDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee().minus(discountAmount); } } public class NonDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee(); } } public class PercentDiscountStrategy extends DiscountStrategy { protected Money getDiscountedFee(Showing showing) { return showing.getFixedFee().minus(showing.getFixedFee().times(percent)); } } 89 / 객체지향적인 도메인 레이어 구축하기
  • 90. Domain Layer Collaboration :Showing :Reservation :Movie :DiscountStrategy :Rule reserve() new calculateFee() calculateFee() calculateFee() * isStatisfied() 90 / 객체지향적인 도메인 레이어 구축하기
  • 91. Data Model RESERVATION CUSTOMER ID ID CUSTOMER_ID(FK) CUSTOMER_ID SHOWING_ID(FK) NAME FEE_AMOUNT FEE_CURRENCY AUDIENCE_COUNT RULE SHOWING MOVIE DISCOUNT ID ID ID MOVIE_ID(FK) DISCOUNT_ID(FK) MOVIE_ID(FK) TITLE DISCOUNT_TYPE POSITION SEQUENCE RUNNING_TIME FEE_AMOUNT RULE_TYPE SHOWING_TIME FEE_AMOUNT FEE_CURRENCY DAY_OF_WEEK FEE_CURRENCY PERCENT START_TIME REGISTER_DATE END_TUME SEQUENCE 91 / 객체지향적인 도메인 레이어 구축하기
  • 92. Appendix C. Impedance Mismatch Summary
  • 93. 임피던스 불일치Impedance Mismatch MOVIE running Duration Time ID(PK) quantity Movie TITLE RUNNING_TIME title Money FEE_AMOUNT FEE_CURRENCY amount fee currency Movie Showing MOVIE SHOWING 1 * ID(PK) ID(PK) Movie Showing TITLE MOVIE_ID(FK) SEQUENCE 1 * RUNNING_TIME FEE_AMOUNT SHOWING_TIME FEE_CURRENCY Movie Showing 1 * AMOUNT_ {abstract} DISCOUNT DISCOUNT DiscountStrategy MOVIE_ID(FK) MOVIE_ID(FK) registerDate DISCOUNT REGISTER_DATE FEE_AMOUNT MOVIE_ID(FK) FEE_CURRENCY REGISTER_DATE DISCOUNT_TYPE Amount Percent Non FEE_AMOUNT PERCENT_ AMOUNT_ PERCENT_ FEE_CURRENCY Discount Discount Discount PERCENT DISCOUNT DISCOUNT DISCOUNT Strategy Strategy Strategy REGISTER_DATE MOVIE_ID(FK) DISCOUNT_ID(FK) DISCOUNT_ID(FK) discountAmount percent PERCENT FEE_AMOUNT PERCENT REGISTER_DATE FEE_CURRENCY 93 / 객체지향적인 도메인 레이어 구축하기