팻 모델 / 씬 컨트롤러 대 서비스 레이어 [닫기]


84

.Net을 사용하여 수년 동안 엔터프라이즈 애플리케이션을 개발해 왔습니다. 내 앱에는 일반적으로 SQL DB 테이블에 매핑되는 엔터티를 포함하는 도메인 모델이 있습니다. 리포지토리 패턴, 종속성 주입 및 서비스 계층을 사용합니다.

최근에 우리는 MVC 3 프로젝트 작업을 시작했고 어떤 로직을 어디에 둘 것인지에 대해 토론했습니다. 나는 얇은 컨트롤러 / FAT 모델 아키텍처를 건너 왔고 서비스 계층이 어떻게 들어갈 지 궁금했습니다.

옵션 1-모델이 서비스와 대화

컨트롤러는 얇고 모델의 메서드를 호출합니다. 모델은 DB에서 자신을로드하고 저장소 또는 서비스와 통신하는 방법을 "알고"있습니다. 예를 들어 customerModel에는 Load (id) 메서드가 있고 고객과 GetContracts ()와 같은 일부 자식 개체를로드합니다.

옵션 2-컨트롤러가 서비스와 통신

Controller는 서비스에 모델 개체를 검색하도록 요청합니다. 로딩 / 저장 등의 로직은 서비스 계층에 있습니다. 모델은 데이터 만있는 순수 엔티티 모델입니다.

특히 엔터프라이즈 애플리케이션에 대해 이야기 할 때 옵션 1이 더 나은 선택 인 이유는 내 경험에 따르면 우려 사항을 분리하고 모델과 컨트롤러를 가능한 한 얇게 유지하며 비즈니스 로직을 수행하는 전문 서비스 (DB 상호 작용 포함)를 갖도록합니다.

좋은 리소스에 대한 모든 조언과 참조에 감사드립니다.

답변:


95

이 모든 것은 응용 프로그램의 의도와 요구 사항에 따라 다릅니다.

즉, "중간 규모"(지역 식당이 아니라 Twitter / Facebook이 아닌) 웹 응용 프로그램에 대한 제 제안입니다.

  1. 린 도메인 모델링

    가급적이면 특정 구현에서 느슨하게 결합 된 상태로 유지하기 위해 웹 응용 프로그램의 MVC 아키텍처에 무지한 건조한 POCO 스타일 개체. ).

    MVC의 "모델"은 가장 정확하게 컨트롤러가 인식하는 모델을 의미 하며 따라서 보기를위한 모델을 의미합니다 .

    더 작은 (종종 자습서) 응용 프로그램에서 "응용 프로그램 / 도메인 모델 계층"의 엔티티 모델은 컨트롤러가 뷰에 제공하는 동일한 인스턴스화 된 객체입니다.

    대규모 응용 프로그램에서 개발자는 종종 MVVM 아키텍처의 원칙을 사용하고 별도의 View Model 개체를 사용하기 시작합니다. 컨트롤러는 종종 아래에 보이지 않는 엔티티와 함께 ​​작동하는 중간 계층 서비스를 호출합니다. 이 시나리오에서 MVC의 M은 가장 정확하게보기 모델을 의미합니다.

  2. 강력한 서비스 계층

    이것은 비만 논리가 아니라 잘 작성된 단일 목적 서비스를 의미합니다. 모델 외부의 서비스에서 비즈니스 로직을 코딩하는 것은 순수한 "OOP"보다 "절차 적"이지만 느슨한 결합, 테스트 및 유연한 배포 (예 : n 계층 배포)에 많은 도움이됩니다.

    개인적으로 저는 POCO 객체 (지속성 메커니즘, 낮은 수준의 유효성 검사 등)의 행동 모델링을 고려하는 데이터 계층에서 서비스를 코딩하고 더 높은 수준의 서비스 (비즈니스 / 워크 플로 기능)를 MVC 역학.

  3. 린 컨트롤러

    나는 플레이 (서비스) 나 플레이어 (엔티티 모델 또는 뷰 모델)가 아니라, 단순히 누가 어떤 포지션을 플레이하고 어떤 플레이를 할 것인지 결정 한다는 점에서 내 컨트롤러가 코치 일뿐 임을 확인합니다. 내 컨트롤러는 두 가지 작업을 수행합니다.

    1. 엔티티 / 도메인 모델과 상호 작용하는 서비스 호출

    2. 적절한보기에 대한보기 모델을 준비합니다.

    인증 / 승인 된 컨트롤러 작업도 삽입 된 서비스 / 속성을 통해 수행됩니다.


편집 1 :

이것이 귀하의 엔티티 / 도메인 모델이 빈혈이거나 빈혈이어야 함을 의미하지는 않습니다. ORM, 저장소 및 공장, 유효성 검사 또는 상태 메커니즘을 환영합니다. 그것은 단지 중간 규모의 애플리케이션의 경우, 의미 모델 MVC에서가 나타내는 보기에 떨어져 손을, 컨트롤러에 대한 의미 모델을 .

이 점이 빈혈 데이터 모델반 패턴 이라고 믿는 파울러 사도들을 진정시킬 수 있기를 바랍니다 . 동시에, 그것은 않습니다 는 모델 클래스의 동작을 포함하는 더 순수한입니다 OOP보다 약간 더 절차 각도를 반영합니다.

"궁극적 인 진실"은 없지만이 패턴을 사용하면 많은 재사용 성과 확장 성을 유지하면서 애플리케이션을 쉽게 빌드, 테스트 및 배포 할 수 있습니다.


편집 2 :

즉, 적당한 크기의 응용 프로그램의 경우에도 시스템을 설계하는 것보다 시스템을 너무 일반적입니다. 예를 들어, 저장소 패턴으로 ORM을 래핑 한 다음 저장소를 사용하기위한 서비스를 작성합니다 ...이 모든 것은 우려 사항을 분리하는 데 유용하지만 프로젝트에서 필요하지 않은 경우 ( 필요 하지 않을 경우) ) 그런 것들을 만들지 마십시오. 저장소를 모두 건너 뛰거나 ORM에 대해 씬 비즈니스 서비스 (예 : 쿼리 클래스)를 작성하거나 컨트롤러가 직접 통신하도록하는 것은 문제가되지 않습니다. 그것은 모두 규모에 달려 있습니다.


편집 3 :

이 설명과 조언은 Knockout이나 Backbone과 같은 clent-side 프레임 워크가 아니라 ASP.Net과 같은 서버 측 MVC 아키텍처의 컨텍스트에 대한 것임을 주목하고 싶었습니다.


11
이것은 컨트롤러가 저장소에 대한 지식이 없다는 점을 제외하면 내가 사용하는 디자인 패턴과 거의 동일합니다. 컨트롤러는 리포지토리와 상호 작용하는 서비스와 만 상호 작용합니다.
Lester

2
@Lester 나는 그것을 정리하기 위해 편집했습니다. 95 %의 시간 내에서도 마찬가지입니다. 아이디어는 서비스가하는 것입니다. 작은 애플 리케이션에 그것은 잔인한 사람이 될 수 있지만, 자사의 좋은 연습 사람과 훨씬 더 쉽게는 IoC 컨테이너로 유지하기
one.beat.consumer

1
+1 @ one.beat.consumer : 이것은 제가 프로젝트에서 취하는 것과 동일한 접근 방식입니다 ... 때로는 규칙에 대해 너무 순수 해지면 솔루션이 너무 복잡해집니다. 실제 검증 된 솔루션에서 더 많은 이점을 경험할 수 있습니다. 완벽하게 GOF 패턴을 따르지 않는
themarcuz

7
MVC의 @ivowiblo 모델은 컨트롤러가 준비하고 뷰에 전달하는 데이터 모델입니다. 이것이 바로 당신의 '애플리케이션 모델'(도메인 모델, 모델 레이어, 라벨이 무엇이든 상관 없음)이 MVC 라이브러리를 완전히 인식하지 못할 수있는 이유이며, 개별적으로 분산 된 시스템의 솔루션 외부에 존재할 수도 있습니다. MVC에서 요청은 단순히 컨트롤러로 라우팅됩니다. 컨트롤러는 뷰 모델 (프레젠테이션 레이어 용 데이터)을 조립합니다. 이 모델은 당신이 아마 가난한 연습, 당신의 영속 역학에서 사용되는 동일한 인스턴스화 된 객체이지만,이 경우 되고 의미 수없는 독점적 인 정의가 없다.
one.beat.consumer

2
+1 MVC에서 염두에 두어야 "모델은"가장 정확하게 컨트롤러가 인식 모델 따라서보기위한 의도 된 모델을 의미한다.
Luiz Damim

16

우리가 모든 것을 어디에 둘 것인지 논의하기 전에 MVC에 대해 좀 더 알아야합니다. 음, 패턴을 따르고 싶다면. 그렇지 않으면 지금 읽기를 중단 할 수 있습니다.

패턴은 매우 느슨하게 정의됩니다. 컨트롤러, 뷰 또는 모델이 어떻게 생겼는지 또는 어떻게 구성되어야하는지에 대한 설명은 없습니다. 패턴은 단순히 부품을 분리해야하고 부품이 서로 상호 작용하는 방식을 나타냅니다. 그래서 그들이 무엇인지에 대해 좀 더 살펴 보겠습니다 (제 해석).

MVC

모델 모델은 무엇이든 될 수 있습니다. 웹 서비스, 저장소, 서비스 클래스 또는 단순히 도메인 모델 일 수 있습니다. 모델은 필요한 정보를 얻는 데 사용되는 모든 것입니다. "모델"을 단일 개체가 아닌 레이어로 간주합니다.

컨트롤러 컨트롤러는 접착제입니다. 모델에서 정보를 가져 와서보기에 맞게 조정하고 그 반대의 경우도 마찬가지입니다.

보기보기 는 사용자가 보는 것만 렌더링해야합니다.

모델을 뷰 모델과 혼동해서는 안됩니다. Microsoft는 "모델"폴더의 이름을 "ViewModels"로 지정 했어야합니다. 뷰에서 직접 "모델"의 정보를 사용하지 않습니다. 그렇게하지 않으면보기가 변경되고 그 반대의 경우 모델을 변경해야합니다.

대답

모델은 뷰 모델이 아니라 레이어입니다. 모델의 모든 것은 뷰에 필요한 정보를 가져 오는 데 사용됩니다. 컨트롤러는 해당 정보를 가져 와서 단일 뷰 모델에 넣습니다.

단일 컨트롤러 작업은 뷰에 필요한 정보를 어셈블 할 수 있도록 "모델"에 대한 하나 또는 여러 호출을 사용할 수 있습니다.

즉, 유지 관리 및 확장이 쉬운 응용 프로그램을 원할 때 두 번째 옵션이 가장 정확합니다.

서비스 계층이 필요하지 않을 수 있습니다. 컨트롤러에서 직접 OR / M을 호출 할 수 있습니다. 그러나 코드를 복제하거나 복잡한 컨트롤러를 확보하는 경우 로직을 서비스 계층으로 이동하기 만하면됩니다. 적절한 뷰 모델을 사용하고 있기 때문에 컨트롤러 만 해당 변경 사항에 영향을받지 않습니다.


3
ASP.NET MVC가 대신 ASP.NET ModelView View Controller로 명명 되었으면합니다. 그것은 끔찍한 이름이 될 것이지만, 적어도 그것의 진정한 의미 : 전달할 것
헥터 코레아

ASP.NET MVC를 사용한 후에도 모델이 뷰 모델을 의미하지 않는다는 것을 깨닫는 데는 시간이 걸렸습니다.
Lester

@ one.beat.consumer : 모델에 대한 나의 요점은 그것이 무엇이든 될 수 있다는 것입니다. 그것은 단지 레이어 일뿐입니다. 응용 프로그램에 맞게 만드십시오. 많은 사람들이 ASP.NET MVC의 모델이 뷰 모델이거나 VM과 모델이 동일하다고 생각하기 때문에 그렇게했습니다.
jgauffin

나는 내가 그 질문을 다룬다 고 생각한다. customerModel그가 질문에서 말한 나의 해석은 뷰 모델입니다. 그가 그렇지 않다는 것을 이해한다면 대답은 더 분명합니다.
jgauffin

2
@jgauffin 의미론은 여기서 중요합니다. MVC에서 "모델" "모델 계층"을 의미 하지 않습니다 . 그것은 단지 Controller가 View에 전달하는 모델 객체를 의미 합니다 . 규모가 큰 애플리케이션에서 MVC 아키텍처는 종종 모델 / 데이터 레이어 또는 사용자가 호출하기로 선택한 항목을 인식하지 못합니다. 내 편집 된 답변은이 혼란을 설명하려고합니다 ... 주로 앱이 작을 때 Model과 View 모델을 추가로 분리 할 필요가 없기 때문에 사람들은 모델을 표시하고 컨트롤러가 저장소를 사용하도록하는 경향이 있습니다. 전체 크기 앱의 경우 거의 발생하지 않습니다.
one.beat.consumer

0

옵션 1 : 모델 == 서비스라고 생각할 수 있습니다. 모델은 또한 비즈니스 계층입니다.

옵션 2는 빈혈 도메인 모델 안티 패턴입니다. http://en.wikipedia.org/wiki/Anemic_domain_model


안티 패턴이라고 부르는 것은 더 많은 맥락이 필요하다는 것을 명심하십시오! 대부분의 응용 프로그램은 CRUD 작업이므로 도메인 모델이 필요하지 않습니다.
Rookian 2013-04-24

도메인 모델은 "메타 데이터"가있는 데이터 일뿐입니다. 메타 데이터가 없으면 괜찮습니다. 나는 당신이 그 부분에 맞기 때문에 "반 패턴"단어를 제거했습니다. 나는 받아 들여지는 대답이 정말 마음에 들었고 내 대답은 대신 주석이어야했습니다.
Imre L

0

옵션 2는 Fat Stupid Ugly Controllers 아키텍처로 설명 된 것 입니다 (이 표현식의 작성자 참조 ). 이 솔루션은 일반적으로 우려의 분리를 깨뜨리기 때문에 MVC 정신에 위배됩니다.


1
public ActionResult FetchApple() { return View(_groceryService.GetApple("Granny Smith")); }당신이 나에게 물어 보면 꽤 마른 것입니다.
one.beat.consumer

4
FSUC 기사를 읽은 내용이 위의 옵션 2와 일치하지 않습니다. FSUC 작성자가 제공하는 예제는 모든 주문 논리가 캡슐화 된 서비스 계층의 사용을 보여주지 않습니다. 대신 컨트롤러가 비즈니스 로직과 함께로드되었음을 보여줍니다. 그리고 컨트롤러에 있기 때문에 비즈니스 로직의 재사용 성은 이제 손실됩니다.
Marvo 2011
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.