계산 된 가치와 간단한 읽기 – 도메인 기반 디자인에 대한 잔인한 고통!


9

내가 계속 직면하는 문제는 데이터 저장소에 대해 효율적으로 작업하면서 도메인 논리에 의해 구동되는 계산 된 값을 처리하는 방법입니다.

예:

서비스를 통해 저장소에서 제품 목록을 반환합니다. 이 목록은 클라이언트가 보낸 요청 DTO의 페이지 매김 정보로 제한됩니다. 또한 DTO는 정렬 매개 변수 (클라이언트 친화적 열거 형)를 지정합니다.

간단한 시나리오에서는 모든 것이 잘 작동합니다. 서비스는 페이징 및 정렬 표현식을 리포지토리로 보내고 리포지토리는 DB에 효율적인 쿼리를 발행합니다.

그러나 도메인 모델에서 메모리에 생성 된 값을 정렬해야 할 때 모든 것이 고장납니다. 예를 들어 Product 클래스에는 비즈니스 논리를 기반으로 bool을 반환하는 IsExpired () 메서드가 있습니다. 이제는 저장소 수준에서 정렬하고 페이지를 지정할 수 없습니다. 모두 메모리에서 비효율적이며 서비스는 이러한 매개 변수를 언제 저장소에 발행하고 언제 정렬 / 페이징을 수행해야하는지에 대한 복잡성을 알아야합니다. 그 자체.

나에게 이해가되는 유일한 패턴은 db에 엔티티 상태를 저장하는 것입니다 (IsExpired ()를 읽기 전용 필드로 만들고 저장하기 전에 도메인 논리를 통해 업데이트하십시오). 이 로직을 별도의 "read model / dto"및 "reporting"리포지토리로 분리하면 모델을 원하는 것보다 더 빈약하게 만듭니다.

BTW, 이와 같은 계산에 대해 본 모든 예제는 실제로 메모리 내 처리 및 장기적으로 훨씬 덜 효율적이라는 사실에 의존하는 것처럼 보입니다. 어쩌면 나는 조기에 최적화하고 있지만 그것은 나에게 맞지 않습니다.

DDD와 관련된 거의 모든 프로젝트에서 공통적이라고 확신하기 때문에 다른 사람들이 이것을 어떻게 처리했는지 듣고 싶습니다.

답변:


3

동일한 데이터 모델의 서로 다른 두 개의 도메인 모델을 사용하면 도메인이 무해하다고 생각하지 않습니다. 빈혈 도메인 모델은 종종 변경되는 비즈니스 로직이 서비스 계층 (또는 UI 계층)에서 도메인에서 숨겨지는 모델입니다.

명령 및 쿼리 도메인 모델의 분리는 종종 필요하며 CQRS (Command Query Responsibility Segregation)에서 Google을 사용할 수있는 좋은 약어입니다.

도메인 모델 패턴, Udi Dahan 사용

과거에는 명령과 쿼리를 모두 처리하는 단일 영구 객체 모델을 만드는 데 "성공적"이었지만 시스템의 각 부분이 다른 방향으로 모델을 조정했기 때문에 크기를 조정하는 것이 매우 어려웠습니다.

개발자가 비즈니스에서 실제로 요구하는 것보다 더 까다로운 요구 사항을 수행하는 경우가 종종 있습니다. 정보를 사용자에게 보여주기 위해 도메인 모델 엔터티를 사용하기로 결정한 것은 바로 그러한 예입니다.

[...]

기억해야 할 나이가 많은 사람들을 위해 COM + 사용에 관한 모범 사례를 통해 읽기 전용 및 읽기 / 쓰기 논리를위한 별도의 구성 요소를 만들었습니다. 우리는 10 년 후 Entity Framework와 같은 새로운 기술을 사용하지만 동일한 원칙을 계속 유지합니다.

Akka 행위자와 기능적 도메인 모델을 갖춘 CQRS, Debasish Ghosh

Greg Young은 DDD 및 CQRS에 대한 훌륭한 세션을 제공했습니다. 2008 년에 그는 "보고, 검색 및 거래 행동에는 단일 모델이 적합하지 않다"고 말했다. 명령을 처리하고 사용자 쿼리 및 보고서를 제공하는 다른 모델에 변경 사항을 제공하는 두 가지 모델이 있습니다. 응용 프로그램의 트랜잭션 동작은 집계 및 리포지토리의 풍부한 도메인 모델을 통해 실행되는 반면 쿼리는 비정규 화 된 데이터 모델에서 직접 제공됩니다.

CQRS, 마틴 파울러

CQRS가 도입 한 변경 사항은 해당 개념 모델을 업데이트 및 표시를 위해 별도의 모델로 분할하는 것입니다. CommandQuerySeparation의 용어에 따라 각각 Command 및 Query라고합니다. 이론적 근거는 많은 문제, 특히 더 복잡한 영역에서 명령과 쿼리에 대해 동일한 개념적 모델을 가지면 더 잘 수행되지 않는보다 복잡한 모델로 이어진다는 것입니다.

요컨대, 명령 모델이 만기를 처리하고이를 데이터베이스로 전달하도록하는 아이디어는 절대적으로 좋습니다. 위의 첫 번째 기사를 읽으면 비슷하지만 더 복잡한 시나리오가 나타납니다.


2

사양

귀하가 이미 답변을 수락했지만 DDD에 대해 문의했으며 이에 대한 정확한 일치는 Evans에서 '사양'이라고합니다.
Google 도서 링크 직접 연결
해당 링크가 작동하지 않는 경우 다음 결과에서 도서를 확인
책이 있다면 226 페이지입니다.

227 페이지에는 유효성 검사, 삭제, 새 특수 객체 작성의 세 가지 용도가 있습니다. 당신은 '선택'입니다-IsExpired.

'specificaiton'개념에 대한 또 다른 점은 효율성을 위해 메모리 내 객체에서 작동하려면 하나의 코드 버전이 필요하고 먼저 가져 오지 않고도 저장소를 효율적으로 쿼리하기 위해 다른 버전의 코드가 필요하다는 점을 인정한다는 것입니다 모든 객체를 메모리에 넣습니다.

단순한 세계에서 이것은 저장소에 SQL 버전을, 모델에 객체 버전을 넣는 것은 물론 단점이 있음을 의미합니다. 논리는 2 곳 (나쁜 사람은 그 장소를 업데이트하는 것을 잊어 버릴 것입니다)에 있으며 저장소에 도메인 논리가 있습니다.

따라서 두 가지 논리 세트를 모두 사양에 넣는 것이 정답입니다. 분명히 메모리 내 버전이지만 리포지토리 버전도 있습니다. 예를 들어 n-hibernate를 사용하는 경우 리포지토리 버전에 내장 된 쿼리 언어를 사용할 수 있습니다.

그렇지 않으면 스펙 오브젝트에서 사용되는이 스펙에 대한 특수 저장소 메소드를 작성해야합니다. 사양과 일치하는 객체의 콜레시 톤 호출은 리포지토리가 아닌 사양을 통해 수행됩니다. 그리고 적어도 코드는 미래의 관리자에게 '나는 두 곳, 나는 그것을 잊지 마십시오'라고 비명을 지 릅니다. 231-232 페이지에 아주 비슷한 문제를 해결하는 훌륭한 예가 있습니다.

이 사양은 DDD '순도'의 '허용 된'누출 / 슬립 페이지입니다. 여전히 다양한 목적으로 귀하의 요구를 충족시키지 못할 수도 있습니다. 예를 들어, ORM은 잘못된 SQL을 생성 할 수 있습니다. 여분의 코딩이 너무 많을 수 있습니다. 따라서 스펙에 SQL을 넣는 것과 거의 비슷한 저장소 메소드를 호출해야 할 수도 있습니다. 물론 나쁜 것입니다. 그러나 프로그램이 합리적인 속도로 작동해야한다는 것을 잊지 마십시오. DDD 순도 상을 수상 할 필요는 없습니다. 따라서 데이터 스토어를 전환한다는 사실은 프로그램을 통틀어 구식의 고뇌를 의미 할 수 있습니다. 또한 나쁜 것. 그러나 느린 (일명 SUCKing) 프로그램만큼 나쁘지는 않습니다. 다양한 DB에서 즉시 실행되는 것이 현실이라면 각 사양의 각 데이터 저장소에 대한 비즈니스 규칙을 복제하게 될 것입니다. 최소한 문제에 손가락을 대고 리포지토리를 바꿀 때 전략 패턴을 사용할 수 있습니다. 그러나 특정 DB를 사용하고 있다면 이미 기억하십시오.야 그니.

CQRS 관련 : 위에서 pdr에 의한 Fowler의 인용문은 여기서도 여전히 유효합니다. "명령과 쿼리에 대해 동일한 개념 모델을 갖는 것은 좋지 않은 복잡한 모델로 이어집니다 ." 그러나 개발 및 유지 관리 측면에서 보면 훨씬 비쌉니다. 다른 공급 업체와 경쟁하는 패키지 공급 업체 인 경우 비용이 지불 될 수 있습니다. 한 고객을 위해 맞춤형 LOB 앱을 작성하는 경우 완벽한 촬영이 적합하지 않습니다. 완전 또는 대부분 이중 모델을 갖는 가치가 추가 노력의 가치가 있는지 여부를 결정해야합니다. 사양하나의 모델의 (개발) 속도와 단순성을 통해 프로그램을 필요로하는 프로그램의 일부만으로 분리 할 수 ​​있기 때문에 좋은 절충안입니다. 행운을 빕니다!


완벽하게 이해됩니다. 나는 총알을 물고 에반스의 책을 읽어야한다고 생각합니다. :-) 나는이 개념에 대해 깊이 이해하면 실제로 당신을 마비시킬 수 있다고보고 있습니다!
drogon

0

isExpired가 true인지 아닌지를 결정하는 비즈니스 로직이 무엇인지에 대해 의문을 가질 것입니다. 이 논리는 데이터 모델이있는 쿼리에 의해 수행 될 수 있습니까? 그렇다면 제품을 특정 방식으로 요청할 때 "isExpired"논리를 사용하기에 충분한 저장소를 지능적으로 만들 수 있습니까? 그렇지 않은 경우 데이터 모델을 다시 검사해야 할 수 있습니다.

DDD는 리포지토리가 어리석은 것이 아니라 도메인이 리포지토리와 대화하는 방법을 알아야한다는 것을 의미합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.