왜 데이터 액세스를 분리해야합니까?
이 책에서 Model Driven Design 장의 처음 두 페이지는 도메인 모델 구현에서 기술적 구현 세부 사항을 추상화하려는 이유에 대한 정당성을 제공한다고 생각합니다.
- 도메인 모델과 코드를 밀접하게 연결하려고합니다.
- 기술적 문제를 분리하면 모델이 구현에 실용적임을 증명할 수 있습니다
- 유비쿼터스 언어가 시스템 설계에 스며 들기를 원합니다.
이것은 시스템의 실제 구현과 분리되는 별도의 "분석 모델"을 피하기위한 것입니다.
이 책에서 내가 이해 한 바에 따르면이 "분석 모델"은 소프트웨어 구현을 고려하지 않고도 설계 될 수 있다고합니다. 개발자가 비즈니스 측면에서 이해 한 모델을 구현하려고 시도하면 필요로 인해 자체 추상화를 형성하여 의사 소통과 이해에 벽을 가져옵니다.
다른 한편으로, 도메인 모델에 너무 많은 기술적 인 관심사를 도입 한 개발자는이 차이도 발생할 수 있습니다.
따라서 지속성과 같은 우려 사항을 분리하면 분석 모델이 발산되는 이러한 설계로부터 보호하는 데 도움이 될 수 있습니다. 모델에 퍼시스턴스 (persistence)와 같은 것들을 도입 할 필요가 있다고 느낀다면 그것은 붉은 깃발입니다. 모델이 구현에 실용적이지 않을 수 있습니다.
인용 :
"단일 모델은 설계가 이제 신중하게 고려 된 모델의 직접적인 결과물이기 때문에 오류 발생 가능성을 줄입니다. 설계 및 코드 자체는 모델의 통신 성을 갖습니다."
내가 이것을 해석하는 방식으로, 데이터베이스 액세스와 같은 것들을 다루는 더 많은 코드 줄로 끝내면 그 의사 소통을 잃게됩니다.
데이터베이스에 액세스해야 할 필요성이 고유성을 확인하는 것과 같은 것이라면 다음을 살펴보십시오.
Udi Dahan : DDD를 적용 할 때 팀이 저지르는 가장 큰 실수
http://gojko.net/2010/06/11/udi-dahan-the-biggest-mistakes-teams-make-when-applying-ddd/
"모든 규칙이 동일하게 생성되지 않았습니다"에서
과
도메인 모델 패턴 사용
http://msdn.microsoft.com/en-us/magazine/ee236415.aspx#id0400119
동일한 주제를 다루는 "도메인 모델을 사용하지 않는 시나리오"에서
데이터 액세스를 분리하는 방법
인터페이스를 통한 데이터 로딩
"데이터 액세스 계층"은 필요한 데이터를 검색하기 위해 호출하는 인터페이스를 통해 추상화되었습니다.
var orderLines = OrderRepository.GetOrderLines(orderId);
foreach (var line in orderLines)
{
total += line.Price;
}
장점 :이 인터페이스는 "데이터 액세스"배관 코드를 분리하여 테스트를 작성할 수 있습니다. 데이터 액세스는 사례별로 처리 할 수있어 일반적인 전략보다 더 나은 성능을 제공합니다.
단점 : 호출 코드는로드 된 것과로드되지 않은 것을 가정해야합니다.
GetOrderLines가 성능상의 이유로 null ProductInfo 속성을 가진 OrderLine 객체를 반환한다고 가정 해보십시오. 개발자는 인터페이스 뒤의 코드에 대해 잘 알고 있어야합니다.
실제 시스템 에서이 방법을 시도했습니다. 결국 성능 문제를 해결하기 위해로드되는 내용의 범위를 변경하게됩니다. 인터페이스 뒤에 숨어 데이터로드 코드를 살펴보고로드되거나로드되지 않는 것을 확인합니다.
이제 관심사를 분리하면 개발자는 코드의 한 측면에 최대한 집중할 수 있습니다. 인터페이스 기술은이 데이터가로드되는 방법을 제거하지만로드되는 시점과로드 시점에 얼마나 많은 데이터가로드되는지를 제거합니다.
결론 : 상당히 낮은 분리!
게으른 로딩
요청시 데이터가로드됩니다. 데이터를로드하기위한 호출은 객체 그래프 자체에 숨겨져 있으며, 속성에 액세스하면 결과를 반환하기 전에 SQL 쿼리가 실행될 수 있습니다.
foreach (var line in order.OrderLines)
{
total += line.Price;
}
장점 : 데이터 액세스의 'WHEN, WHERE 및 HOW'는 도메인 논리에 중점을 둔 개발자에게 숨겨져 있습니다. 데이터로드를 처리하는 집계에는 코드가 없습니다. 로드되는 데이터의 양은 코드에 필요한 정확한 양일 수 있습니다.
단점 : 성능 문제가 발생했을 때 일반적인 "한 크기에 맞는"솔루션이 있으면 해결하기가 어렵습니다. 지연 로딩은 전체적으로 성능을 저하시킬 수 있으며 지연 로딩을 구현하는 것은 까다로울 수 있습니다.
역할 인터페이스 / 열쇠 가져 오기
각 사용 사례는 집계 클래스에 의해 구현 된 역할 인터페이스 를 통해 명시 적으로 작성 되므로 사용 사례별로 데이터로드 전략을 처리 할 수 있습니다.
페칭 전략은 다음과 같습니다.
public class BillOrderFetchingStrategy : ILoadDataFor<IBillOrder, Order>
{
Order Load(string aggregateId)
{
var order = new Order();
order.Data = GetOrderLinesWithPrice(aggregateId);
return order;
}
}
그런 다음 집계는 다음과 같습니다.
public class Order : IBillOrder
{
void BillOrder(BillOrderCommand command)
{
foreach (var line in this.Data.OrderLines)
{
total += line.Price;
}
etc...
}
}
BillOrderFetchingStrategy는 집계를 빌드하는 데 사용되며 집계는 작업을 수행합니다.
장점 : 사용 사례별로 사용자 지정 코드를 허용하여 최적의 성능을 제공합니다. 인터페이스 분리 원리 와 일치합니다 . 복잡한 코드 요구 사항이 없습니다. 집계 단위 테스트는로드 전략을 모방하지 않아도됩니다. 일반 로딩 전략은 대부분의 경우에 사용될 수 있으며 (예 : "모두로드"전략) 필요한 경우 특수 로딩 전략을 구현할 수 있습니다.
단점 : 개발자는 도메인 코드를 변경 한 후에도 페칭 전략을 조정 / 검토해야합니다.
페칭 전략 접근 방식을 사용하면 비즈니스 규칙 변경을 위해 사용자 정의 페칭 코드를 변경하는 것을 여전히 알 수 있습니다. 문제를 완벽하게 분리하지는 않지만 유지 관리가 쉬우 며 첫 번째 옵션보다 낫습니다. 페치 전략은 HOW, WHEN 및 WHERE 데이터가로드되는 것을 캡슐화합니다. 하나의 크기가 모든 게으른 로딩 방식에 맞는 것처럼 유연성을 잃지 않으면 서 더 나은 우려 분리 기능을 제공합니다.