SlideShare uma empresa Scribd logo
1 de 21
Baixar para ler offline
Ch.9 암시적인 개념을 명확하게
     (Domain Driven Design)
     chois79




12년 10월 29일 월요일
About This Chapter
     • 심층 모델은 도메인에 대한 본질적인 지식을 간결하고 유연하게 표현하는 중심 개념과 추상화를 담고 있는 중요한 요소이다


     • 심층 모델 생성 과정


          • 도메인의 본질적인 개념을 모델로 표현


          • 성공적인 지식 탐구와 리팩토링을 반복하며 정제


                  • 중요한 개념이 모델과 설계에 명확하게 인식되고 표현이 되었을 때 가능


     • 그렇다면, 어떻게 중요한 개념을 모델과 설계 내에 명확히 표현되게 할것인가?


          • 전통적인 방식: 요구사항 문서에 서술된 명사와 동사를 식별


                  • 명사 -> 객체 이름, 동사 -> 객체의 메서드


                  • 얄팍한 지식에 기반을 둔 투박하고 무의미한 모델인 경우가 대부분


          • 도메인 내의 암시적인 개념을 명확히 인식하고 반영하는 것이 필요



12년 10월 29일 월요일
개념 파헤치기

     • 개발자는 잠재해 있는 암시적인 개념을 드러내는 단서에 민감해야 한다


          • 언어에 귀를 기울여라


          • 어색한 부분을 조사하라


          • 모순점에 대해 깊이 고민하라


          • 시도하고 또 시도하라




12년 10월 29일 월요일
언어에 귀를 기울여라

     • 도메인 전문가가 사용하는 언어에 귀 기울여라


          • 복잡하게 뒤얽힌 개념들을 간결하게 표현하는 용어가 있는가?


          • 선택한 단어를 더 적절하게 고쳐주는가?


          • 특정 문구를 이야기할 때 도메인 전문가의 얼굴에서 곤혹스러운 표정이 사라지는가?


          • 개발자와 도메인 전문가가 설계상의 어디에도 표현돼 있지 않은 어휘를 사용하는가?


     • 새로운 단어는 유용한 개념을 찾기 위한 대화와 지식 탐구로 이어진다


          • 누락된 용어(개념)를 설계에 포함시켜 모델과 설계를 향상시키는 기회가 될수 있다


12년 10월 29일 월요일
어색한 부분을 조사하라

     • 필요한 개념이 늘 대화나 문서로 인식할 수 있을 만큼 드러나 있는 것은 아니다


     • 설계에서 어색한 부분


          • 설명하기 힘들 만큼 복잡한 작업을 수행하는 프로시저


          • 관련된 부분이나 새로운 요구사항 탓에 복잡성이 증가하는 부분


     • 해결책은 도메인 전문가가 필요한 개념을 발견할 수 있게 돕는 것


          • 바람직한 경우: 도메인 전문가가 다양한 아이디어를 고안해서 모델에 시도


          • 그 밖의 경우: 개발자가 아이디어를 제안하고, 도메인 전문가의 동의를 구함


12년 10월 29일 월요일
모순점에 대해 깊이 고민하라

     • 요구사항 분석시 마주치게 되는 모순은 심층적 모델에 이르는 중요한 단서가 된다


     • 모순의 발생 원인


          • 용어를 다르게 사용하는 경우


          • 도메인을 잘못 이해했을 경우


          • 간혹, 두 도메인 전문가가 서로 모순되는 진술을 하는 경우


     • 모순에 대한 저자의 견해


          • 흥미롭지 않을뿐더러 그렇게 심오한 내용을 암시하지도 않다


          • 모든 모순을 해소하는 것은 현실적이지도, 바람직하지도 않다


          • 하지만, 심사숙고 하는 과정에서 숨겨진 있던 사실들을 밝히는 계기가 마련될 수 있다



12년 10월 29일 월요일
서적을 참고하라

     • 모델의 개념을 조사할 때는 분명해 보이는 사실이라고 해서 간과해서는 안된다


     • 서적을 참고할 경우


          • 다양한 분야에 대한 근본 개념과 일반적인 통념을 얻을 수 있다


          • 이를 통해, 일관성 있고 사려 깊은 관점에서 작업을 시작할 수 있다




12년 10월 29일 월요일
시도하고 또 시도하라

     • 모델에서 유용해 보이는 지식을 발견하기까지는 많은 시행착오 과정이 필요


          • 모델러/설계자는 자신의 아이디어에 집착해서는 안된다


          • 리팩토링을 통해 수정해야 할 것으로 판명된 곳을 지체하지 않고 수정할 수 있게 모델의
            상태를 유지


     • 시도하고 또 시도하라


          • 실험은 유용한 것과 유용하지 않은 것이 무엇인지 배우는 방법


          • 설계 과정에서 실수를 피하려고 발버둥 치면, 더 적은 경험을 바탕으로 해야하는 탓에
            품질이 더 낮은 결과물을 얻게 될 것이다


12년 10월 29일 월요일
다소 불명확한 개념을 모델링하는 법

     • 객체지향 설계 입문자가 명확한 개념으로 인식하기 힘든 세가지 범주


          • 명시적인 제약조건


          • 도메인 객체로서의 프로세스


          • SPECIFICATION




12년 10월 29일 월요일
How to Model Less Obvious Kinds of Concepts
             The object-oriented paradigm leads us to look for and invent certain kinds of concepts. Things,
             even very abstract ones such as "accruals," are the meat of most object models, along with the
             actions those things take. These are the "nouns and verbs" that introductory object-oriented
             design books talk about. But other important categories of concepts can be made explicit in a
             model as well.


     명시적인 제약 조건(1/2)
             I'll discuss three such categories that were not obvious to me when I started with objects. My
             designs became sharper with each one of these I learned.



             Explicit Constraints
             Constraints make up a particularly important category of model concepts. They often emerge

     • 암시적인 상태의 제약조건을, 명시적으로 표현할 경우 설계를 대폭 개선
             implicitly, and expressing them explicitly can greatly improve a design.

             Sometimes constraints find a natural home in an object or method. A "Bucket" object must
             guarantee the invariant that it does not hold more than its capacity.




          • ex) “Bucket” 객체는 제한된 용량을 초과해서 저장할 수 있다는 제약조건
                                                       Figure 9.10.



                                                                                                               class Bucket {
                                                                                                                    private float capacity; private float contents;
                                                                                                                    public void pourIn(float addedVolume) {
                                                                                                                          if (contents + addedVolume > capacity) {
                                                                                                                                 contents = capacity;
                                                                                                                           } else {
                                                                                                                                contents = contents + addedVolume;
                                                                                                                          }
                                                                                                                    }
                                                                                                               }


             A simple invariant like this can be enforced using case logic in each operation capable of changing
             contents.
                                                                                                            제약조건을    함수로 분리

                 class Bucket {
             class Bucket {
                privateprivate float capacity;
                        float capacity;
                privateprivate float contents;
                        float contents;

                  public public void pourIn(float addedVolume) {
                         void pourIn(float addedVolume) {
                               float volumePresent = contents + addedVolume;
                     if (contents + addedVolume > capacity) {
                               contents = constrainedToCapacity(volumePresent);
                        contents = capacity;                                                                   문제점
                         }
                                                                                                               ✓ 한 메서드 안에 제약 조건을 다 담을 수 없을 경우
                     } else {
                        contents =float constrainedToCapacity(float volumePlacedIn) {
                         private contents + addedVolume;
                                if (volumePlacedIn > capacity)                                                 ✓ 객체의 주된 책임을 수행하는데 필요하지 않은 정보를
                                     return capacity;                                                          해당 메소드에서 필요로 하는 경우
                                return volumePlacedIn;
                        }
                  }




12년 10월 29일 월요일
명시적인 제약 조건(2/2)

     • 제약 조건을 포함한 객체의 설계가 어딘가 잘못되어 있음을 나타내는 조짐


          • 제약조건을 평가하려면 해당 객체의 정의에 적합하지 않은 데이터가 필요한 경우
           Example
           Review: Overbooking Policy
          • 관련된 규칙이 여러 객체에 걸쳐 나타나며, 동일한 계층 구조에 속하지 않는 객체 간에 중복 또는 상속 관계를 강요하는
            경우
           In Chapter 1, we worked with a common shipping business practice: booking 10 percent more
           cargo than the transports could handle. (Experience has taught shipping firms that this
           overbooking compensates for last-minute cancellations, so their ships will sail nearly full.)
          • 설계와 요구사항에 관한 다양한 논의는 제약조건에 초첨을 맞춰 이뤄지지만 정작 구현 단계에서 절차적인 코드에 묻혀
           This constraint on the association between Voyage and Cargo was made explicit, both in the
            명시적으로 표현되지 않는 경우
           diagrams and in the code, by adding a new class that represented the constraint.


     • 제약조건을 표현하는 새로운 클래스 추가
              Figure 9.11. The model refactored to make policy explicit




           To review the code and reasoning in the full example, see page 17.



           Processes as Domain Objects
12년 10월 29일 월요일
도메인 객체로서의 프로세스

     • 객체는 절차를 캡슐화해서 절차 대신 객체의 목표나 의도에 관해 생각하게 해야 한다


          • 모델내에 프로세스가 나타나면 객체를 어색하게 설계하는 경향이 있음


     • 프로세스를 도메인 객체로 표현하는 방법


          • SERVICE는 프로세스를 명시적으로 표현


          • 프로세스를 수행하는 방법이 한가지 이상일 경우


                  • 프로세스를 STRATEGY로 표현


     • 명시적으로 표현해야할 프로세스와 숨겨야할 프로세스의 구분법


          • 도메인 전문가가 이야기 하고 있는 프로세스인가? => 명시적으로 표현



12년 10월 29일 월요일
SPECIFICATION

     • 모든 종류의 애플리케이션에는 규칙을 검사하는 Boolean 테스트 메서드가 존재


          • ex) Invoice의 지불 기간이 지났는지를 검사하는 함수
                    public boolean isOverdue() {
                        Date currentDate = new Date();
                        return currentDate.after(dueDate);
                    }


                  • 고객의 계정 상태에 따른 지불 유예기간 정책과 같은 복잡한 규칙이 추가 된다면?


                    • 지불요청을 의미하는 Invoice의 명료함이 규칙에 묻혀 사라질 것


                    • 여러 도메인 클래스 및 하위 시스템에 의존성을 가지게 될 것


                  • 그렇다면 어떻게 할 것인가?


                    • 응용 계층으로 분리?



12년 10월 29일 월요일
SPECIFICATION
     • 명세를 위한 객체


          • 다른 객체가 SPECIFICATION에 명시된 기준을 만족하는지 검사
                  I developed SPECIFICATION in collaboration with Martin Fowler (Evans and Fowler 1997). The
                  simplicity of the concept belies the subtlety in application and implementation, so there is a lot of
                  detail in this section. There will be even more discussion in Chapter 10, where the pattern is
          • 특별한 목적을 위한 명시적인 VALUE OBJECT
                  extended. After reading the initial explanation of the pattern that follows, you may want to skim
                  the "Applying and Implementing SPECIFICATIONS" section, until you are actually attempting to apply
                  the pattern.

          • 규칙을 도메인 계층에 유지
                  Specification




                  In all kinds of applications, Boolean test methods appear that are really parts of little rules. As long
                  as they are simple, we handle them with testing methods, such as anIterator.hasNext() or
                  anInvoice.isOverdue(). In an Invoice class, the code in isOverdue() is an algorithm that
                  evaluates a rule. For example,
     • SPECIFICATION의 적용
                  public boolean isOverdue() {
                     Date currentDate = new Date();
                     return currentDate.after(dueDate);
          • 업무 규칙이 ENTITY나 VALUE OBJECT가 맡고 있는 책임에 맞지 않는 경우
                  }


                  But not all rules are so simple. On the same Invoice class, another rule,
                  anInvoice.isDelinquent() would presumably start with testing if the Invoice is overdue, but
          • 규칙의 다양성과 조합이 도메인 객체의 기본의미를 압도하는 경우
                  that would just be the beginning. A policy on grace periods could depend on the status of the
                  customer's account. Some delinquent invoices will be ready for a second notice, while others will
                  be ready to be sent to a collection agency. The payment history of the customer, company policy
                  on different product lines . . . the clarity of Invoice as a request for payment will soon be lost in
                  • 규칙을 도메인 계층으로 분리한다면 도메인 코드가 더는 모델을 표현할 수 없음
                  the sheer mass of rule evaluation code. The Invoice will also develop all sorts of dependencies on
                  domain classes and subsystems that do not support that basic meaning.

                  At this point, in an attempt to save the Invoice class, a developer will often refractor the rule
                  evaluation code into the application layer (in this case, a bill collection application). Now the rules
                  have been separated from the domain layer altogether, leaving behind a dead data object that
                  does not express the rules inherent in the business model. These rules need to stay in the domain
                  layer, but they don't fit into the object being evaluated (the Invoice in this case). Not only that,
                  but evaluating methods swell with conditional code, which make the rule hard to read.
12년 10월 29일 월요일
SPECIFICATION 용도

     • 3가지 용도는 개념적 차원에서는 동일함.


          • 검증: 객체가 어떤 요건을 충족시키거나 특정 목적으로 사용할 수 있는지 검사


          • 선택: 컬렉션 내의 객체를 선택


          • 요청 구축: 특정한 요구 사항을 만족하는 새로운 객체의 생성을 명시




12년 10월 29일 월요일
3.




         SPECIFICATION - 검증
possibly contradictory forms. The conceptual unity can be lost. Applying the SPECIFICATION pattern
allows a consistent model to be used, even when the implementation may have to diverge.


Validation
         • SPECIFICATION의 개념을 가장 직관적으로 사용하는 방식
The simplest use of a SPECIFICATION is validation, and it is the use that demonstrates the concept
most straightforwardly.


             • 특정한조건에 부합하는지 여부를 판단하여, 결과를 기반으로 특정 행위를 수행
         Figure 9.14. A model applying a
                             SPECIFICATION for validation




                                                                      public boolean accountIsDelinquent(Customer customer) {
                                                                           Date today = new Date();
                                                                           Specification delinquentSpec = new DelinquentInvoiceSpecification(today);
                                                                           Iterator it = customer.getInvoices().iterator();
                                                                           while (it.hasNext()) {
                                                                                Invoice candidate = (Invoice) it.next();
                                                                                if (delinquentSpec.isSatisfiedBy(candidate))
                                                                                     return true;
                                                                           }
class DelinquentInvoiceSpecification extends                               return false;
      InvoiceSpecification {                                          }
   private Date currentDate;
   // An instance is used and discarded on a single date
           class DelinquentInvoiceSpecification extends InvoiceSpecification {
                private Date currentDate;
     public DelinquentInvoiceSpecification(Date currentDate) {
                // An instance is used and discarded on a single date
        this.currentDate = currentDate;
}               public DelinquentInvoiceSpecification(Date currentDate) {
                     this.currentDate = currentDate;
     public boolean isSatisfiedBy(Invoice candidate) {
                }
        int gracePeriodboolean isSatisfiedBy(Invoice candidate) {
                public =
                     int gracePeriod = candidate.customer().getPaymentGracePeriod();
           candidate.customer().getPaymentGracePeriod();
        Date firmDeadline firmDeadline = DateUtility.addDaysToDate(candidate.dueDate(), gracePeriod);
                     Date =
                     return currentDate.after(firmDeadline);
           DateUtility.addDaysToDate(candidate.dueDate(),
                }
              gracePeriod);
           }
           return currentDate.after(firmDeadline);
     }
} 12년 10월 29일 월요일
SPECIFICATION - 선택 (1/3)
                                                            "SELECT * FROM INVOICE, CUSTOMER" +
                                                            " WHERE INVOICE.CUST_ID = CUSTOMER.ID" +
                                                            " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" +
     • 특정한 조건을 기반으로 객체 컬렉션의 일부를 선택                          "     < " + SQLUtility.dateAsSQL(currentDate);
                                                     }
           public Set selectSatisfying(InvoiceSpecification spec) {
                Set results = new HashSet();
                Iterator it = invoices.iterator();   SPECIFICATIONS mesh smoothly with REPOSITORIES, which are the building-block mechanisms
                while (it.hasNext()) {
                                                     providing query access to domain objects and encapsulating the interface to the database (s
                     Invoice candidate = (Invoice) it.next();
                                                     Figure 9.15).
                     if (spec.isSatisfiedBy(candidate))
                     results.add(candidate);
                }

           }
                return results;
                                                          Figure 9.15. The interaction between REPOSITORY and SPECIFICATIO

     • SPECIFICATION을 유지하며 관계형 데이터 베이스에 질의


          • 맵핑 프레임워크를 사용하지 않는 경우
        public String asSQL() {
             return "SELECT * FROM INVOICE, CUSTOMER" +
                  " WHERE INVOICE.CUST_ID = CUSTOMER.ID" +
                  " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" +
                  " < " + SQLUtility.dateAsSQL(currentDate);
        }

                  문제점
                  ✓ 테이블 구조가 Domain Layer에 노출




                                                     Now this design has some problems. Most important, the details of the table structure have
                                                     into the DOMAIN LAYER; they should be isolated in a mapping layer that relates the domain ob
12년 10월 29일 월요일
SPECIFICATION - 선택 (2/3)

     • Double Dispatch 적용
            public class InvoiceRepository {
                 public Set selectWhereGracePeriodPast(Date aDate){
                      //This is not a rule, just a specialized query
                      String sql = whereGracePeriodPast_SQL(aDate);
                      ResultSet queryResultSet = SQLDatabaseInterface.instance().executeQuery(sql);
                       return buildInvoicesFromResultSet(queryResultSet);
                 }
                 public String whereGracePeriodPast_SQL(Date aDate) {
                      return "SELECT * FROM INVOICE, CUSTOMER" +
                           " WHERE INVOICE.CUST_ID = CUSTOMER.ID" +
                           " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" +
                           " < " + SQLUtility.dateAsSQL(aDate);
                 }                                                          문제점
                 public Set selectSatisfying(InvoiceSpecification spec) {
                      return spec.satisfyingElementsFrom(this);
                                                                            ✓체납 개념을 구성하는 본질적인 규칙은 SPECIFICATION에 명시
                 }                                                          되었으나, 규칙을 깔끔하게 모으지 못함
            }



           public class DelinquentInvoiceSpecification {
                // Basic DelinquentInvoiceSpecification code here
                public Set satisfyingElementsFrom(InvoiceRepository repository) {
                     //Delinquency rule is defined as:
                     // "grace period past as of current date"
                     return repository.selectWhereGracePeriodPast(currentDate);
                }
           }




12년 10월 29일 월요일
SPECIFICATION - 선택 (3/3)

     • REPOSITORY를 일반화 상태로 유지
         public class InvoiceRepository {
              public Set selectWhereDueDateIsBefore(Date aDate) {
                   String sql = whereDueDateIsBefore_SQL(aDate);
                   ResultSet queryResultSet = SQLDatabaseInterface.instance().executeQuery(sql);
                   return buildInvoicesFromResultSet(queryResultSet);
              }
              public String whereDueDateIsBefore_SQL(Date aDate) {
                   return "SELECT * FROM INVOICE" +
                        " WHERE INVOICE.DUE_DATE" +
                        " < " + SQLUtility.dateAsSQL(aDate);
              }                                                                      문제점
              public Set selectSatisfying(InvoiceSpecification spec) {
                   return spec.satisfyingElementsFrom(this);                         ✓성능 저하 발생
              }                                                                      ✓성능 vs. 책임분할에 대한 검증 필요
         }

         public class DelinquentInvoiceSpecification {
              //Basic DelinquentInvoiceSpecification code here
              public Set satisfyingElementsFrom(InvoiceRepository repository) {
                   Collection pastDueInvoices = repository.selectWhereDueDateIsBefore(currentDate);
                   Set delinquentInvoices = new HashSet();
                   Iterator it = pastDueInvoices.iterator();
                   while (it.hasNext()) {
                        Invoice anInvoice = (Invoice) it.next();
                        if (this.isSatisfiedBy(anInvoice))
                             delinquentInvoices.add(anInvoice);
                   }
                   return delinquentInvoices;
              }
         }




12년 10월 29일 월요일
SPECIFICATION - 요청 구축

     • SPECIFICATION을 만족하는 객체를 생성


          • SPECIFICATION을 사용하지 않고 Generator을 사용할 경우


                  • Generator 내에 행위를 암시적으로 규정해야 함


          • SPECIFICATION을 사용할 경우


                  • Generator의 구현을 인터페이스로부터 분리 (암시적인 규정)


                  • 개발자가 세부사항을 이해하지 않고도 결과물을 예측 가능


                  • 생성 요청을 하는 코드는 클라이언트에 있기 때문에 더 유연한 개선이 가능


                  • SPECIFICATION을 통해 생성된 결과물을 검증 가능



12년 10월 29일 월요일
요약

     • 도메인의 숨겨진 개념을 명확하게 인식하는 방법


          • 언어에 귀를 기울여라


          • 어색한 부분을 조사하라


          • 모순점에 대해 깊이 고민하라


          • 시도하고 또 시도하라


     • 객체지향 설계 입문자가 명확한 개념으로 인식하기 힘든 세가지 범주


          • 명시적인 제약조건


          • 도메인 객체로서의 프로세스


          • SPECIFICATION



12년 10월 29일 월요일

Mais conteúdo relacionado

Destaque

서버인프라를지탱하는기술3_2_3
서버인프라를지탱하는기술3_2_3서버인프라를지탱하는기술3_2_3
서버인프라를지탱하는기술3_2_3HyeonSeok Choi
 
Domain driven design ch1
Domain driven design ch1Domain driven design ch1
Domain driven design ch1HyeonSeok Choi
 
자바 병렬 프로그래밍 ch9
자바 병렬 프로그래밍 ch9자바 병렬 프로그래밍 ch9
자바 병렬 프로그래밍 ch9HyeonSeok Choi
 
Code 11 논리 게이트
Code 11 논리 게이트Code 11 논리 게이트
Code 11 논리 게이트HyeonSeok Choi
 
자바 병렬 프로그래밍 1&2
자바 병렬 프로그래밍 1&2자바 병렬 프로그래밍 1&2
자바 병렬 프로그래밍 1&2HyeonSeok Choi
 
컴퓨터 프로그램 구조와 해석 3.5
컴퓨터 프로그램 구조와 해석 3.5컴퓨터 프로그램 구조와 해석 3.5
컴퓨터 프로그램 구조와 해석 3.5HyeonSeok Choi
 
실무로 배우는 시스템 성능 최적화 Ch7
실무로 배우는 시스템 성능 최적화 Ch7실무로 배우는 시스템 성능 최적화 Ch7
실무로 배우는 시스템 성능 최적화 Ch7HyeonSeok Choi
 
서버인프라를지탱하는기술2_1-2
서버인프라를지탱하는기술2_1-2서버인프라를지탱하는기술2_1-2
서버인프라를지탱하는기술2_1-2HyeonSeok Choi
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6HyeonSeok Choi
 
HTTP 완벽가이드 16장
HTTP 완벽가이드 16장HTTP 완벽가이드 16장
HTTP 완벽가이드 16장HyeonSeok Choi
 
Mining the social web ch1
Mining the social web ch1Mining the social web ch1
Mining the social web ch1HyeonSeok Choi
 
Abstract factory petterns
Abstract factory petternsAbstract factory petterns
Abstract factory petternsHyeonSeok Choi
 
Head first statistics14
Head first statistics14Head first statistics14
Head first statistics14HyeonSeok Choi
 
C++ API 디자인 - 확장성
C++ API 디자인 - 확장성C++ API 디자인 - 확장성
C++ API 디자인 - 확장성HyeonSeok Choi
 
실무로 배우는 시스템 성능 최적화 10부. 네트워크 모니터링
실무로 배우는 시스템 성능 최적화   10부. 네트워크 모니터링실무로 배우는 시스템 성능 최적화   10부. 네트워크 모니터링
실무로 배우는 시스템 성능 최적화 10부. 네트워크 모니터링Hyunsoo Jung
 
Tools in android sdk
Tools in android sdkTools in android sdk
Tools in android sdkMinchul Jung
 

Destaque (20)

서버인프라를지탱하는기술3_2_3
서버인프라를지탱하는기술3_2_3서버인프라를지탱하는기술3_2_3
서버인프라를지탱하는기술3_2_3
 
Domain driven design ch1
Domain driven design ch1Domain driven design ch1
Domain driven design ch1
 
C++ api design 품질
C++ api design 품질C++ api design 품질
C++ api design 품질
 
자바 병렬 프로그래밍 ch9
자바 병렬 프로그래밍 ch9자바 병렬 프로그래밍 ch9
자바 병렬 프로그래밍 ch9
 
Code 11 논리 게이트
Code 11 논리 게이트Code 11 논리 게이트
Code 11 논리 게이트
 
자바 병렬 프로그래밍 1&2
자바 병렬 프로그래밍 1&2자바 병렬 프로그래밍 1&2
자바 병렬 프로그래밍 1&2
 
컴퓨터 프로그램 구조와 해석 3.5
컴퓨터 프로그램 구조와 해석 3.5컴퓨터 프로그램 구조와 해석 3.5
컴퓨터 프로그램 구조와 해석 3.5
 
실무로 배우는 시스템 성능 최적화 Ch7
실무로 배우는 시스템 성능 최적화 Ch7실무로 배우는 시스템 성능 최적화 Ch7
실무로 배우는 시스템 성능 최적화 Ch7
 
서버인프라를지탱하는기술2_1-2
서버인프라를지탱하는기술2_1-2서버인프라를지탱하는기술2_1-2
서버인프라를지탱하는기술2_1-2
 
실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6실무로 배우는 시스템 성능 최적화 Ch6
실무로 배우는 시스템 성능 최적화 Ch6
 
HTTPS
HTTPSHTTPS
HTTPS
 
HTTP 완벽가이드 16장
HTTP 완벽가이드 16장HTTP 완벽가이드 16장
HTTP 완벽가이드 16장
 
Mining the social web ch1
Mining the social web ch1Mining the social web ch1
Mining the social web ch1
 
Abstract factory petterns
Abstract factory petternsAbstract factory petterns
Abstract factory petterns
 
MutiCore 19-20
MutiCore 19-20MutiCore 19-20
MutiCore 19-20
 
Head first statistics14
Head first statistics14Head first statistics14
Head first statistics14
 
Hadoop overview
Hadoop overviewHadoop overview
Hadoop overview
 
C++ API 디자인 - 확장성
C++ API 디자인 - 확장성C++ API 디자인 - 확장성
C++ API 디자인 - 확장성
 
실무로 배우는 시스템 성능 최적화 10부. 네트워크 모니터링
실무로 배우는 시스템 성능 최적화   10부. 네트워크 모니터링실무로 배우는 시스템 성능 최적화   10부. 네트워크 모니터링
실무로 배우는 시스템 성능 최적화 10부. 네트워크 모니터링
 
Tools in android sdk
Tools in android sdkTools in android sdk
Tools in android sdk
 

Mais de HyeonSeok Choi

밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05HyeonSeok Choi
 
밑바닥부터시작하는딥러닝 Ch2
밑바닥부터시작하는딥러닝 Ch2밑바닥부터시작하는딥러닝 Ch2
밑바닥부터시작하는딥러닝 Ch2HyeonSeok Choi
 
프로그래머를위한선형대수학1.2
프로그래머를위한선형대수학1.2프로그래머를위한선형대수학1.2
프로그래머를위한선형대수학1.2HyeonSeok Choi
 
알고리즘 중심의 머신러닝 가이드 Ch04
알고리즘 중심의 머신러닝 가이드 Ch04알고리즘 중심의 머신러닝 가이드 Ch04
알고리즘 중심의 머신러닝 가이드 Ch04HyeonSeok Choi
 
딥러닝 제대로시작하기 Ch04
딥러닝 제대로시작하기 Ch04딥러닝 제대로시작하기 Ch04
딥러닝 제대로시작하기 Ch04HyeonSeok Choi
 
밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05HyeonSeok Choi
 
7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성HyeonSeok Choi
 
7가지 동시성 모델 4장
7가지 동시성 모델 4장7가지 동시성 모델 4장
7가지 동시성 모델 4장HyeonSeok Choi
 
실무로 배우는 시스템 성능 최적화 Ch8
실무로 배우는 시스템 성능 최적화 Ch8실무로 배우는 시스템 성능 최적화 Ch8
실무로 배우는 시스템 성능 최적화 Ch8HyeonSeok Choi
 
Logstash, ElasticSearch, Kibana
Logstash, ElasticSearch, KibanaLogstash, ElasticSearch, Kibana
Logstash, ElasticSearch, KibanaHyeonSeok Choi
 
실무로배우는시스템성능최적화 Ch1
실무로배우는시스템성능최적화 Ch1실무로배우는시스템성능최적화 Ch1
실무로배우는시스템성능최적화 Ch1HyeonSeok Choi
 
HTTP 완벽가이드 21장
HTTP 완벽가이드 21장HTTP 완벽가이드 21장
HTTP 완벽가이드 21장HyeonSeok Choi
 
HTTP 완벽가이드 6장.
HTTP 완벽가이드 6장.HTTP 완벽가이드 6장.
HTTP 완벽가이드 6장.HyeonSeok Choi
 
HTTP 완벽가이드 1장.
HTTP 완벽가이드 1장.HTTP 완벽가이드 1장.
HTTP 완벽가이드 1장.HyeonSeok Choi
 

Mais de HyeonSeok Choi (20)

밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05
 
밑바닥부터시작하는딥러닝 Ch2
밑바닥부터시작하는딥러닝 Ch2밑바닥부터시작하는딥러닝 Ch2
밑바닥부터시작하는딥러닝 Ch2
 
프로그래머를위한선형대수학1.2
프로그래머를위한선형대수학1.2프로그래머를위한선형대수학1.2
프로그래머를위한선형대수학1.2
 
알고리즘 중심의 머신러닝 가이드 Ch04
알고리즘 중심의 머신러닝 가이드 Ch04알고리즘 중심의 머신러닝 가이드 Ch04
알고리즘 중심의 머신러닝 가이드 Ch04
 
딥러닝 제대로시작하기 Ch04
딥러닝 제대로시작하기 Ch04딥러닝 제대로시작하기 Ch04
딥러닝 제대로시작하기 Ch04
 
밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05밑바닥부터시작하는딥러닝 Ch05
밑바닥부터시작하는딥러닝 Ch05
 
함수적 사고 2장
함수적 사고 2장함수적 사고 2장
함수적 사고 2장
 
7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성7가지 동시성 모델 - 데이터 병렬성
7가지 동시성 모델 - 데이터 병렬성
 
7가지 동시성 모델 4장
7가지 동시성 모델 4장7가지 동시성 모델 4장
7가지 동시성 모델 4장
 
Bounded Context
Bounded ContextBounded Context
Bounded Context
 
DDD Repository
DDD RepositoryDDD Repository
DDD Repository
 
DDD Start Ch#3
DDD Start Ch#3DDD Start Ch#3
DDD Start Ch#3
 
실무로 배우는 시스템 성능 최적화 Ch8
실무로 배우는 시스템 성능 최적화 Ch8실무로 배우는 시스템 성능 최적화 Ch8
실무로 배우는 시스템 성능 최적화 Ch8
 
Logstash, ElasticSearch, Kibana
Logstash, ElasticSearch, KibanaLogstash, ElasticSearch, Kibana
Logstash, ElasticSearch, Kibana
 
실무로배우는시스템성능최적화 Ch1
실무로배우는시스템성능최적화 Ch1실무로배우는시스템성능최적화 Ch1
실무로배우는시스템성능최적화 Ch1
 
HTTP 완벽가이드 21장
HTTP 완벽가이드 21장HTTP 완벽가이드 21장
HTTP 완벽가이드 21장
 
HTTP 완벽가이드 6장.
HTTP 완벽가이드 6장.HTTP 완벽가이드 6장.
HTTP 완벽가이드 6장.
 
HTTP 완벽가이드 1장.
HTTP 완벽가이드 1장.HTTP 완벽가이드 1장.
HTTP 완벽가이드 1장.
 
Cluster - spark
Cluster - sparkCluster - spark
Cluster - spark
 
Pair RDD - Spark
Pair RDD - SparkPair RDD - Spark
Pair RDD - Spark
 

Domain driven design ch9

  • 1. Ch.9 암시적인 개념을 명확하게 (Domain Driven Design) chois79 12년 10월 29일 월요일
  • 2. About This Chapter • 심층 모델은 도메인에 대한 본질적인 지식을 간결하고 유연하게 표현하는 중심 개념과 추상화를 담고 있는 중요한 요소이다 • 심층 모델 생성 과정 • 도메인의 본질적인 개념을 모델로 표현 • 성공적인 지식 탐구와 리팩토링을 반복하며 정제 • 중요한 개념이 모델과 설계에 명확하게 인식되고 표현이 되었을 때 가능 • 그렇다면, 어떻게 중요한 개념을 모델과 설계 내에 명확히 표현되게 할것인가? • 전통적인 방식: 요구사항 문서에 서술된 명사와 동사를 식별 • 명사 -> 객체 이름, 동사 -> 객체의 메서드 • 얄팍한 지식에 기반을 둔 투박하고 무의미한 모델인 경우가 대부분 • 도메인 내의 암시적인 개념을 명확히 인식하고 반영하는 것이 필요 12년 10월 29일 월요일
  • 3. 개념 파헤치기 • 개발자는 잠재해 있는 암시적인 개념을 드러내는 단서에 민감해야 한다 • 언어에 귀를 기울여라 • 어색한 부분을 조사하라 • 모순점에 대해 깊이 고민하라 • 시도하고 또 시도하라 12년 10월 29일 월요일
  • 4. 언어에 귀를 기울여라 • 도메인 전문가가 사용하는 언어에 귀 기울여라 • 복잡하게 뒤얽힌 개념들을 간결하게 표현하는 용어가 있는가? • 선택한 단어를 더 적절하게 고쳐주는가? • 특정 문구를 이야기할 때 도메인 전문가의 얼굴에서 곤혹스러운 표정이 사라지는가? • 개발자와 도메인 전문가가 설계상의 어디에도 표현돼 있지 않은 어휘를 사용하는가? • 새로운 단어는 유용한 개념을 찾기 위한 대화와 지식 탐구로 이어진다 • 누락된 용어(개념)를 설계에 포함시켜 모델과 설계를 향상시키는 기회가 될수 있다 12년 10월 29일 월요일
  • 5. 어색한 부분을 조사하라 • 필요한 개념이 늘 대화나 문서로 인식할 수 있을 만큼 드러나 있는 것은 아니다 • 설계에서 어색한 부분 • 설명하기 힘들 만큼 복잡한 작업을 수행하는 프로시저 • 관련된 부분이나 새로운 요구사항 탓에 복잡성이 증가하는 부분 • 해결책은 도메인 전문가가 필요한 개념을 발견할 수 있게 돕는 것 • 바람직한 경우: 도메인 전문가가 다양한 아이디어를 고안해서 모델에 시도 • 그 밖의 경우: 개발자가 아이디어를 제안하고, 도메인 전문가의 동의를 구함 12년 10월 29일 월요일
  • 6. 모순점에 대해 깊이 고민하라 • 요구사항 분석시 마주치게 되는 모순은 심층적 모델에 이르는 중요한 단서가 된다 • 모순의 발생 원인 • 용어를 다르게 사용하는 경우 • 도메인을 잘못 이해했을 경우 • 간혹, 두 도메인 전문가가 서로 모순되는 진술을 하는 경우 • 모순에 대한 저자의 견해 • 흥미롭지 않을뿐더러 그렇게 심오한 내용을 암시하지도 않다 • 모든 모순을 해소하는 것은 현실적이지도, 바람직하지도 않다 • 하지만, 심사숙고 하는 과정에서 숨겨진 있던 사실들을 밝히는 계기가 마련될 수 있다 12년 10월 29일 월요일
  • 7. 서적을 참고하라 • 모델의 개념을 조사할 때는 분명해 보이는 사실이라고 해서 간과해서는 안된다 • 서적을 참고할 경우 • 다양한 분야에 대한 근본 개념과 일반적인 통념을 얻을 수 있다 • 이를 통해, 일관성 있고 사려 깊은 관점에서 작업을 시작할 수 있다 12년 10월 29일 월요일
  • 8. 시도하고 또 시도하라 • 모델에서 유용해 보이는 지식을 발견하기까지는 많은 시행착오 과정이 필요 • 모델러/설계자는 자신의 아이디어에 집착해서는 안된다 • 리팩토링을 통해 수정해야 할 것으로 판명된 곳을 지체하지 않고 수정할 수 있게 모델의 상태를 유지 • 시도하고 또 시도하라 • 실험은 유용한 것과 유용하지 않은 것이 무엇인지 배우는 방법 • 설계 과정에서 실수를 피하려고 발버둥 치면, 더 적은 경험을 바탕으로 해야하는 탓에 품질이 더 낮은 결과물을 얻게 될 것이다 12년 10월 29일 월요일
  • 9. 다소 불명확한 개념을 모델링하는 법 • 객체지향 설계 입문자가 명확한 개념으로 인식하기 힘든 세가지 범주 • 명시적인 제약조건 • 도메인 객체로서의 프로세스 • SPECIFICATION 12년 10월 29일 월요일
  • 10. How to Model Less Obvious Kinds of Concepts The object-oriented paradigm leads us to look for and invent certain kinds of concepts. Things, even very abstract ones such as "accruals," are the meat of most object models, along with the actions those things take. These are the "nouns and verbs" that introductory object-oriented design books talk about. But other important categories of concepts can be made explicit in a model as well. 명시적인 제약 조건(1/2) I'll discuss three such categories that were not obvious to me when I started with objects. My designs became sharper with each one of these I learned. Explicit Constraints Constraints make up a particularly important category of model concepts. They often emerge • 암시적인 상태의 제약조건을, 명시적으로 표현할 경우 설계를 대폭 개선 implicitly, and expressing them explicitly can greatly improve a design. Sometimes constraints find a natural home in an object or method. A "Bucket" object must guarantee the invariant that it does not hold more than its capacity. • ex) “Bucket” 객체는 제한된 용량을 초과해서 저장할 수 있다는 제약조건 Figure 9.10. class Bucket { private float capacity; private float contents; public void pourIn(float addedVolume) { if (contents + addedVolume > capacity) { contents = capacity; } else { contents = contents + addedVolume; } } } A simple invariant like this can be enforced using case logic in each operation capable of changing contents. 제약조건을 함수로 분리 class Bucket { class Bucket { privateprivate float capacity; float capacity; privateprivate float contents; float contents; public public void pourIn(float addedVolume) { void pourIn(float addedVolume) { float volumePresent = contents + addedVolume; if (contents + addedVolume > capacity) { contents = constrainedToCapacity(volumePresent); contents = capacity; 문제점 } ✓ 한 메서드 안에 제약 조건을 다 담을 수 없을 경우 } else { contents =float constrainedToCapacity(float volumePlacedIn) { private contents + addedVolume; if (volumePlacedIn > capacity) ✓ 객체의 주된 책임을 수행하는데 필요하지 않은 정보를 return capacity; 해당 메소드에서 필요로 하는 경우 return volumePlacedIn; } } 12년 10월 29일 월요일
  • 11. 명시적인 제약 조건(2/2) • 제약 조건을 포함한 객체의 설계가 어딘가 잘못되어 있음을 나타내는 조짐 • 제약조건을 평가하려면 해당 객체의 정의에 적합하지 않은 데이터가 필요한 경우 Example Review: Overbooking Policy • 관련된 규칙이 여러 객체에 걸쳐 나타나며, 동일한 계층 구조에 속하지 않는 객체 간에 중복 또는 상속 관계를 강요하는 경우 In Chapter 1, we worked with a common shipping business practice: booking 10 percent more cargo than the transports could handle. (Experience has taught shipping firms that this overbooking compensates for last-minute cancellations, so their ships will sail nearly full.) • 설계와 요구사항에 관한 다양한 논의는 제약조건에 초첨을 맞춰 이뤄지지만 정작 구현 단계에서 절차적인 코드에 묻혀 This constraint on the association between Voyage and Cargo was made explicit, both in the 명시적으로 표현되지 않는 경우 diagrams and in the code, by adding a new class that represented the constraint. • 제약조건을 표현하는 새로운 클래스 추가 Figure 9.11. The model refactored to make policy explicit To review the code and reasoning in the full example, see page 17. Processes as Domain Objects 12년 10월 29일 월요일
  • 12. 도메인 객체로서의 프로세스 • 객체는 절차를 캡슐화해서 절차 대신 객체의 목표나 의도에 관해 생각하게 해야 한다 • 모델내에 프로세스가 나타나면 객체를 어색하게 설계하는 경향이 있음 • 프로세스를 도메인 객체로 표현하는 방법 • SERVICE는 프로세스를 명시적으로 표현 • 프로세스를 수행하는 방법이 한가지 이상일 경우 • 프로세스를 STRATEGY로 표현 • 명시적으로 표현해야할 프로세스와 숨겨야할 프로세스의 구분법 • 도메인 전문가가 이야기 하고 있는 프로세스인가? => 명시적으로 표현 12년 10월 29일 월요일
  • 13. SPECIFICATION • 모든 종류의 애플리케이션에는 규칙을 검사하는 Boolean 테스트 메서드가 존재 • ex) Invoice의 지불 기간이 지났는지를 검사하는 함수 public boolean isOverdue() { Date currentDate = new Date(); return currentDate.after(dueDate); } • 고객의 계정 상태에 따른 지불 유예기간 정책과 같은 복잡한 규칙이 추가 된다면? • 지불요청을 의미하는 Invoice의 명료함이 규칙에 묻혀 사라질 것 • 여러 도메인 클래스 및 하위 시스템에 의존성을 가지게 될 것 • 그렇다면 어떻게 할 것인가? • 응용 계층으로 분리? 12년 10월 29일 월요일
  • 14. SPECIFICATION • 명세를 위한 객체 • 다른 객체가 SPECIFICATION에 명시된 기준을 만족하는지 검사 I developed SPECIFICATION in collaboration with Martin Fowler (Evans and Fowler 1997). The simplicity of the concept belies the subtlety in application and implementation, so there is a lot of detail in this section. There will be even more discussion in Chapter 10, where the pattern is • 특별한 목적을 위한 명시적인 VALUE OBJECT extended. After reading the initial explanation of the pattern that follows, you may want to skim the "Applying and Implementing SPECIFICATIONS" section, until you are actually attempting to apply the pattern. • 규칙을 도메인 계층에 유지 Specification In all kinds of applications, Boolean test methods appear that are really parts of little rules. As long as they are simple, we handle them with testing methods, such as anIterator.hasNext() or anInvoice.isOverdue(). In an Invoice class, the code in isOverdue() is an algorithm that evaluates a rule. For example, • SPECIFICATION의 적용 public boolean isOverdue() { Date currentDate = new Date(); return currentDate.after(dueDate); • 업무 규칙이 ENTITY나 VALUE OBJECT가 맡고 있는 책임에 맞지 않는 경우 } But not all rules are so simple. On the same Invoice class, another rule, anInvoice.isDelinquent() would presumably start with testing if the Invoice is overdue, but • 규칙의 다양성과 조합이 도메인 객체의 기본의미를 압도하는 경우 that would just be the beginning. A policy on grace periods could depend on the status of the customer's account. Some delinquent invoices will be ready for a second notice, while others will be ready to be sent to a collection agency. The payment history of the customer, company policy on different product lines . . . the clarity of Invoice as a request for payment will soon be lost in • 규칙을 도메인 계층으로 분리한다면 도메인 코드가 더는 모델을 표현할 수 없음 the sheer mass of rule evaluation code. The Invoice will also develop all sorts of dependencies on domain classes and subsystems that do not support that basic meaning. At this point, in an attempt to save the Invoice class, a developer will often refractor the rule evaluation code into the application layer (in this case, a bill collection application). Now the rules have been separated from the domain layer altogether, leaving behind a dead data object that does not express the rules inherent in the business model. These rules need to stay in the domain layer, but they don't fit into the object being evaluated (the Invoice in this case). Not only that, but evaluating methods swell with conditional code, which make the rule hard to read. 12년 10월 29일 월요일
  • 15. SPECIFICATION 용도 • 3가지 용도는 개념적 차원에서는 동일함. • 검증: 객체가 어떤 요건을 충족시키거나 특정 목적으로 사용할 수 있는지 검사 • 선택: 컬렉션 내의 객체를 선택 • 요청 구축: 특정한 요구 사항을 만족하는 새로운 객체의 생성을 명시 12년 10월 29일 월요일
  • 16. 3. SPECIFICATION - 검증 possibly contradictory forms. The conceptual unity can be lost. Applying the SPECIFICATION pattern allows a consistent model to be used, even when the implementation may have to diverge. Validation • SPECIFICATION의 개념을 가장 직관적으로 사용하는 방식 The simplest use of a SPECIFICATION is validation, and it is the use that demonstrates the concept most straightforwardly. • 특정한조건에 부합하는지 여부를 판단하여, 결과를 기반으로 특정 행위를 수행 Figure 9.14. A model applying a SPECIFICATION for validation public boolean accountIsDelinquent(Customer customer) { Date today = new Date(); Specification delinquentSpec = new DelinquentInvoiceSpecification(today); Iterator it = customer.getInvoices().iterator(); while (it.hasNext()) { Invoice candidate = (Invoice) it.next(); if (delinquentSpec.isSatisfiedBy(candidate)) return true; } class DelinquentInvoiceSpecification extends return false; InvoiceSpecification { } private Date currentDate; // An instance is used and discarded on a single date class DelinquentInvoiceSpecification extends InvoiceSpecification { private Date currentDate; public DelinquentInvoiceSpecification(Date currentDate) { // An instance is used and discarded on a single date this.currentDate = currentDate; } public DelinquentInvoiceSpecification(Date currentDate) { this.currentDate = currentDate; public boolean isSatisfiedBy(Invoice candidate) { } int gracePeriodboolean isSatisfiedBy(Invoice candidate) { public = int gracePeriod = candidate.customer().getPaymentGracePeriod(); candidate.customer().getPaymentGracePeriod(); Date firmDeadline firmDeadline = DateUtility.addDaysToDate(candidate.dueDate(), gracePeriod); Date = return currentDate.after(firmDeadline); DateUtility.addDaysToDate(candidate.dueDate(), } gracePeriod); } return currentDate.after(firmDeadline); } } 12년 10월 29일 월요일
  • 17. SPECIFICATION - 선택 (1/3) "SELECT * FROM INVOICE, CUSTOMER" + " WHERE INVOICE.CUST_ID = CUSTOMER.ID" + " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" + • 특정한 조건을 기반으로 객체 컬렉션의 일부를 선택 " < " + SQLUtility.dateAsSQL(currentDate); } public Set selectSatisfying(InvoiceSpecification spec) { Set results = new HashSet(); Iterator it = invoices.iterator(); SPECIFICATIONS mesh smoothly with REPOSITORIES, which are the building-block mechanisms while (it.hasNext()) { providing query access to domain objects and encapsulating the interface to the database (s Invoice candidate = (Invoice) it.next(); Figure 9.15). if (spec.isSatisfiedBy(candidate)) results.add(candidate); } } return results; Figure 9.15. The interaction between REPOSITORY and SPECIFICATIO • SPECIFICATION을 유지하며 관계형 데이터 베이스에 질의 • 맵핑 프레임워크를 사용하지 않는 경우 public String asSQL() { return "SELECT * FROM INVOICE, CUSTOMER" + " WHERE INVOICE.CUST_ID = CUSTOMER.ID" + " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" + " < " + SQLUtility.dateAsSQL(currentDate); } 문제점 ✓ 테이블 구조가 Domain Layer에 노출 Now this design has some problems. Most important, the details of the table structure have into the DOMAIN LAYER; they should be isolated in a mapping layer that relates the domain ob 12년 10월 29일 월요일
  • 18. SPECIFICATION - 선택 (2/3) • Double Dispatch 적용 public class InvoiceRepository { public Set selectWhereGracePeriodPast(Date aDate){ //This is not a rule, just a specialized query String sql = whereGracePeriodPast_SQL(aDate); ResultSet queryResultSet = SQLDatabaseInterface.instance().executeQuery(sql); return buildInvoicesFromResultSet(queryResultSet); } public String whereGracePeriodPast_SQL(Date aDate) { return "SELECT * FROM INVOICE, CUSTOMER" + " WHERE INVOICE.CUST_ID = CUSTOMER.ID" + " AND INVOICE.DUE_DATE + CUSTOMER.GRACE_PERIOD" + " < " + SQLUtility.dateAsSQL(aDate); } 문제점 public Set selectSatisfying(InvoiceSpecification spec) { return spec.satisfyingElementsFrom(this); ✓체납 개념을 구성하는 본질적인 규칙은 SPECIFICATION에 명시 } 되었으나, 규칙을 깔끔하게 모으지 못함 } public class DelinquentInvoiceSpecification { // Basic DelinquentInvoiceSpecification code here public Set satisfyingElementsFrom(InvoiceRepository repository) { //Delinquency rule is defined as: // "grace period past as of current date" return repository.selectWhereGracePeriodPast(currentDate); } } 12년 10월 29일 월요일
  • 19. SPECIFICATION - 선택 (3/3) • REPOSITORY를 일반화 상태로 유지 public class InvoiceRepository { public Set selectWhereDueDateIsBefore(Date aDate) { String sql = whereDueDateIsBefore_SQL(aDate); ResultSet queryResultSet = SQLDatabaseInterface.instance().executeQuery(sql); return buildInvoicesFromResultSet(queryResultSet); } public String whereDueDateIsBefore_SQL(Date aDate) { return "SELECT * FROM INVOICE" + " WHERE INVOICE.DUE_DATE" + " < " + SQLUtility.dateAsSQL(aDate); } 문제점 public Set selectSatisfying(InvoiceSpecification spec) { return spec.satisfyingElementsFrom(this); ✓성능 저하 발생 } ✓성능 vs. 책임분할에 대한 검증 필요 } public class DelinquentInvoiceSpecification { //Basic DelinquentInvoiceSpecification code here public Set satisfyingElementsFrom(InvoiceRepository repository) { Collection pastDueInvoices = repository.selectWhereDueDateIsBefore(currentDate); Set delinquentInvoices = new HashSet(); Iterator it = pastDueInvoices.iterator(); while (it.hasNext()) { Invoice anInvoice = (Invoice) it.next(); if (this.isSatisfiedBy(anInvoice)) delinquentInvoices.add(anInvoice); } return delinquentInvoices; } } 12년 10월 29일 월요일
  • 20. SPECIFICATION - 요청 구축 • SPECIFICATION을 만족하는 객체를 생성 • SPECIFICATION을 사용하지 않고 Generator을 사용할 경우 • Generator 내에 행위를 암시적으로 규정해야 함 • SPECIFICATION을 사용할 경우 • Generator의 구현을 인터페이스로부터 분리 (암시적인 규정) • 개발자가 세부사항을 이해하지 않고도 결과물을 예측 가능 • 생성 요청을 하는 코드는 클라이언트에 있기 때문에 더 유연한 개선이 가능 • SPECIFICATION을 통해 생성된 결과물을 검증 가능 12년 10월 29일 월요일
  • 21. 요약 • 도메인의 숨겨진 개념을 명확하게 인식하는 방법 • 언어에 귀를 기울여라 • 어색한 부분을 조사하라 • 모순점에 대해 깊이 고민하라 • 시도하고 또 시도하라 • 객체지향 설계 입문자가 명확한 개념으로 인식하기 힘든 세가지 범주 • 명시적인 제약조건 • 도메인 객체로서의 프로세스 • SPECIFICATION 12년 10월 29일 월요일