Program Tip

빈혈 도메인 모델 : 장점 / 단점

programtip 2020. 10. 15. 21:29
반응형

빈혈 도메인 모델 : 장점 / 단점


빈혈 도메인 모델 (아래 링크 참조) 사용에 대한 장단점이 무엇인지 알고 싶습니다.

파울러 기사


장점 :

  • 도메인 모델이라고 주장하고 개발자 친구에게 자랑하고 이력서에 올릴 수 있습니다.
  • 데이터베이스 테이블에서 자동으로 생성하는 것은 쉽습니다.
  • 놀랍도록 잘 데이터 전송 개체에 매핑됩니다.

단점 :

  • 도메인 논리는 아마도 클래스 (정적) 메서드로 가득 찬 클래스에있을 것입니다. 또는 GUI 코드. 또는 논리가 상충되는 여러 곳에서.
  • 안티 패턴이므로 다른 개발자가 객체 지향 디자인의 개념을 이해하는지 묻습니다.

"빈혈 도메인 모델"이 안티 패턴인데 왜이를 구현하는 시스템이 그렇게 많습니까?

몇 가지 이유가 있다고 생각합니다

1. 시스템의 복잡성

구현하려는 경우 간단한 시스템 (인터넷에서 찾을 수있는 거의 모든 예제 및 샘플 코드)에서 :

주문에 제품 추가

이 기능을 주문에 넣었습니다.

public void Order.AddOrderLine(Product product)
{
    OrderLines.Add(new OrderLine(product));
}

멋지고 슈퍼 객체 지향.

이제 제품이 재고에 있는지 확인하고 그렇지 않은 경우 예외를 throw해야한다고 가정 해 보겠습니다.

주문이 재고에 의존하는 것을 원하지 않기 때문에 더 이상 주문에 넣을 수 없습니다. 이제 서비스를 시작해야합니다.

public void OrderService.AddOrderLine(Order order, Product product)
{
    if (!InventoryService.Has(product)
       throw new AddProductException

    order.AddOrderLine(product);
}

IInventoryService를 Order.AddOrderLine에 전달할 수도 있는데, 이는 또 다른 옵션이지만 여전히 Order가 InventoryService에 종속되도록합니다.

Order.AddOrderLine에는 여전히 일부 기능이 있지만 일반적으로 Order 범위로 제한되지만 내 경험으로는 Order 범위에서 벗어난 비즈니스 로직이 훨씬 더 많습니다.

시스템이 기본 CRUD 이상이면 OrderService에서 대부분의 논리를 사용하고 Order에서는 거의 사용하지 않습니다.

2. OOP에 대한 개발자의 관점

어떤 논리가 엔티티에 적용되어야하는지에 대해 인터넷에서 열띤 토론이 많이 있습니다.

같은 것

주문. 저장

주문이 스스로를 구하는 방법을 알아야합니까? 이를위한 저장소가 있다고 가정 해 봅시다.

이제 주문이 주문 라인을 추가 할 수 있습니까? 간단한 영어로 이해하려고하면 말도 안 돼요. 사용자가 주문에 제품을 추가하므로 User.AddOrderLineToOrder ()를 수행해야합니까? 과잉 인 것 같습니다.

OrderService.AddOrderLine ()은 어떻습니까? 이제 말이 되네요!

OOP에 대한 나의 이해는 캡슐화를 위해 함수가 클래스의 내부 상태에 액세스해야하는 클래스에 함수를 배치한다는 것입니다. Order.OrderLines 컬렉션에 액세스해야하는 경우 Order에 Order.AddOrderLine ()을 넣습니다. 이렇게하면 클래스의 내부 상태가 노출되지 않습니다.

3. IoC 컨테이너

IoC 컨테이너를 사용하는 시스템은 일반적으로 완전히 빈혈입니다.

인터페이스가있는 서비스 / 저장소를 테스트 할 수 있지만 모든 인터페이스에 인터페이스를 배치하지 않는 한 도메인 개체를 (쉽게) 테스트 할 수 없기 때문입니다.

"IoC"는 현재 모든 프로그래밍 문제에 대한 해결책으로 찬사를 받고 있기 때문에 많은 사람들이 맹목적으로이를 따르고 이런 식으로 Anemic Domain Models로 끝납니다.

4. OOP는 어렵고 절차는 쉬움

I have a bit of a "Curse of Knowledge" on this one, but I have discovered that for newer developers having DTOs and Services is a lot easier than Rich Domain.

Possibly it is because with Rich Domain it is more difficult to know on which classes to put the logic. When to create new classes? Which patterns to use? etc..

With stateless services you just slap it in the service with closest name.


그 이후로 오랫동안 머릿속에 생각이 떠 올랐습니다. "OOP"라는 용어가 진정으로 의도하지 않은 의미를 가지고 있다고 생각합니다. 애너그램은 우리 모두가 잘 알고 있듯이 "객체 지향 프로그래밍"을 의미합니다. 물론 초점은 "지향적"이라는 단어에 있습니다. "객체 필수 프로그래밍"을 의미하는 "OMP"가 아닙니다. ADM과 RDM은 모두 OOP의 예입니다. 개체, 속성, 메서드 인터페이스 등을 사용합니다. 그러나 ADM과 RDM은 캡슐화하는 방법에 차이가 있습니다. 두 가지 다른 것입니다. ADM이 잘못된 OOP라고 말하는 것은 정확한 진술이 아닙니다. 대신 다양한 수준의 캡슐화에 대해 다른 용어가 필요할 수 있습니다. 또한 안티 패턴이라는 용어를 좋아하지 않았습니다. 일반적으로 반대 그룹의 구성원이 무언가에 할당합니다. ADM과 RDM은 모두 유효한 패턴이며 단순하며 서로 다른 목표를 염두에두고 있으며 서로 다른 비즈니스 요구 사항을 해결하기위한 것입니다. DDD를 실행하는 사람들은 적어도 이것을 감사해야하며 ADM을 구현하기로 선택한 사람들을 때려서 다른 사람의 수준에 떨어지지 않아야합니다. 내 생각뿐입니다.


"반 패턴이기 때문에 다른 개발자들이 객체 지향 디자인의 개념을 이해하는지 물어볼 것입니다."

"빈혈 도메인 모델은 안티 패턴입니다. 안티 패턴에는 전문가가 없습니다."

빈혈 도메인 모델이 반 패턴인지 여부는 의견의 문제입니다. Martin Fowler는 OO를 완전히 알고있는 많은 개발자들이 그렇지 않다고 말합니다. 의견을 사실로 말하는 것은 거의 도움이되지 않습니다.

An, 비록 그것이 일반적으로 반 패턴으로 받아 들여 졌다고하더라도, 여전히 약간의 (비록 적지 만) 상승 여력이있을 가능성이 있습니다.


Fowler의 주된 반대는 다음과 같은 의미에서 ADM이 OO가 아니라는 것 같습니다. 다른 코드에 의해 조작되는 수동적 데이터 구조를 중심으로 "처음부터"시스템을 설계한다면, 이것은 확실히 객체 지향 설계보다 절차 적 설계에 더 가깝습니다.

나는 이런 종류의 디자인을 만들 수있는 최소한 두 가지 힘이 있다고 제안합니다.

  1. 시스템 을 생성하기 위해 객체 지향 환경에서 작업해야한다고 생각하는 디자이너 / 프로그래머 (또는 ... 할 수 있다고 가정)

  2. 언어에 관계없이 OO가 아닌 방식으로 설계된 레거시 시스템 에 서비스와 같은 "얼굴"을 배치하기 위해 노력하는 개발자 .

예를 들어 기존 COBOL 메인 프레임 애플리케이션의 기능을 노출하기 위해 서비스 세트를 구축하는 경우 내부 COBOL 데이터 구조를 미러링 하지 않는 개념적 모델 측면에서 서비스 및 인터페이스를 정의 할 수 있습니다 . 그러나 서비스가 기존의 숨겨진 구현을 사용하기 위해 새 모델을 레거시 데이터에 매핑하는 경우 새 모델은 Fowler의 기사 (예 : TransferObject 스타일 정의 집합)의 의미에서 "빈혈"이 될 수 있습니다. 실제 행동이없는 관계.

이러한 종류의 타협은 이상적으로 순수한 OO 시스템이 기존의 비 OO 환경과 상호 작용해야하는 경계에서 매우 일반적 일 수 있습니다.


빈혈 도메인 모델 (ADM)은 팀이 리치 도메인 모델 (RDM)을 구축 할 수 없거나 시간이 지남에 따라 유지 관리 할 수없는 경우 좋은 선택이 될 수 있습니다. RDM으로 승리하려면 시스템에서 사용되는 지배적 인 추상화에주의를 기울여야합니다. 어떤 개발 그룹에서든 구성원의 절반 이상, 아마도 10 분의 1만이 추상화에 능숙하다는 것을 알 수 있습니다. 이 간부 (아마도 한 명의 개발자 만)가 전체 그룹의 활동에 대한 영향력을 유지할 수 없다면 RDM은 엔트로피에 굴복 할 것입니다.

And the entropic RDM hurts, in particular ways. Its developers will learn harsh lessons. At first they will be able to meet the expectations of their stakeholders, because they will have no history to live up to. But as their system becomes more complicated (not complex) it will become brittle; the developers will try to reuse code but tend to induce new bugs or back-track in development (and thus overrun their estimates).

In contrast, the ADM developers will set lower expectations for themselves, because they won't expect to reuse as much code for new features. Over time they will have a system with many inconsistencies, but it probably won't break unexpecredly. Their time to market will be longer than with a successful RDM, but their stakeholders are unlikely to perceive this possibility.


"Developers working to put a service-like "face" on a legacy system designed in a non-OO fashion (regardless of language)."

If you think of many LOB applications, these legacy systems will often not use the same domain model as you do. The Anemic Domain Model solves this with the use of business logic in service classes. You could put all this interface code inside your model (in the traditional OO sense) - but you typically end up losing modularity.


When I first came across the Anemic Domain Model article I thought "holy s***, that's what I do. horror!" I persevered and followed the references to Eric Evan's book, held to be a good example, and downloaded the source. It turns out that "not using an Anemic Domain Model" does not mean "not using service classes, not using mediators, not using strategies" or even "putting logic on the class being manipulated".

The DDD examples have service classes, XyzUpdaters, singletons and IoC.

I remain confused by exactly what an Anemic Domain Model is. I expect "I'll know it when I see it". For now I'm content with a positive example of good design.


It's the same pro as with most anti-patterns: it allows you to keep a lot of people busy for a long time. As managers tend to be paid more when they manage more people, there is a strong incentive not to improve.


Having worked with a 'mature' system with an ADM and feel I can provide some, at least, anecdotal feedback to this question.

1) Lack of Encapsulation

In a live system with an ADM there is the possibility to write e.g. 'obj.x = 100; obj.save', even if this violates business logic. This leads to a number of bugs that would not be encountered if the invariants were modelled on the object. It is the severity and pervasiveness of these bugs that I feel is the most serious negative to an ADM.

I feel it important to point out here that this is where a functional solution, and the procedural solutions of an ADM differ significantly and any similarities that others may have drawn to the surface similarities between an ADM and a functional solution are incidental.

2) Code bloat

I estimate that the amount of code produced in an ADM is 5-10x that which an OOP/RDM solution would create. This is accounted for by perhaps 50% being code repetition, 30% being boiler plate code, and 20% being the solving or resolving of problems which arise from the lack of a RDM.

3) Poor understanding of the domain problems

An ADM and a poor understanding of the domain problems go somewhat hand in hand. Naive solutions arise, requirements are poorly considered due to the difficulty of supporting them with the existing DM, and the ADM becomes a significant barrier to business innovation given the longer development times and lack of flexibility.

4) Difficulty of maintenance

A certain level of rigour is required to ensure that a domain concept is changed in all the places it is expressed, given that the concept may not be just a copy and paste re-implementation. This often leads to the same bugs being investigated and fixed on multiple occasions.

5) Increased difficulty with on-boarding

I think one of the benefits of a RDM is the cohesion of concepts which allow a faster understanding of the domain. With an ADM concepts may be fragmented and lacking clarity hence harder for new developers to acquire.

I was also tempted to include the operational support costs for an ADM being higher than for an RDM but this would depend on a number of factors.

As others have pointed out, look at DDD (Greg Evans, Vince Vaughn, and Scott Millett) for the benefits of a RDM.


In line with Eric P's answer as well as what some others above wrote, it seems that the main disadvantage of an ADM is the loss of OOD, specifically of keeping the logic and data of a domain concept together so that the implementation details are hidden while the API can be rich.

Eric goes on to point out that there's often information outside a domain class that is necessary for the logic of acting on that class, such as checking an inventory before adding an item to an order. I question, though, whether the answer is a Service layer that holds this overarching logic, or whether it's better handled as part of the object design. Somebody has to know about the Inventory object, the Product object and the Order object. Perhaps it's simply an OrderSystem object, which has an Inventory member, a list of Orders and so forth. This won't look very different from a Service, but I think it's conceptually more coherent.

Or look at it this way: You can have a User with an internal credit balance, and every time that User.addItemToOrder(item) is called it gets the item's price and checks the credit before adding it, etc. That seems a reasonable OO design. I'm not sure precisely what's lost by replacing that with Service.addItemToUserOrder(user, item), but I'm not sure what's gained, either. I guess a loss would be the extra layer of code, plus the clunkier style of writing and the enforced ignorance of the underlying Domain Model.


It gives better predictability. Managers like that, especially if the project is paid time & materials. Every change means a lot of work, so difficult work can be hidden behind lots of repetitive work. In a well-designed DRY system, predictability is very bad, as you are constantly doing new things.


To extend Michael's answer I'd have thought it's (fairly) clear where that code should go: into a dedicated Mediator that handles the interaction betwene the Order and the Inventory.

From my POV the key thing about the domain is that it MUST hold the simple testing behaviour the isInThisState() methods etc. In my experience these are also scattered throughout the service tears (sic :)) in most companies, and either copied ar endlessly rewritten. All of which breaks standard conhesion rules.

In my view the approach should be to aim for a DM that holds as much of the biz beahaviour as is practical, put the rest in clearly designated areas (ie not in the services)


My team personally prefers the ADM. we have a set of business objects that represent specific parts of our domain. We use services to save these objects to the db. Our business objects do have methods, however these methods only manipulate it's internal state.

The benefit for us in using the ADM over RDM can be seen in how we persist the objects to db. Developers working on our legacy code systems can use our business objects(from the new system)and continue using their current data access layer to persist these objects to the db. Using the RDM would force developers of our legacy system to inject Repository objects into our business model...which would not be consistent with their current data access layer.


It should be noted that as systems grow in complexity and granularity of variation, the encapsulation and consolidation of interface points afforded by a well designed message-passing object model make it much safer to change and maintain critical code without widespread refactoring.

The service layers created by the ADM, while certainly easier to implement (since they require relatively little thought and have many decentralized interface points) will likely create trouble down the road when it is time to modify a live and growing system.

I might add also that not all cases call for a domain model at all (let alone the ADM one). Sometimes it is better to use a more procedural / functional style of the task is data driven and does not depend on application-wide logic / business rules.

전체 앱의 장단점을 결정하려는 경우 한 줄의 코드 작성을 시작하기 전에 먼저 주어진 응용 프로그램에 대해 각각의 모양을 디자인하는 것이 중요하다고 생각합니다. 두 가지 스타일로 응용 프로그램을 CRC 또는 와이어 프레임 한 후에는 한 걸음 물러서서 어느 것이 더 합리적이고 응용 프로그램에 더 잘 맞는지 결정하십시오.

또한 어느 것이 유지하기 더 쉬울 지 미리 생각하십시오.


빈혈 도메인 모델은 안티 패턴이다. 안티 패턴에는 전문가가 없습니다.

참고 URL : https://stackoverflow.com/questions/258534/anemic-domain-model-pros-cons

반응형