Model domeny bogatej vs anemicznej [zamknięty]

98

Decyduję, czy powinienem użyć Rich Domain Model zamiast Anemic Domain Model i szukam dobrych przykładów tych dwóch.

Budowałem aplikacje internetowe przy użyciu Anemic Domain Model, wspieranego przez system warstwy Service -> Repository -> Storage , używając FluentValidation do walidacji BL i umieszczając wszystkie moje BL w warstwie usług.

Przeczytałem książkę DDD Erica Evana i on (wraz z Fowlerem i innymi) wydaje się myśleć, że Anemic Domain Models jest anty-wzorcem.

Tak więc naprawdę chciałem uzyskać wgląd w ten problem.

Poza tym naprawdę szukam dobrych (podstawowych) przykładów Rich Domain Model i korzyści w stosunku do Anemic Domain Model, który zapewnia.

Sam
źródło
Możesz również sprawdzić tego bloga, który przemawia za modelem domeny anemicznej
Japheth Ongeri - inkalimeva
14
DDD> ADM , ADM> DDD , DDD> ADM , ADM> DDD , ADM + DDD ... DDD / ADM, czyli jak nie zgodzić się na projekt oprogramowania !
sp00m
Oto przykład, jak uniknąć anemicznego modelu domeny: medium.com/@wrong.about/ ...
Vadim Samokhin
11
To zabawne, że na to pytanie można było odpowiedzieć za pomocą jednego linku do rzeczywistego projektu finansowanego przez prawdziwą organizację. Po 5 latach brak dobrej odpowiedzi, IMO. Rozmowa jest tania. Pokaż mi kod.
Mateusz Stefek

Odpowiedzi:

57

Różnica polega na tym, że model anemiczny oddziela logikę od danych. Logika jest często umieszczane w zajęciach nazwanych **Service, **Util, **Manager, **Helperi tak dalej. Te klasy implementują logikę interpretacji danych i dlatego przyjmują model danych jako argument. Na przykład

public BigDecimal calculateTotal(Order order){
...
}

podczas gdy podejście z bogatą domeną odwraca to, umieszczając logikę interpretacji danych w bogatym modelu domeny. W ten sposób łączy logikę i dane, a bogaty model domeny wyglądałby następująco:

order.getTotal();

Ma to duży wpływ na spójność obiektu. Ponieważ logika interpretacji danych opakowuje dane (dostęp do danych można uzyskać tylko za pomocą metod obiektowych), metody mogą reagować na zmiany stanu innych danych -> To właśnie nazywamy zachowaniem.

W modelu anemicznym modele danych nie mogą zagwarantować, że są w stanie legalnym, podczas gdy w bogatym modelu domeny mogą. Model bogatej domeny stosuje zasady OO, takie jak hermetyzacja, ukrywanie informacji oraz łączenie danych i logiki, a zatem model anemiczny jest anty-wzorcem z perspektywy obiektu obiektowego.

Aby uzyskać głębszy wgląd, zajrzyj na mój blog https://www.link-intersystems.com/blog/2011/10/01/anemic-vs-rich-domain-models/

René Link
źródło
15
Załóżmy, że obliczenie łącznej ceny zamówienia obejmuje: 1) Zastosowanie rabatu, który jest uzależniony od uczestnictwa klienta w jednym z wielu programów lojalnościowych. 2) Stosowanie rabatu przy zamówieniach zawierających razem określoną grupę artykułów w zależności od aktualnie prowadzonej przez sklep akcji marketingowej. 3) Obliczanie podatku, którego wysokość zależy od konkretnej pozycji zamówienia. Twoim zdaniem, do czego miałaby należeć ta cała logika? Czy mógłbyś podać prosty przykład pseudokodu. Dziękuję Ci!
Nik
4
@Nik W bogatym modelu Zamówienie miałoby odniesienie do obiektu Customer, a obiekt Customer miałoby odniesienie do Programu Lojalnościowego. W ten sposób Zakon miałby dostęp do wszystkich potrzebnych mu informacji bez konieczności wyraźnych odniesień do takich rzeczy, jak usługi i repozytoria, z których można pobrać te informacje. Wydaje się jednak, że łatwo trafić na przypadek, w którym pojawiają się cykliczne odniesienia. Tj. Zamówienie odwołuje się do klienta, klienta ma listę wszystkich zamówień. Myślę, że może to częściowo dlatego, że ludzie wolą teraz Anemic.
zmiażdż
3
@crush Podejście, które opisujesz, działa naprawdę dobrze. Jest jeden haczyk. Prawdopodobnie przechowujemy jednostki w bazie danych. Tak więc, aby obliczyć sumę zamówienia, musimy pobrać z bazy danych zamówienie, klienta, program lojalnościowy, kampanię marketingową, tabelę podatków. Weź również pod uwagę, że klient ma kolekcję zamówień, program lojalnościowy ma kolekcję klientów i tak dalej. Jeśli naiwnie pobierzemy to wszystko, w końcu załadujemy cały DB do pamięci RAM. To oczywiście nie jest wykonalne, więc uciekamy się do ładowania tylko odpowiednich danych z bazy danych ... 1/2
Nik
3
@Nik "Jeśli pobieramy je wszystkie natywnie, załadujemy całą bazę danych do pamięci RAM." To także jedna z głównych wad bogatego modelu. Bogaty model jest fajny, dopóki domena nie stanie się duża i złożona, a potem nie zaczniesz napotykać ograniczeń infrastruktury. W tym przypadku ORM z leniwym ładowaniem może jednak przyjść z pomocą. Znajdź dobry, a możesz zachować bogate modele, nie ładując całej bazy danych do pamięci, gdy potrzebujesz jej tylko 1/20. To powiedziawszy, sam zwykle używam Modelu Anemicznego z CQRS po wielu latach przechodzenia między anemią a bogactwem.
zmiażdżyć
2
Inną rzeczą do rozważenia jest miejsce, w którym znajduje się logika domeny biznesowej. Coraz więcej programistów przenosi go z bazy danych i do aplikacji, do których moim zdaniem należy. Ale jeśli utkniesz w sytuacji, w której Twoja firma wymaga, aby logika biznesowa pozostała w warstwie bazy danych (procedurach składowanych), prawie na pewno nie odniesiesz korzyści z dodania tej logiki w bogatym modelu domeny. W rzeczywistości możesz po prostu ustawić się na konflikty, w których procedury składowane mają inne reguły niż warstwa domeny aplikacji ...
zmiażdżyć
53

Bozhidar Bozhanov wydaje się opowiadać za modelem anemicznym w tym poście na blogu.

Oto podsumowanie, które przedstawia:

  • obiekty domeny nie powinny być zarządzane wiosną (IoC), nie powinny mieć DAO ani niczego związanego z infrastrukturą w nich wstrzykniętą

  • obiekty domeny mają obiekty domeny, od których zależą, ustawiane przez hibernację (lub mechanizm trwałości)

  • obiekty domeny wykonują logikę biznesową, zgodnie z ideą DDD, ale nie obejmuje to zapytań do bazy danych ani CRUD - tylko operacje na wewnętrznym stanie obiektu

  • rzadko są potrzebne DTO - obiekty domeny to w większości przypadków same DTO (co pozwala zaoszczędzić trochę kodu standardowego)

  • usługi wykonują operacje CRUD, wysyłają e-maile, koordynują obiekty domeny, generują raporty w oparciu o obiekty wielu domen, wykonują zapytania itp.

  • warstwa usług (aplikacji) nie jest tak cienka, ale nie zawiera reguł biznesowych, które są nieodłączne dla obiektów domeny

  • należy unikać generowania kodu. Abstrakcji, wzorców projektowych i DI należy używać, aby przezwyciężyć potrzebę generowania kodu, a ostatecznie - aby pozbyć się duplikowania kodu.

AKTUALIZACJA

Niedawno czytałem ten artykuł, w którym autorka opowiada się za podejściem hybrydowym - obiekty domenowe mogą odpowiadać na różne pytania wyłącznie na podstawie ich stanu (co w przypadku modeli całkowicie anemicznych prawdopodobnie odbyłoby się w warstwie usługowej)

geoand
źródło
11
Nie mogę wyciągnąć z tego artykułu, że Bozho wydaje się argumentować na korzyść modelu domeny anemicznej. warstwa usług (aplikacji) nie jest tak cienka, ale nie zawiera reguł biznesowych, które są nieodłączne dla obiektów domeny . Rozumiem, że obiekty domeny powinny zawierać logikę biznesową, która jest dla nich nieodłączna, ale nie powinny zawierać żadnej innej logiki infrastruktury . To podejście wcale nie wydaje mi się anemicznym modelem domeny.
Utku
8
Również ten: obiekty domeny wykonują logikę biznesową, zgodnie z podstawową ideą DDD, ale nie obejmuje to zapytań do bazy danych ani operacji CRUD - tylko operacji na wewnętrznym stanie obiektu . Te stwierdzenia nie wydają się w ogóle faworyzować modelu domeny anemicznej. Stwierdzają tylko, że logika infrastruktury nie powinna być sprzężona z obiektami domeny. Tak przynajmniej rozumiem.
Utku
@Utku Moim zdaniem wydaje się dość jasne, że Bozho opowiada się za czymś w rodzaju hybrydy między dwoma modelami, hybrydy, która, powiedziałbym, jest bliższa modelowi anemicznemu niż modelowi bogatemu.
geo i
41

Mój punkt widzenia jest taki:

Model domeny anemicznej = tabele bazy danych odwzorowane na obiekty (tylko wartości pól, brak rzeczywistego zachowania)

Model domeny bogatej = kolekcja obiektów, które ujawniają zachowanie

Jeśli chcesz stworzyć prostą aplikację CRUD, może wystarczy model anemiczny z klasycznym frameworkiem MVC. Ale jeśli chcesz zaimplementować jakąś logikę, model anemiczny oznacza, że ​​nie będziesz robić programowania obiektowego.

* Zauważ, że zachowanie obiektu nie ma nic wspólnego z trwałością. Za utrwalanie obiektów domeny odpowiada inna warstwa (mapery danych, repozytoria itp.).

Jerzy
źródło
5
Przepraszam za moją ignorancję, ale w jaki sposób bogaty model domeny może podążać za SOLID principe, jeśli umieścisz całą logikę związaną z Entity w klasie. To narusza SOLID principe, dokładnie „S”, które oznacza pojedynczą odpowiedzialność, która mówi, że klasa powinna robić tylko jedną rzecz i robić to dobrze.
redigaffi
6
@redigaffi To zależy od tego, jak zdefiniujesz „jedną rzecz”. Rozważmy klasę z dwóch właściwości i dwiema metodami: x, y, sumi difference. To cztery rzeczy. Możesz też argumentować, że to dodawanie i odejmowanie (dwie rzeczy). Możesz też argumentować, że to matematyka (jedno). Istnieje wiele postów na blogach o tym, jak znaleźć równowagę w stosowaniu SRP. Oto jeden: hackernoon.com/…
Rainbolt,
2
W DDD pojedyncza odpowiedzialność oznacza, że ​​klasa / model może zarządzać swoim własnym stanem bez powodowania żadnych skutków ubocznych dla reszty systemu jako całości. Każda inna definicja po prostu prowadzi do żmudnych filozoficznych debat z mojego doświadczenia.
ZombieTfk
12

Przede wszystkim skopiowałem wklejoną odpowiedź z tego artykułu http://msdn.microsoft.com/en-gb/magazine/dn385704.aspx

Rysunek 1 przedstawia Anemic Domain Model, który jest w zasadzie schematem z pobierającymi i ustawiającymi.

Figure 1 Typical Anemic Domain Model Classes Look Like Database Tables

public class Customer : Person
{
  public Customer()
  {
    Orders = new List<Order>();
  }
  public ICollection<Order> Orders { get; set; }
  public string SalesPersonId { get; set; }
  public ShippingAddress ShippingAddress { get; set; }
}
public abstract class Person
{
  public int Id { get; set; }
  public string Title { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string CompanyName { get; set; }
  public string EmailAddress { get; set; }
  public string Phone { get; set; }
}

W tym bogatszym modelu, zamiast po prostu ujawniać właściwości do odczytu i zapisu, publiczna powierzchnia Klienta jest utworzona z jawnych metod.

Figure 2 A Customer Type That’s a Rich Domain Model, Not Simply Properties

public class Customer : Contact
{
  public Customer(string firstName, string lastName, string email)
  {
    FullName = new FullName(firstName, lastName);
    EmailAddress = email;
    Status = CustomerStatus.Silver;
  }
  internal Customer()
  {
  }
  public void UseBillingAddressForShippingAddress()
  {
    ShippingAddress = new Address(
      BillingAddress.Street1, BillingAddress.Street2,
      BillingAddress.City, BillingAddress.Region,
      BillingAddress.Country, BillingAddress.PostalCode);
  }
  public void CreateNewShippingAddress(string street1, string street2,
   string city, string region, string country, string postalCode)
  {
    ShippingAddress = new Address(
      street1,street2,
      city,region,
      country,postalCode)
  }
  public void CreateBillingInformation(string street1,string street2,
   string city,string region,string country, string postalCode,
   string creditcardNumber, string bankName)
  {
    BillingAddress = new Address      (street1,street2, city,region,country,postalCode );
    CreditCard = new CustomerCreditCard (bankName, creditcardNumber );
  }
  public void SetCustomerContactDetails
   (string email, string phone, string companyName)
  {
    EmailAddress = email;
    Phone = phone;
    CompanyName = companyName;
  }
  public string SalesPersonId { get; private set; }
  public CustomerStatus Status { get; private set; }
  public Address ShippingAddress { get; private set; }
  public Address BillingAddress { get; private set; }
  public CustomerCreditCard CreditCard { get; private set; }
}
Razan Paul
źródło
2
Występuje problem z metodami, które zarówno tworzą obiekt, jak i przypisują właściwość do nowo utworzonego obiektu. Dzięki nim kod jest mniej rozszerzalny i elastyczny. 1) A co, jeśli konsument kodu nie chce tworzyć Address, ale ExtendedAddressodziedziczyć Addressz kilkoma dodatkowymi właściwościami? 2) Lub zmienić CustomerCreditCardparametry konstruktora, które mają być przyjmowane BankIDzamiast BankName?
Lightman
Co to jest tworzenie adresu wymaga dodatkowych usług niż to, co składa się na obiekt? Pozostaje Ci wstrzyknięcie metody, aby uzyskać te usługi. A jeśli to dużo usług?
zmiażdż
8

Jedną z zalet bogatych klas domeny jest to, że możesz wywołać ich zachowanie (metody) za każdym razem, gdy masz odwołanie do obiektu w dowolnej warstwie. Ponadto masz tendencję do pisania małych i rozproszonych metod, które współpracują ze sobą. W klasach domeny anemicznej masz tendencję do pisania grubych metod proceduralnych (w warstwie usług), które są zwykle kierowane przez przypadek użycia. Zazwyczaj są trudniejsze w utrzymaniu w porównaniu z bogatymi klasami domen.

Przykład klas domeny z zachowaniami:

class Order {

     String number

     List<OrderItem> items

     ItemList bonus

     Delivery delivery

     void addItem(Item item) { // add bonus if necessary }

     ItemList needToDeliver() { // items + bonus }

     void deliver() {
         delivery = new Delivery()
         delivery.items = needToDeliver()
     }

}

Metoda needToDeliver()zwróci listę elementów, które należy dostarczyć, w tym premię. Można go wywołać wewnątrz klasy, z innej pokrewnej klasy lub z innej warstwy. Na przykład, jeśli przejdziesz Orderdo przeglądania, możesz użyć needToDeliver()zaznaczonych Orderdo wyświetlenia listy pozycji do potwierdzenia przez użytkownika przed kliknięciem przycisku Zapisz, aby zachować plik Order.

Odpowiadanie na komentarz

Oto jak używam klasy domeny z kontrolera:

def save = {
   Order order = new Order()
   order.addItem(new Item())
   order.addItem(new Item())
   repository.create(order)
}

Stworzenie Orderi LineItemto w jednej transakcji. Jeśli jednego z LineItemnie można utworzyć, nie Orderzostanie utworzony.

Zwykle mam metodę, która reprezentuje pojedynczą transakcję, na przykład:

def deliver = {
   Order order = repository.findOrderByNumber('ORDER-1')
   order.deliver()       
   // save order if necessary
}

Wszystko w środku deliver()zostanie wykonane jako jedna transakcja. Gdybym potrzebował wykonać wiele niepowiązanych metod w jednej transakcji, utworzyłbym klasę usług.

Aby uniknąć leniwego ładowania, używam nazwanego wykresu encji JPA 2.1. Na przykład w kontrolerze ekranu dostawy mogę utworzyć metodę ładowania deliveryatrybutu i ignorowania bonus, taką jak repository.findOrderByNumberFetchDelivery(). Na ekranie bonusowym wywołuję inną metodę, która ładuje bonusatrybut i ignoruje delivery, na przykład repository.findOrderByNumberFetchBonus(). To wymaga dyscypliny, ponieważ nadal nie mogę zadzwonić deliver()na ekranie bonusowym.

jocki
źródło
1
A co z zakresem transakcji?
kboom
5
Zachowania modelu domeny nie powinny zawierać logiki trwałości (w tym transakcji). Powinny być testowalne (w teście jednostkowym) bez połączenia z bazą danych. Za zakres transakcji odpowiada warstwa usług lub warstwa trwałości.
jocki
1
A co powiesz na leniwe ładowanie?
kboom
Podczas tworzenia wystąpień klas domeny w teście jednostkowym nie są one w stanie zarządzanym, ponieważ są zwykłymi obiektami. Wszystkie zachowania można odpowiednio przetestować.
jocki
A co się dzieje, gdy spodziewasz się, że obiekt domeny będzie pochodził z warstwy usług? Czy w takim razie nie jest zarządzany?
kboom
8

Kiedy pisałem monolityczne aplikacje desktopowe, tworzyłem rozbudowane modele domen, które dawniej czerpałem radość z ich tworzenia.

Teraz piszę małe mikrousługi HTTP, jest jak najmniej kodu, w tym anemiczne DTO.

Myślę, że DDD i ten anemiczny argument pochodzą z ery monolitycznych aplikacji na komputery stacjonarne lub serwery. Pamiętam tamtą epokę i zgodzę się, że anemiczne modele są dziwne. Zbudowałem dużą, monolityczną aplikację do handlu walutami i nie było modelu, naprawdę, to było okropne.

W przypadku mikrousług małe usługi z ich bogatym zachowaniem są prawdopodobnie modelami i agregatami, które można komponować w ramach domeny. Dlatego same implementacje mikrousług mogą nie wymagać dalszego DDD. Aplikacja mikrousług może być domeną.

Mikrousługa zamówień może mieć bardzo mało funkcji, wyrażonych jako zasoby RESTful lub przez SOAP lub cokolwiek innego. Kod mikrousługi zamówień może być niezwykle prosty.

Większa, bardziej monolityczna pojedyncza (mikro) usługa, szczególnie taka, która utrzymuje model w pamięci RAM, może skorzystać na DDD.

Luke Puplett
źródło
Czy masz jakieś przykłady kodu dla mikrousług HTTP, które reprezentują Twój obecny stan wiedzy? Nie prosząc o nic więcej, po prostu udostępnij linki, jeśli masz coś, na co możesz wskazać. Dzięki.
Casey Plummer
3

Myślę, że źródłem problemu jest fałszywa dychotomia. Jak można wyodrębnić te 2 modele: bogaty i „anemiczny” i zestawić je ze sobą? Myślę, że jest to możliwe tylko wtedy, gdy masz błędne wyobrażenie o tym, czym jest klasa . Nie jestem pewien, ale wydaje mi się, że znalazłem to w jednym z filmów Bozhidara Bozhanova na Youtube. Klasa nie jest danymi + metodami na tych danych. Jest to całkowicie błędne rozumienie, które prowadzi do podziału klas na dwie kategorie: tylko dane, a więc model anemiczny i dane + metody - tak bogaty model (aby być bardziej poprawnym, istnieje trzecia kategoria: tylko metody).

Prawdą jest, że klasa jest pojęciem w pewnym modelu ontologicznym, słowem, definicją, terminem, ideą, to DENOTAT . I to zrozumienie eliminuje fałszywą dychotomię: nie można mieć TYLKO modelu anemicznego lub TYLKO bogatego modelu, ponieważ oznacza to, że twój model nie jest adekwatny, nie ma związku z rzeczywistością: niektóre pojęcia mają tylko dane, niektóre mają tylko metody, inne z nich są mieszane. Ponieważ staramy się opisać w tym przypadku pewne kategorie, zbiory obiektów, relacje, pojęcia z klasami, a jak wiemy, niektóre pojęcia są tylko procesami (metodami), niektóre z nich są tylko zbiorem atrybutów (danych), niektóre są to relacje z atrybutami (mieszane).

Uważam, że odpowiednia aplikacja powinna obejmować wszystkie rodzaje zajęć i unikać fanatycznego ograniczania się do jednego modelu. Bez względu na to, jak przedstawia się logika: za pomocą kodu lub z interpretowalnymi obiektami danych (takimi jak Free Monady ), w każdym razie: powinniśmy mieć klasy (pojęcia, denotaty) reprezentujące procesy, logikę, relacje, atrybuty, cechy, dane itp., A nie starać się unikać niektórych z nich lub sprowadzać wszystkie tylko do jednego rodzaju.

Możemy więc wyodrębnić logikę do innej klasy i pozostawić dane w oryginalnej, ale nie ma to sensu, ponieważ niektóre pojęcia mogą zawierać atrybuty i relacje / procesy / metody, a ich oddzielenie powieli pojęcie pod 2 nazwami, które mogą być zredukowane do wzorców: „OBJECT-Attributes” i „OBJECT-Logic”. Jest to dobre w językach proceduralnych i funkcjonalnych ze względu na ich ograniczenia, ale jest to nadmierne powściągliwość dla języka, który pozwala opisywać wszelkiego rodzaju koncepcje.

Losowe B.
źródło
1

Modele domen anemicznych są ważne dla ORM i łatwego transferu przez sieci (podstawa wszystkich komercyjnych aplikacji), ale OO jest bardzo ważne dla hermetyzacji i uproszczenia części kodu „transakcyjnej / obsługi”.

Dlatego ważna jest umiejętność identyfikacji i konwersji z jednego świata do drugiego.

Nazwij modele Anemic coś w rodzaju AnemicUser lub UserDAO itp., Aby programiści wiedzieli, że istnieje lepsza klasa do użycia, a następnie przygotuj odpowiedniego konstruktora dla klasy none Anemic

User(AnemicUser au)

i metodę adaptera, aby utworzyć klasę anemiczną na potrzeby transportu / trwałości

User::ToAnemicUser() 

Staraj się używać żadnego anemicznego użytkownika wszędzie poza transportem / trwałością

pasztet z andrzeja
źródło
-1

Oto przykład, który może pomóc:

Anemiczny

class Box
{
    public int Height { get; set; }
    public int Width { get; set; }
}

Bez anemii

class Box
{
    public int Height { get; private set; }
    public int Width { get; private set; }

    public Box(int height, int width)
    {
        if (height <= 0) {
            throw new ArgumentOutOfRangeException(nameof(height));
        }
        if (width <= 0) {
            throw new ArgumentOutOfRangeException(nameof(width));
        }
        Height = height;
        Width = width;
    }

    public int area()
    {
       return Height * Width;
    }
}
Alireza Rahmani Khalili
źródło
Wygląda na to, że można go przekonwertować na ValueObject w porównaniu z Entity.
code5
Tylko skopiuj wklej z Wikipedii bez żadnego wyjaśnienia
wst
kto napisał wcześniej? @wst
Alireza Rahmani Khalili
@AlirezaRahmaniKhalili według historii Wikipedii to oni byli pierwsi ... Chyba że nie zrozumiałem twojego pytania.
wst
-1

Klasyczne podejście do DDD nie stanowi, aby za wszelką cenę unikać modeli Anemic vs Rich. Jednak MDA może nadal stosować wszystkie koncepcje DDD (ograniczone konteksty, mapy kontekstowe, obiekty wartości itp.), Ale we wszystkich przypadkach używać modeli Anemic vs Rich. Istnieje wiele przypadków, w których korzystanie z usług domenowych do organizowania złożonych przypadków użycia domeny w zestawie agregatów domen jest znacznie lepszym podejściem niż tylko wywoływanie agregatów z warstwy aplikacji. Jedyną różnicą w stosunku do klasycznego podejścia DDD jest to, gdzie znajdują się wszystkie walidacje i reguły biznesowe? Istnieje nowa konstrukcja znana jako walidatory modeli. Walidatory zapewniają integralność pełnego modelu wejściowego przed każdym przypadkiem użycia lub przepływem pracy w domenie. Zagregowane jednostki główne i podrzędne są anemiczne, ale każda z nich może mieć własne walidatory modelu wywoływane w razie potrzeby, przez jego główny walidator. Walidatory nadal są zgodne z SRP, są łatwe w utrzymaniu i można je testować jednostkowo.

Przyczyną tej zmiany jest to, że teraz zmierzamy bardziej w kierunku najpierw interfejsu API niż pierwszego podejścia UX do mikrousług. REST odegrał w tym bardzo ważną rolę. Tradycyjne podejście API (ze względu na SOAP) zostało początkowo naprawione na podstawie poleceń API w porównaniu z czasownikami HTTP (POST, PUT, PATCH, GET i DELETE). Interfejs API oparty na poleceniach dobrze pasuje do podejścia obiektowego Rich Model i nadal jest bardzo ważny. Jednak proste interfejsy API oparte na CRUD, chociaż mogą pasować do modelu bogatego, są znacznie lepiej dostosowane do prostych modeli anemicznych, walidatorów i usług domenowych, aby zaaranżować resztę.

Uwielbiam DDD we wszystkim, co ma do zaoferowania, ale przychodzi czas, gdy trzeba go trochę rozciągnąć, aby pasował do ciągle zmieniającego się i lepszego podejścia do architektury.

kod5
źródło