Source

09 암시적인 개념을 명확하게


p.283 “SPECIFICATION의 개념은 단순해서 이를 적용하거나 구현할 때 미묘한 사항들을 착각할 여지 가 있으므로 이번 절에서는 가급적 자세하게 설명하겠다.”

p.283 “SPECIFICATION을 확장하는 10장에 서는 더 다양한 문제를 살펴보겠다.”

p.284 “모든 종류의 애플리케이션에는 대수롭지 않은 규칙을 검사하는 Boolean 테스트 메서드가 있 다.”

p.284 “규칙이 모두 이렇게 단순하기만 한 것은 아니다.”

p.284 “계정 상태에 따라 달라질 수 있다. 일부 체납된 송장의 경우 2차 통보가 준비 중인 반면, 일 부 송장은 미수금 처리 대행 회사로 넘길 준비가 돼 있을 것이다.”

p.284 “지불 요청을 의미하는 Invoice의 명료함이 규칙을 평 가하는 코드 덩어리에 묻혀 이내 사라져 버릴 것”

p.284 “Invoice는 근본적인 의미를 지원하지 않는 도메인 클래스와 하위시스템에 대해 의존성을 갖게 될 것”

p.284 “규칙을 평가하는 코드를 리팩터링해 서 응용 계층(이 경우에는 청구서 수집 애플리케이션)으로 옮길 것이다. 이제 업무 모델에 내재 된 규칙을 표현하지 않는 쓸모 없는 데이터 객체를 뒤로한 채 규칙은 도메인 계층과 완전히 분 리된다.”

p.284 “규칙을 도메인 계층 내에 유지할 필요가 있지만 규칙을 통해 평가하려는 객체(이 경우 Invoice)에 규칙을 두기에는 적절하지 않다”

p.284 “규칙을 평가하는 메서드는 조건 코드 로 팽창할 것이고 결국 규칙에 대한 가독성은 떨어지고 만다.”

p.285 “규칙은 술어(predicate)로 표현할 수 있다. 술어는 “true” 또는 “false”로 평가되는 함수이며, 더 복잡한 규칙을 표현하기 위해 “AND”와”OR”와 같은 연산자를 사용해서 결합할 수 있다.”

p.285 “우리가 논리 패러다임을 사용하고 있었다면 말이다.”

p.285 “논리를 객체 안에 구현하는 것은 커다란 작업 이라는 점”

p.285 “업무 규칙이 ENTITY VALUE OBJECT가 맡고 있는 책임에 맞지 않고 규칙의 다양성 과 조합이 도메인 객체의 기본 의미를 압도할 때가 있다.”

p.285 “그렇다고 규칙을 도메인 계층으로부터 분리한다면 도메인 코드가 더는 모델을 표현할 수 없어서 상황이 더 악화된다.”

p.285 “순수한 객체를 이용해 술어의 개념을 완전히 구현하기란 매우 성가신 작업이다. 또한 이 방법은 너무 일반적이라서 논리 프로그래밍과 같은 특별한 설계만큼 의도를 충분히 전달하지 못한다.”

p.285 “술어의 개념을 차용해서 Boolean 결과를 내는 특별한 객체를 만들 수 있다. 감당할 수 없을 정도로 덩치가 커진 테스트 메서드는 독립적인 객체로 발전할 것”

p.286 “새로운 객체는 명세(specification)에 해당한다. SPECIFICATION은 다 른 객체에 대한 제약조건을 기술하며, 제약조건은 존재할 수도 존재하지 않을 수도 있다.”

p.286 “가장 기본적인 개념은 다른 객체가 SPECIFICATION에 명시된 기준을 만족하는지 검사할 수 있다는 것”

p.286 “규칙이 복잡한 경우 논리 연산자를 사용해 술어를 결합하는 것과 동일 한 방식으로 단순한 명세들을 결합하도록 개념을 확장할 수 있다.”

p.287 “SPECIFICATION을 이용하면 규칙을 도메인 계층에 유지할 수 있다. 아울러 완전한 객체 를 사용해서 규칙을 표현하므로 설계가 모델을 더욱 명확하게 반영할 수 있다.”

p.287 “FACTORY는 고 객의 계정이나 기업 정책 데이터베이스와 같은 외부 정보를 사용해 SPECIFICATION을 설정 할 수 있다.”

p.287 “Delinquent Invoice Specification을 생성하고 Invoice를 평가한 후 제거하므로 특정한 평가 일자를 Delinquent Invoice Specification 안에 포함할 수 있다.”

SPECIFICATION의 적용과 구현


p.288 “검증(validation), 선택(selection), 요청 구축(building to order)이라는 SPECIFICATION의 세 가지 용도는 개념적인 차원에서 동일하다.”

검증


p.289 “판매원이 고객에게 체납 청구서를 보낸 경우 붉은 색으로 표시하고 싶다고 가정하자.”

선택(또는 질의)


p.289 “SPECIFICATION을 사용해야 하 는 다른 경우는 특정한 조건을 기반으로 객체 컬렉션의 일부를 선택하는 것이다.”

p.289 “체납된 송장을 보유한 모든 고객 목록을 나열하는 요구사항이 있다고 해보자.”

p.290 “다음과 같이 Invoice Repository에 SPECIFICATION을 기반으로 Invoice를 선택하는 일반화된 메서드를 구현할 수 있다.”

p.290 “일반적인 업무 시스템이 라면 데이터를 관계형 데이터베이스에 저장할 것이다.그리고 이전장에서 지적한 것처럼 상이한 기술과 교차되는 지점에서는 모델의 초점을 잃어버리기 쉽다.”

p.290 “SPECIFICATION의 모델은 유지하면 서도 모델의 초점을 잃어버리는 문제를 해결하려면 관계형 데이터베이스의 능력을 어떻게 활용 할 수 있을까?”

p.290 “SQL을 사용하면 매우 자연스러운 방식으로 SPECIFICATION을 작성할 수 있다.”

p.290 “Invoice Specification에 메서드 하나를 추가하고 Delinquent Invoice Specification 하위 클래스에서 이 메서드를 구현한다.”

p.291 “가장 중요한 문제는 세부적인 테이블 구조가 DOMAIN LAYER에 노출된다는 점이다.”

p.291 “테이블 구조는 도메인 객체와 관계형 테이블 간의 관계를 책임지 는 매핑 계층 내부로 격리해야 한다.”

p.292 “일부 객체지향 매핑 프레임워크에서는 질의문을 모델 객체와 속성을 사용해 표현하는 방법을 제공하며, 인프라스트럭처 계층에서 실제로 실행될 SQL문을 생성한다. 이러한 프레임워크를 이용하면 두 마리 토끼를 한꺼번에 잡을 수 있다.”

p.292 “REPOSITORY에 선택(selection) 규칙을 포함하 지 않으려면 질의문을 좀더 일반화된 방식으로 표현해야 하며, 이러한 질의는 규칙을 담지 않지 만 규칙을 만들어내는 컨텍스트에서 결합되거나 그러한 컨텍스트에 위치할 수 있다(여기서는 DOUBLE DISPATCH 패턴을 사용한다).”

Double Dispatch?

selectSatisfying(InvoiceSpecification spec)에서 this를 전달하도록 구현하는 것이 Double Dispatch 패턴이라고 볼 수 있다.

p.292 “Delinquent Invoice Specification은 다음과 같이 구현된다.”

p.293 “SQL문은 REPOSITORY 내부에 위치하며 SPECIFICATION은 어떤 질의문을 사용 해야 하는지 제어한다.”

p.293 “이 방식 은 수용할 만하지만 체납된 Invoice에 대한 기간 초과 Invoice의 상대적인 개수에 따라서는 REPOSITORY 메서드를 좀더 일반화된 상태로 유지할 수 있는 중재안이 SPECIFICATION을 좀더 자기 설명적(self-explanatory)으로 유지하면서도 더 나은 성능을 보일 수 있다.”

Repository 내의 특화된 쿼리를 보다 일반화하고 Specification으로서의 필요한 규칙들은 Specification 쪽으로 조금 더 가져오는 방식

p.294 “이 코드에서는 더 많은 양의 Invoice를 메모리로 적재한 후 메모리상에서 원하는 Invoice를 선 택해야 하므로 성능 저하를 겪는다.”

p.294 “이것이 더 좋은 책임의 분할을 위해 수용 가능한 비용인가는 전적으로 상황에 따라 달라진다.”

p.294 “성능을 향상시키거나 보안을 강화하고자 질의문을 서버상의 저장 프로시저(stored procedure)로 구현할 수도 있다. 이 경우 SPECIFICATION은 저장 프로시저에 전달할 수 있는 매개변수만 포함할 것이다.”

p.294 “그럼에도 각 구현 방법에 포함된 모델 간에는 차이가 없다. 모델에 의 해 특수하게 제약을 받는 경우를 제외하면 모델의 구현 방법을 자유롭게 선택할 수 있다.”

p.294 “이러한 논의는 SPECIFICATION과 데이터베이스를 결합하는 데 따르는 표면상의 문제만을 다루는 것에 불과하며, 지면상 관련된 모든 고려사항을 다루지는 않겠다.”

데이터베이스가 아닌 다른 값 (예를 들면 외부 API 호출의 결과 값 혹은 요청의 Context로부터 온 값)을 기반으로 Specification이 구현되어야 한다면...?

선언적인 형식의 설계


SPECIFICATION을 선언적인 형식으로 확장하기