복잡한 도메인 중심 애플리케이션에서 기본 CRUD 작업에 대한 DDD 접근


9

우리 회사는 웹 애플리케이션을 처음부터 다시 작성하고 있습니다. 금융 업계에서 복잡한 도메인을 가진 대기업 수준의 응용 프로그램입니다.

지속성을 위해 ORM (Entity Framework)을 사용하고 있습니다.

본질적으로 응용 프로그램의 절반은 사용자로부터 원시 데이터를 수집하고 저장하는 데 중점을 둔 다음 실제 도메인 논리를 대부분 포함하는 응용 프로그램의 나머지 절반은 원시 데이터를 사용하여 원본과 크게 다른 도메인 그림을 만듭니다. 원시 입력을 가져 와서이를 calc 엔진에 전달하고 calc를 실행 한 다음 결과를 뱉어내어 사용자에게 표시합니다.

계층을 사용하는 DDD 방식에서는 CRUD 작업이 도메인 계층을 통과하는 것처럼 보입니다. 그러나 적어도 우리의 경우에는 이치에 맞지 않는 것 같습니다.

예를 들어 사용자가 편집 화면으로 이동하여 투자 계정을 변경하면 화면의 필드는 나중에 계산에 사용되는 도메인 표현이 아니라 데이터베이스에 저장된 정확한 필드입니다. 편집 화면에 데이터베이스 표현 (원시 입력)이 필요할 때 왜 투자 계정의 도메인 표현을로드해야합니까?

사용자가 투자 계정 화면에서 "완료"를 클릭하고 컨트롤러에 대한 POST가 완료된 후, 컨트롤러는 이제 저장해야하는 투자 계정의 데이터베이스를 거의 정확하게 나타냅니다. 그러나 어떤 이유로 컨트롤러의 모델을 데이터베이스 모델 (Entity Framework 모델)에 직접 매핑하는 대신 도메인 표현을로드하여 수정해야합니까?

본질적으로 데이터 모델을 도메인 모델에 매핑하고 있으므로 데이터 모델에 다시 매핑하여 유지할 수 있습니다. 어떻게 말이 되나요?

답변:


9

Ok 양식 작성 게시물을 EF 객체에 직접 매핑 한 다음 계정에 저장 한 계정 생성 페이지를 구현했다고 가정 해 봅시다.

데이터베이스에 완전히 잘못된 데이터가 입력되는 것을 방지하는 다양한 제한 사항이 있다고 가정합니다. 계정에는 항상 고객 등이 있습니다.

모든 것이 잘 작동하는 것 같습니다. 그러나 비즈니스는 새로운 규칙을 만듭니다.

  • 목요일에 만든 계정은 2 %의 보너스 이율을받습니다. (이자율이 계정 필드 중 하나라고 가정)

이제이 로직을 어딘가에 배치해야하며이를 넣을 도메인 객체가 없습니다.

DDD는 항상 이런 종류의 규칙을 가지고 있다고 가정하며 아마도 그렇게 할 것입니다. 계정을 만들려면 다양한 검사, 감사 로그 등이 있어야만 'db에 행을 쓰지'않아야합니다.

추가 논리가 포함 된 지속성 또는 MVC 컨트롤러가 없다고 가정하고 도메인을 계획하십시오. 모든 요구 사항 을 캡처하고 모두 도메인 모델에 있는지 확인하십시오 .


3
그것을 넣는 좋은 방법입니다. DB 세부 사항과 혼합 된 비즈니스 규칙을 찾는 것이 싫습니다. +1
candied_orange

좋은 점이지만 이러한 유효성 검사 규칙이 사용자 입력을 만들고 업데이트하는 동안에 만 적용되는 경우 그런 다음 사용자 입력이 있으면 계산을 실행할 때 생성되는 모델은 완전히 다른 모델입니다. 투자 계정에 대한 두 가지 도메인 모델이 있어야합니까? 하나는 사용자에 대한 원시 입력의 CRUD 조작과 다른 입력이 계산에 사용되는 도메인 모델을 작성하는 데 사용되는 경우에 대한 것입니까?
wired_in

내 질문을 혼란스럽게합니다. 완전한 예를 제시해야합니다. 도메인 논리가 있으면 도메인 개체로 이동해야합니다. 그렇다고 나중에 첫 번째 도메인에서 다른 도메인 개체를 만들 수 없다는 의미
Ewan

복잡한 계산 엔진을 상상해보십시오. 계산을 실행하는 데 필요한 입력 중 하나는 투자 계정이지만 모든 투자 계정은 calc 엔진에 대한 일정 기간 동안의 수입원입니다. 투자 계정의이 도메인 모델은 사용자가이 투자 계정에 입력 한 원시 입력과 완전히 다릅니다. 그러나 사용자가 이름, 현재 값 등과 같은 기본 입력을 입력 할 때 여전히 유효성 검증 논리가 필요하지만 calc 엔진이 사용하는 모델과는 관련이 없어야합니다. 여기 투자 계정에 대한 두 가지 도메인 모델이 있습니까?
wired_in

..... 또는 도메인에 투자 계정 모델이있는 것은 CRUD 작업에 과잉이며 사용 된 유효성 검사기 속성 또는 무언가가 있어야합니다
wired_in

7

어떻게 말이 되나요?

짧은 대답 : 그렇지 않습니다 .

더 긴 대답 : 도메인 모델을 개발하기위한 헤비급 패턴은 데이터베이스에 불과한 솔루션 부분에는 적용되지 않습니다.

우디 다한 흥미로운 관찰했다 5 월 도움이 명확히 있음

Dahan은 서비스에 일종의 기능과 데이터가 모두 있어야한다고 생각합니다. 데이터가 없으면 함수일뿐입니다. 데이터에서 CRUD 작업을 수행하는 것이 전부라면 데이터베이스입니다.

결국 도메인 모델의 요점은 데이터에 대한 모든 업데이트가 현재 비즈니스 불변을 유지하도록하는 것입니다. 또는 달리 말하면 도메인 모델은 레코드 시스템 역할 을하는 데이터베이스 가 올바른지 확인해야합니다.

CRUD 시스템을 다룰 때는 일반적으로 데이터 기록 시스템이 아닙니다. 현실 세계는 기록의 책이며, 데이터베이스는 현실 세계의 단지 로컬로 캐시 된 표현입니다.

예를 들어, 이메일 주소 나 정부가 발행 한 식별 번호와 같이 사용자 프로필에 나타나는 대부분의 정보는 비즈니스 외부에 존재하는 진실의 원천을 가지고 있습니다. 다른 사람의 메일 관리자는 이메일 주소를 할당하고 취소하지 않습니다. 앱. 앱이 아닌 SSN을 할당하는 것은 정부입니다.

따라서 일반적으로 외부 세계에서 오는 데이터에 대해서는 도메인 유효성 검사 를 수행하지 않습니다 . 데이터가 올바르게 구성되고 적절하게 위생 처리 되었는지 확인하기위한 점검이있을 수 있습니다 . 그러나 귀하의 데이터는 아닙니다. 도메인 모델에는 거부권이 없습니다.

계층을 사용하는 DDD 방식에서는 CRUD 작업이 도메인 계층을 통과하는 것처럼 보입니다. 그러나 적어도 우리의 경우에는 이치에 맞지 않는 것 같습니다.

데이터베이스가 장부 인 경우에 맞습니다 .

Ouarzy는 이런 식으로 그것을 넣어 .

많은 레거시 코드를 작업하면서 도메인 내부와 외부를 식별하는 일반적인 실수를 관찰합니다.

데이터 모델 주위에 비즈니스 로직이없는 경우에만 애플리케이션을 CRUD로 간주 할 수 있습니다. 이 경우에도 데이터 모델은 도메인 모델이 아닙니다. 비즈니스 로직이 없기 때문에이를 관리하기 위해 추상화가 필요하지 않으므로 도메인 모델이 없습니다.

도메인 모델을 사용하여 도메인 내부에 속한 데이터를 관리합니다. 도메인 외부의 데이터는 이미 다른 곳에서 관리되고 있습니다. 우리는 단지 사본을 캐싱하고 있습니다.

Greg Young은 창고 시스템 을 다른 곳 (예 : 창고 층)에있는 솔루션의 기본 그림으로 사용합니다. 그가 설명하는 구현 방식은웨어 하우스에서 수신 한 메시지를 캡처하는 논리 데이터베이스와 메시지 분석에서 도출 된 결론을 캐싱하는 별도의 논리 데이터베이스와 비슷합니다.

어쩌면 여기에 두 가지 맥락이 있습니까? 각각 다른 모델로investment account

아마도. 다른 수하물과 함께 제공되는 것이 확실하지 않기 때문에 제한적인 컨텍스트로 태그를 지정하는 것을 꺼려합니다. 두 가지 컨텍스트가있을 수 있습니다. 아직 선택하지 않은 유비쿼터스 언어의 미묘한 차이가있는 하나의 컨텍스트 일 ​​수 있습니다.

가능한 리트머스 테스트 :이 스펙트럼을 다루기 위해 두 명의 도메인 전문가가 필요하거나 여러 가지 방법으로 구성 요소에 대해 이야기하는 도메인 전문가가 필요한 도메인 전문가 수 기본적으로 Conway의 법칙을 거꾸로하여 얼마나 많은 제한적 맥락을 가지고 있는지 추측 할 수 있습니다.

제한된 컨텍스트가 서비스와 일치한다고 생각하면 더 쉬울 수 있습니다.이 두 가지 기능을 독립적으로 배포 할 수 있습니까? 그렇습니다. 두 가지 맥락이 있습니다. 그러나 동기화 상태를 유지해야하는 경우 그 중 하나 일 수 있습니다.


유효성 검사 및 기본 논리가 있지만 투자 계정의 원시 입력을 작성 / 업데이트 할 때만 적용됩니다. 그런 다음 calc 엔진의 입력으로 사용할 때 훨씬 더 풍부한 투자 계정 모델을 사용합니다. 어쩌면 여기에 두 가지 맥락이 있습니까? 각각 다른 투자 계좌 모델이 있습니다 '
wired_in

나는 몇 년 후에 이것으로 돌아 왔으며, 당신의 의견은 어떤 이유로 든 이전보다 더 많이 울려 퍼지고 있습니다. 여기에 좋은 것들이 많이 있지만 나를 위해 한 가지를 분명히 할 수 있습니까? "도메인 모델의 요점은 결국 데이터에 대한 모든 업데이트가 현재 비즈니스 불변을 유지하도록하는 것입니다." 이는 정보를 저장 / 업데이트하는 앱 부분에 적용됩니다. 다른 부분은 단지 계산 엔진입니다. 데이터를 입력으로 표현하고 결과를 뱉어냅니다. 그것은 도메인 모델의 일부가 아닌가? 저장된 데이터에 영향을 미치지 않기 때문에?
wired_in

2

도메인에서는 데이터베이스가 존재한다는 것을 알 필요가 없습니다.

귀하의 도메인은 비즈니스 규칙에 관한 것입니다. 데이터베이스를 만든 회사가 비즈니스를 중단 할 때 생존해야하는 것들. 즉, 회사가 생존하기를 원한다면. 이러한 규칙이 데이터 유지 방법을 변경 한 것을 신경 쓰지 않으면 정말 좋습니다.

데이터베이스 세부 사항이 존재하고 처리해야합니다. 그들은 다른 곳에 살아야합니다. 그것들을 경계를 가로 질러 놓으십시오. 경계를 넘어 의사 소통하는 방법을 신중하게 통제하십시오.

Bob 아저씨는 데이터를 넣을 대상에 대해 다음과 같이 말합니다.

일반적으로 경계를 넘는 데이터는 간단한 데이터 구조입니다. 원하는 경우 기본 구조체 또는 간단한 데이터 전송 개체를 사용할 수 있습니다. 또는 데이터는 단순히 함수 호출에서 인수가 될 수 있습니다. 또는 해시 맵으로 묶거나 객체로 구성 할 수 있습니다.

중요한 것은 격리되고 간단한 데이터 구조가 경계를 넘어 전달된다는 것입니다. 엔터 티나 데이터베이스 행을 속이고 통과하고 싶지 않습니다. 데이터 구조가 종속성 규칙을 위반하는 모든 종류의 종속성을 갖기를 원하지 않습니다.

[…] 경계를 넘어 데이터를 전달할 때는 항상 내부 원에 가장 편리한 형태입니다.

깨끗한 건축

또한 외부 레이어가 내부 레이어에 플러그인되는 방법을 설명하여 내부 레이어가 외부 레이어가 존재하는지도 알지 못하도록합니다.

클린 아키텍처 치트 시트

그런 식으로 입력 유효성 검사 규칙, 입력을 유지 해야하는 규칙, 계산을 실행하는 규칙, 결과를 출력으로 보내는 규칙에 대해 걱정할 수있는 데이터베이스를 무시할 수있는 좋은 장소가 있습니다. 실제로 이런 종류의 코드를 읽는 것이 더 쉽습니다.

또는 도메인이 실제로 데이터베이스를 조작하는 것이라고 결정합니다. 이 경우 도메인 언어는 SQL입니다. 그렇게해도 비즈니스 규칙 구현이 지속성의 변화를 견뎌 낼 것으로 기대하지는 않습니다. 결국 완전히 다시 작성해야합니다.


우리는 ORM (Entity Framework)을 사용하고 있으므로 데이터베이스는 이미 추상화되었지만 데이터 테이블 (Entity Framework 클래스)은 자연스럽게 데이터베이스 테이블과 거의 1 대 1입니다. 문제는 응용 프로그램의 일부 부분에서 사용자가 기본적으로 데이터 모델을 업데이트하고 있다는 것입니다 (화면은 각 텍스트 상자가 데이터베이스의 필드 (데이터 모델) 인 텍스트 상자 목록
일뿐

따라서 CRUD 작업을 수행 할 때 원시 데이터 (데이터 모델)의 표현을 사용하지 않는 이유는 없습니다. 우리는 계산에 사용되는 복잡한 도메인 표현을 가지고 있는데, 이것은 우리의 도메인 모델로 볼 수 있지만, 애플리케이션의 CRUD 부분에 그 그림을로드하는 이유는 알 수 없습니다.
wired_in

"원시 데이터의 표현 사용"으로 의미하는 바를 정의하십시오. 데이터가 입력되고, 도메인 규칙에 따라 데이터가 검증되고, 데이터가 어떻게 든 유지되며, 데이터가 계산되고 결과가 무엇이든 출력됩니다. 뭔가 빠졌습니까?
candied_orange 4

투자 계정에 대해 사용자로부터 얻은 원시 데이터가 calcs에 사용될 때와 같이 응용 프로그램의 주요 부분에서 해당 투자 계정을 나타내는 방식이 아니라고 말하려고합니다. 예를 들어 IsManagedAccount라는 데이터베이스에 저장 한 부울 입력이있을 수 있습니다. 사용자는 편집 화면의 라디오 버튼을 통해이를 제공합니다. 따라서 데이터베이스에서 화면까지의 표현은 1 대 1입니다. 나중에 애플리케이션에서 도메인 모델을 빌드 할 때 ManagedAccount 클래스가있을 수 있으므로 부울 특성이 없습니다. 두 구조는 크게 다릅니다.
wired_in

따라서 사용자가 편집 화면에서 원시 입력을 편집 할 때 왜 도메인 그림을로드 한 다음 강력한 형식의 ManagedAccount 클래스를 IsManagedAccount를 사용하는 단일 클래스 인 평면 표현으로 다시 매핑해야합니까? 특성?
wired_in

1

DDD 이론 적용 :

해당 도메인에는 두 개의 경계 컨텍스트가 있습니다.

  • 투자 계정의 계산. 투자 계정 수학적 모델은 집합 일 수있는 요소입니다.
  • 핵심 금융. 고객 투자 계정은 엔터티 중 하나입니다.

각 바운드 컨텍스트는 다른 아키텍처 디자인을 가질 수 있습니다.

예:

고객 투자 계정은 엔터티 (아마도 집계, 도메인에 따라 다름)이며 데이터의 지속성은 엔터티의 리포지토리 (RDB 또는 OO 데이터베이스와 같은 다른 유형의 DB)를 통해 이루어집니다.

CRUD 작업에는 DDD 방식이 없습니다. DB 필드를 객체의 데이터와 연결하면 디자인 원칙이 깨집니다.

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