[asp.net-mvc] 서비스가 항상 DTO를 반환해야합니까, 아니면 도메인 모델을 반환 할 수 있습니까?
대규모 응용 프로그램을 설계 중이며 DDD 기반의 다중 계층 아키텍처를 사용합니다.
데이터 계층 (리포지토리 구현), 도메인 계층 (도메인 모델 및 인터페이스 정의-리포지토리, 서비스, 작업 단위), 서비스 계층 (서비스 구현)을 갖춘 MVC가 있습니다. 지금까지 모든 계층에 걸쳐 도메인 모델 (주로 엔터티)을 사용하고 DTO를 뷰 모델로만 사용합니다 (컨트롤러에서 서비스는 도메인 모델을 반환하고 컨트롤러는 뷰 모델을 생성하여 뷰에 전달 함).
DTO 사용, 사용 안 함, 매핑 및 전달에 대한 수많은 기사를 읽었습니다. 명확한 답변이 없다는 것을 이해하지만 도메인 모델을 서비스에서 컨트롤러로 되돌릴 수 있는지 확실하지 않습니다. 컨트롤러가 항상 뷰 특정 뷰 모델을 생성하기 때문에 도메인 모델을 반환해도 여전히 뷰로 전달되지 않습니다.이 경우 합법적 인 것처럼 보입니다. 반면, 도메인 모델이 비즈니스 계층 (서비스 계층)을 떠날 때 기분이 좋지 않습니다. 때로는 서비스가 도메인에 정의되지 않은 데이터 객체를 반환해야하는 경우 매핑되지 않은 도메인에 새 객체를 추가하거나 POCO 객체를 생성해야합니다 (일부 서비스는 도메인 모델을 반환하기 때문에 추악합니다) 효과적으로 DTO를 반환).
문제는-뷰 모델을 엄격하게 사용하는 경우 도메인 모델을 컨트롤러로 되돌려 보내도됩니까, 아니면 서비스 계층과의 통신에 항상 DTO를 사용해야합니까? 그렇다면 어떤 서비스가 필요한지에 따라 도메인 모델을 조정해도 괜찮습니까? (서비스가 도메인을 가지고 있어야하기 때문에 솔직히 그렇게 생각하지 않습니다.) DTO를 엄격하게 고수해야한다면 서비스 계층에서 정의해야합니까? (그렇다고 생각합니다.) 때로는 DTO를 사용해야한다는 것이 분명합니다 (예 : 서비스가 많은 비즈니스 로직을 수행하고 새로운 객체를 생성하는 경우). 때로는 도메인 모델 만 사용해야한다는 것이 분명합니다 (예 : 멤버십 서비스가 빈혈 사용자 ( s)-도메인 모델과 동일한 DTO를 만드는 것이별로 의미가없는 것 같습니다.)-일관성과 우수 사례를 선호합니다.
기사 도메인 vs DTO vs ViewModel-언제 어떻게 사용합니까? (및 일부 다른 기사)는 내 문제와 매우 유사하지만이 질문에 대답하지 않습니다. 기사 EF를 사용하여 리포지토리 패턴으로 DTO를 구현해야합니까? 또한 비슷하지만 DDD를 다루지 않습니다.
면책 조항 : 디자인 패턴이 존재하고 멋지 기 때문에 어떤 디자인 패턴 만 사용하려고하지 않습니다. 반면, 좋은 디자인 패턴과 관행을 사용하고 싶습니다. 응용 프로그램 전체를 디자인하고 분리하는 데 도움이되기 때문입니다. 우려 할 점은, 적어도 현재로서는 특정 패턴을 사용하는 것조차 “필요”하지 않다는 것입니다.
언제나 그렇듯이 감사합니다.
답변
도메인 모델이 비즈니스 계층 (서비스 계층)을 떠날 때 기분이 좋지 않습니다.
내장을 바로 잡아 당기는 것 같은 느낌이 들까 요? Martin Fowler에 따르면 : 서비스 계층은 응용 프로그램의 경계를 정의하고 도메인을 캡슐화합니다. 다시 말해 도메인을 보호합니다.
때때로 서비스는 도메인에 정의되지 않은 데이터 객체를 반환해야합니다
이 데이터 개체의 예를 제공 할 수 있습니까?
DTO를 엄격하게 준수해야하는 경우 서비스 계층에서 정의해야합니까?
응답은 서비스 계층의 일부이기 때문에 가능합니다. “다른 곳”으로 정의 된 경우 서비스 계층은 “다른 곳”을 참조하여 라자냐에 새 계층을 추가해야합니다.
도메인 모델을 컨트롤러로 되돌려 보내도됩니까, 아니면 서비스 계층과의 통신에 항상 DTO를 사용해야합니까?
DTO는 응답 / 요청 객체이며, 통신에 사용하는 것이 좋습니다. 프리젠 테이션 레이어 (MVC- 컨트롤러 / 뷰, WebForms, ConsoleApp)에서 도메인 모델을 사용하는 경우 프리젠 테이션 레이어가 도메인과 밀접하게 연결되어 있으며 도메인을 변경하면 컨트롤러를 변경해야합니다.
도메인 모델과 동일한 DTO를 만드는 것은 의미가없는 것 같습니다.)
이것은 새로운 시각에 대한 DTO의 단점 중 하나입니다. 지금 은 코드 중복을 생각하고 있지만 프로젝트가 확장되면 특히 다른 팀이 다른 레이어에 지정된 팀 환경에서 훨씬 더 의미가 있습니다.
DTO는 애플리케이션에 추가적인 복잡성을 추가 할 수 있지만 계층도 복잡합니다. DTO는 시스템의 비싼 기능이며 무료로 제공되지 않습니다.
DTO를 사용해야하는 이유
이 기사에서는 DTO 사용의 장단점을 모두 제공합니다. http://guntherpopp.blogspot.com/2010/09/to-dto-or-not-to-dto.html
다음과 같은 요약 :
사용시기
- 대규모 프로젝트의 경우.
- 프로젝트 수명은 10 년 이상입니다.
- 전략적이고 미션 크리티컬 한 애플리케이션.
- 대규모 팀 (5 명 이상)
- 개발자는 지리적으로 분산되어 있습니다.
- 도메인과 프리젠 테이션이 다릅니다.
- 오버 헤드 데이터 교환 감소 (DTO의 원래 목적)
사용하지 않을 때
- 중소 규모 프로젝트 (최대 5 명)
- 프로젝트 수명은 2 년 정도입니다.
- GUI, 백엔드 등을위한 별도의 팀이 없습니다.
DTO에 대한 주장
- 코드 복제.
- 개발 시간, 디버깅. (DTO 생성 도구 http://entitiestodtos.codeplex.com/ 사용 )
- 두 모델을 항상 동기화해야합니다.
- 개발 비용 : 추가 매핑이 필요합니다. ( https://github.com/AutoMapper/AutoMapper 와 같은 자동 매퍼 사용 )
- 데이터 전송 객체가 왜 안티 패턴입니까?
DTO를 사용한 인수
- DTO가 없으면 프레젠테이션과 도메인이 밀접하게 연결됩니다. (이것은 소규모 프로젝트에는 좋습니다.)
- 인터페이스 / API 안정성
- 절대적으로 필요한 속성 만 포함하는 DTO를 반환하여 프리젠 테이션 계층에 최적화를 제공 할 수 있습니다. linq-projection을 사용 하면 전체 엔티티를 가져올 필요가 없습니다.
- 개발 비용을 줄이려면 코드 생성 도구를 사용하십시오.
답변
DDD 접근 방식을 결정한대로 응용 프로그램이 충분히 크고 복잡해 보입니다. 서비스 계층에 포코 엔터티 또는 소위 도메인 엔터티 및 값 개체를 반환하지 마십시오. 이렇게하려면 더 이상 필요하지 않기 때문에 서비스 계층을 삭제하십시오! View 모델 또는 데이터 전송 개체는 도메인 모델 구성원에 매핑되거나 그 반대로 매핑되어야하므로 서비스 계층에 있어야합니다. 그렇다면 왜 DTO가 필요합니까? 시나리오가 많은 복잡한 응용 프로그램에서는 도메인의 문제와 프레젠테이션보기를 분리해야하며 도메인 모델을 여러 DTO로 나눌 수도 있고 여러 도메인 모델을 DTO로 축소 할 수도 있습니다. 따라서 모델과 동일하더라도 계층 구조로 DTO를 만드는 것이 좋습니다.
서비스 계층과의 통신에 항상 DTO를 사용해야합니까?
예, 도메인 모델 구성원과 함께 서비스 계층의 저장소와 대화하고 DTO에 맵핑하고 MVC 컨트롤러로 리턴하거나 그 반대의 경우 서비스 계층에서 DTO를 리턴해야합니다.
어떤 서비스가 필요한지에 따라 도메인 모델을 조정해도 괜찮습니까?
서비스는 리포지토리 및 도메인 방법 및 도메인 서비스와 통신하기 때문에 필요에 따라 도메인의 비즈니스를 해결해야하며 도메인에 필요한 것을 알려주는 서비스 작업이 아닙니다.
DTO를 엄격하게 준수해야하는 경우 서비스 계층에서 정의해야합니까? 예. DTO 또는 ViewModel을 서비스 계층의 도메인 구성원에 매핑해야하기 때문에 나중에 서비스 상태로 유지하려고합니다. DTO를 응용 프로그램의 컨트롤러에 배치하는 것은 좋지 않습니다 ( 서비스 계층에서 요청 응답 패턴 을 사용하려고 함 ). !
답변
내 경험상 당신은 실용적인 것을해야합니다. “최고의 디자인은 가장 간단한 디자인입니다”-아인슈타인. 그 마음으로 …
뷰 모델을 엄격하게 사용하는 경우 도메인 모델을 컨트롤러로 되돌려 보내도됩니까, 아니면 서비스 계층과의 통신에 항상 DTO를 사용해야합니까?
물론 괜찮습니다! 도메인 엔터티, DTO 및 뷰 모델이있는 경우 데이터베이스 테이블을 포함하면 응용 프로그램의 모든 필드가 4 곳에서 반복됩니다. Domain Entities와 View Models가 잘 작동하는 대규모 프로젝트에서 일했습니다. 응용 프로그램이 배포되고 서비스 계층이 다른 서버에 상주하는 경우에만 직렬화 이유로 인해 DTO가 유선을 통해 전송해야합니다.
그렇다면 어떤 서비스가 필요한지에 따라 도메인 모델을 조정해도 괜찮습니까? (솔직히 말해서, 서비스는 도메인의 것을 소비해야하기 때문에)
도메인 모델은 일반적으로 비즈니스 로직을 반영하고 일반적으로 해당 로직의 소비자에 의해 형성되지 않기 때문에 일반적으로 동의합니다.
DTO를 엄격하게 준수해야하는 경우 서비스 계층에서 정의해야합니까? (나도 그렇게 생각해.)
당신이 그것들을 사용하기로 결정한다면 나는 동의합니다. 그렇습니다. 서비스 계층은 하루가 끝날 때 DTO를 반환하므로 완벽한 장소입니다.
행운을 빕니다!
답변
나는이 파티에 늦었지만 이것은 일반적이고 중요한 질문인데, 내가 대답해야한다고 느꼈습니다.
“서비스” 란 블루 북 의 Evan ‘s에서 설명한 “애플리케이션 계층”을 의미 합니까? 나는 당신이 그렇게한다고 가정 할 것입니다.이 경우 대답은 DTO를 반환 해서는 안됩니다 . 나는 “도서 격리”라는 제목의 청서 4 장을 읽는 것이 좋습니다.
이 장에서 Evans는 레이어에 대해 다음을 말합니다.
복잡한 프로그램을 계층으로 분할하십시오. 응집력이 있고 아래 레이어에만 의존하는 각 레이어 내에서 디자인을 개발하십시오.
이에 대한 충분한 이유가 있습니다. 소프트웨어의 복잡성 을 측정하기 위해 부분 순서 개념을 사용하는 경우 계층을 그 위의 계층에 의존하면 복잡성이 증가하여 유지 관리 성이 떨어집니다.
이것을 귀하의 질문에 적용하면 DTO는 실제로 사용자 인터페이스 / 프리젠 테이션 계층과 관련된 어댑터입니다. 원격 / 교차 프로세스 통신은 정확히 DTO 의 목적 이라는 점을 기억하십시오 (그 포스트에서 Fowler는 DDD가 반드시 DDD 언어를 사용하는 것은 아니지만 서비스 계층의 일부인 DTO에 대해서도 논한다는 점은 주목할 가치가 있습니다).
응용 프로그램 계층이 해당 DTO에 의존하는 경우 자체 계층 이상의 계층에 따라 복잡성이 증가합니다. 이로 인해 소프트웨어 유지 관리가 어려워집니다.
예를 들어, 시스템이 여러 다른 시스템 또는 클라이언트 유형과 인터페이스하고 각각 고유 한 DTO가 필요한 경우 어떻게해야합니까? 응용 프로그램 서비스의 어떤 DTO가 반환해야하는지 어떻게 알 수 있습니까? 선택한 언어에서 반환 유형에 따라 메서드 (이 경우 서비스 메서드) 오버로드를 허용하지 않는 경우이 문제를 어떻게 해결 하시겠습니까? 그리고 방법을 알아 내더라도 프레젠테이션 계층 문제를 지원하기 위해 애플리케이션 계층을 위반하는 이유는 무엇입니까?
실질적인 측면에서 이것은 스파게티 건축물로 끝나는 길을 한 단계 밟습니다. 나는 이런 종류의 혁명과 그 결과를 내 경험에서 보았습니다.
현재 작업중인 응용 프로그램 계층의 서비스는 도메인 개체를 반환합니다. 인터페이스 (예 : UI / 프레젠테이션) 레이어는 그 아래 에있는 도메인 레이어에 의존하기 때문에이 문제를 고려하지 않습니다 . 또한이 종속성은 다음과 같은 이유로 “참조 전용”유형의 종속성으로 최소화됩니다.
a) 인터페이스 계층은 응용 프로그램 계층을 호출하여 얻은 읽기 전용 반환 값으로 이러한 도메인 개체에만 액세스 할 수 있습니다.
b) 애플리케이션 계층의 서비스에 대한 메소드는 해당 계층에 정의 된 “원시”입력 (데이터 값) 또는 객체 매개 변수 (필요한 경우 매개 변수 수를 줄이기 위해)를 입력으로 만 허용합니다. 특히 응용 프로그램 서비스 는 도메인 개체를 입력으로 받아들이지 않습니다 .
인터페이스 계층은 인터페이스 계층 자체에 정의 된 맵핑 기술을 사용하여 도메인 오브젝트에서 DTO로 맵핑합니다. 다시 말하지만 DTO는 인터페이스 계층에 의해 제어되는 어댑터에 계속 집중합니다.
답변
파티에 늦었지만 정확히 같은 유형의 아키텍처에 직면하고 있으며 “서비스에서 온 DTO”에만 집중하고 있습니다. 이것은 주로 객체 내에서 유효성을 유지하기 위해 도메인 객체 / 집계 만 사용하기로 결정했기 때문에 업데이트, 생성 또는 삭제시에만 가능합니다. 데이터를 쿼리 할 때 EF 만 리포지토리로 사용하고 결과를 DTO에 매핑합니다. 이를 통해 읽기 쿼리를 자유롭게 최적화하고 비즈니스 객체에 맞게 조정할 수 없으며 종종 데이터베이스 기능을 빠르게 사용할 수 있습니다.
각 서비스 방법은 자체 계약을 정의하므로 시간이 지남에 따라 유지 관리가 더 쉽습니다. 나는 희망.
답변
지금까지 모든 계층에서 도메인 모델 (주로 엔터티)을 사용하고 DTO를 뷰 모델로만 사용합니다 (컨트롤러에서 서비스는 도메인 모델을 반환하고 컨트롤러는 뷰 모델을 뷰에 전달합니다).
도메인 모델은 전체 응용 프로그램에 대한 용어 ( 유비쿼터스 언어 )를 제공하므로 도메인 모델을 널리 사용하는 것이 좋습니다.
ViewModels / DTO를 사용하는 유일한 이유는 응용 프로그램에서 MVC 패턴 을 구현 하여 View
모든 종류의 프레젠테이션 계층과 Model
(도메인 모델) 분리하기 때문입니다. 이 경우 프레젠테이션과 도메인 모델이 느슨하게 연결됩니다.
때로는 서비스가 도메인에 정의되지 않은 데이터 객체를 반환해야하는 경우 매핑되지 않은 도메인에 새 객체를 추가하거나 POCO 객체를 생성해야합니다 (일부 서비스는 도메인 모델을 반환하기 때문에 추악합니다) 효과적으로 DTO를 반환).
Application / Business / Domain Logic 서비스에 대해 이야기한다고 가정합니다.
가능하면 도메인 엔터티를 반환하는 것이 좋습니다. 추가 정보를 반환해야하는 경우 여러 도메인 엔터티가있는 DTO를 반환해도됩니다.
때로는 도메인 엔터티를 통해 프록시를 생성하는 3 파트 프레임 워크를 사용하는 사람들은 서비스에서 도메인 엔터티를 노출하는 데 어려움을 겪지 만 사용의 문제 일뿐입니다.
문제는-뷰 모델을 엄격하게 사용하는 경우 도메인 모델을 컨트롤러로 되돌려 보내도됩니까, 아니면 서비스 계층과의 통신에 항상 DTO를 사용해야합니까?
99,9 %의 경우 도메인 엔터티를 반환하는 것으로 충분합니다.
DTO 생성을 단순화하고 도메인 엔터티를 매핑하기 위해 AutoMapper 를 사용할 수 있습니다 .
답변
도메인 모델의 일부를 반환하면 계약의 일부가됩니다. 컨텍스트 외부의 상황에 따라 계약이 변경되기 어렵습니다. 따라서 도메인 모델의 일부를 변경하기가 어렵습니다.
도메인 모델의 매우 중요한 측면은 변경하기 쉽다는 것입니다. 따라서 도메인의 변화하는 요구 사항에 유연하게 대처할 수 있습니다.