Mapowanie na Domain Model

0

Jak powinno się implementować Domain Model wraz z ORM.?
Dużo robi się krzyku o to że setery są be bo "naruszają" enkapsulacje.
Tylko, że nikt nigdy nie mówi o konkretnym bugu, w tej konkretnej sytuacji.

Prosty przykład Encji (bez sensu ale mniejsza o to)

public class Order : IValidation
    {
        private string _orederAmount;

        public virtual int Id { get; protected set; }
        public virtual string OrederAmount
        {
            get => _orederAmount;
            protected set => _orederAmount = value;
        }
        public ValidationResult ValidationResult { get; private set; }

        public bool IsValid
        {
            get
            {
                var fiscal = new OrderIsValidValidation();
                ValidationResult = fiscal.Valid(this);
                return ValidationResult.IsValid;
            }
        }

        public decimal Profit(decimal tax)
        {
             var amount = _orederAmount;
            //....
        }
    }

Potem w serwisie mapuje na to tabele Order za pomocą Nhibernate. Co można zarzucić takiemu podejściu?

Spotkałem się z opinią że tak nie wolno, że Presistance dla ORM powinno być oddzielnym bytem a Domain Model To taki adapter na te presistance.
No więc pytam.

0

Jak dla mnie, to po prostu łamanie SRP, a problem może się pojawić wtedy, gdy na tej samej tabeli będzie opartych wiele operacji biznesowych, i taka klasa będzie miała masę metod, które mają sens tylko w określonym kontekście. Zrobi się z tego jakiś god object.
Dla prostych przypadków wolę już mieć model bez logiki i operujące na nim proceduralnie serwisy niż takich biznesowo-bazodanowych transwestytów w kodzie.

0

Wydaje mi się, że przesadzasz, Gdzie te złamanie SRP, że niby Validacja? To twój ogólny problem do Domain Model i DDD. Czy po prostu implementacja ci się nie podoba ?

0

i taka klasa będzie miała masę metod, które mają sens tylko w określonym kontekście. Zrobi się z tego jakiś god object.

A to zleży co dla ciebie jest usługą a co encją z kontekstu dziedziny...

0

Sam siebie waliduje, sam wylicza swój podatek... Potem do tego dojdzie samodzielne wyliczanie obniżki ceny, później samodzielne wyliczenie okresów rozliczeniowych dla zamówień cyklicznych... I tak dalej.

O ile w prostych przypadkach od biedy możesz takie rozwiązanie popełnić, to niestety obawiam się, że bardzo szybko przypadek przestanie być prosty, a Ty zaczniesz rwać włosy z łydek, bo zrobi Ci się kaszana kodzie i to cudo zrobi się takim właśnie god-class.

SRP łamie toto choćby z powodu właśnie walidacji samego siebie. Choć pewno ktoś by mi za to stwierdzenie chętnie urwał kabel od internetu, to od walidacji są osobne mechanizmy, bo samosądy są niefajną sprawą, a i później w sumie nie do końca wiadomo jak to sprzężyć z realną logiką aplikacji żeby wyglądało po ludzku. Tak samo już wyliczanie podatku prawdopodobnie bym odseparował, bo w zależności od systemu prawnego sposób obliczania może się zupełnie różnić, niekoniecznie tylko wysokością ale jakąś większą logiką.(fakt, że o ile się orientuję to czysta fantazja aktualnie, ale jednak jest to jakiś, prymitywny, rodzaj logiki wkraczającej już w domenę na moje oko)

PS: Za dużo edycji... Teraz spojrzałem, że odseparowane to niby jest, choć znowu tworzysz tam sztywne powiązanie w ten sposób.
Nadal jednak podtrzymuję, że walidator lepiej wywołać zewnętrznie, bo wtedy możesz chociażby sterować scenariuszami walidacji w zależności od sytuacji przez, choćby, rzucenie argumentu.

0

Nie ważne, mniejsza o szczegóły pytanie brzmiało jak mapować na Domain Model ...!!

Racja te obliczanie podatku tu nie pasuje, pisałem w nawiasie że przykład jest bez sensu...
Ale widzę tutaj metody np. submit() która zmienia status zamówienia na submit, AddToArchive(), GetTotalCost i tp. Validacja to zależy jeśli chcesz sprawdzić czy np user istnieje w bazie to jest validacja po stronie logiki biznesowej, przecież nie użyjesz do tego ViewModel.

2

TL;DR
Jedyne co bym mógł zarzucić temu kawałkowi kodu nie znając szerszego kontekstu, to to że walidacja powinna być metodą a nie propertisem ;)


W obecnym podejściu niewiele można zarzucić temu fragmentu kodu, bo jest wyrwany z kontekstu i nie wiemy wszystkiego. No ale po kolei :

  • settery są "be" jeśli są publiczne, jeśli są prywatne lub chronione to nie naruszają enkapsulacji, no chyba że patrz punkt następny
  • czyli kwestia czy mieć oddzielny persistence model i domain model, czy jeden wspólny, jeśli nasze źródło danych jest modyfikowane tylko wyłącznie za pomocą naszego modelu, to jak najbardziej jeden model może być wystarczający, no chyba że tak nie jest, wtedy pojawia się punkt następny
  • czyli poprawność modelu do której wszystko się sprowadza(z tym ze model zawsze powinien być w poprawnym stanie prawie wszyscy się zgadzają w środowisku DDD)

Więc jeśli odtworzenie stanu modelu ze źródła danych nie może wprowadzić wspólnego modelu w stan niepoprawny to wszystko jest jak najbardziej okej (i setery i wspólny model):
-zawsze poprawne źródło danych -> ORM używa propertisów do odtworzenia stanu -> poprawny wspólny model
natomiast jeśli nasz scenariusz wygląda następująco (setetry są be, jak i wspólny model jest be)
-źródło danych które może być zmienione za plecami naszego modelu -> ORM używa propertisów do odtworzenia stanu -> dostajemy model w nie wiadomo w jakim stanie -> musimy walidować przy każdej próbie skorzystania z encji -> :(

Wiec pytanie czym jest walidacja i po co ona jest w tej encji?

  • jeśli do sprawdzenia czy niezmienniki danej encji są poprawne np (OrederAmount > 0), to oznacza że możemy mieć model w stanie niepoprawnym, a tego nie chcemy, model musi być zawsze poprawny
  • czy do sprawdzenia poprawności zamówienia z punktu biznesowego czyli np czy OrederAmount < od stanu magazynowego w chwili składania zamówienia, jest jak najbardziej okej

Odnośnie SRP i gdzie walidować, no to tutaj już nie ma konsensusu, jedni preferują encje, jedni serwisy biznesowe. Tak samo z tym liczeniem zysku, jeśli jest to coś bardzo prostego i niezmiennego uszło by zostawienie tego w encji, jakiś bardziej skomplikowany proces -> serwis.

**Podsumowując : model domenowy chcemy mieć zawsze w stanie poprawnym **

1
MrBean Bean napisał(a):

Wydaje mi się, że przesadzasz, Gdzie te złamanie SRP, że niby Validacja?

SRP jest złamane bo Order ma dwa powody do zmiany - zarówno zmianę logiki biznesowej jak i przechowywanych danych.
Wsadzenie tam jeszcze walidacja to też naruszenie SRP, ale głównym problemem jest co innego - encje nie powinny się walidować po utworzeniu na polecenie zewnętrznych obiektów, po prostu nie powinno być w ogóle możliwości utworzenia niespójnej encji. A więc walidacja powinna być zrealizowana na etapie tworzenia obiektu, najczęściej w konstruktorze.

To twój ogólny problem do Domain Model i DDD.

Ale jakiego DDD? Tu nic takiego nawet nie widać.

neves napisał(a):

W obecnym podejściu niewiele można zarzucić temu fragmentu kodu, bo jest wyrwany z kontekstu i nie wiemy wszystkiego. No ale po kolei :

To zależy co to miało być, bo jeśli DDD, to w tym kontekście można zarzucić wszystko.

Więc jeśli odtworzenie stanu modelu ze źródła danych nie może wprowadzić wspólnego modelu w stan niepoprawny to wszystko jest jak najbardziej okej (i setery i wspólny model):

Ale później, przy pomocy publicznych setterów można już ten model wprowadzić w stan niespójny, co nie jest OK, dlatego przy DDD nie powinno ich być.

-zawsze poprawne źródło danych

Coś takiego w ogóle istnieje?

Odnośnie SRP i gdzie walidować, no to tutaj już nie ma konsensusu, jedni preferują encje, jedni serwisy biznesowe.

W serwisach domenowych powinno się walidować tylko to, czego encja sama nie może.

0
neves napisał(a):

TL;DR
źródło danych które może być zmienione za plecami naszego modelu -> ORM używa propertisów do odtworzenia stanu -> dostajemy model w nie wiadomo w jakim stanie -> musimy walidować przy każdej próbie skorzystania z encji -> :(

Czyli chodzi ci o zbieżność w tym co zapisują różne źródła danych do sesji ORM? Mnie to wygląda jak źle napisany kod, to tak jak byś nie używał sesji tak jak powinieneś. Może podać jakiś przykład.?

0
somekind napisał(a):
MrBean Bean napisał(a):

Wydaje mi się, że przesadzasz, Gdzie te złamanie SRP, że niby Validacja?

Ale później, przy pomocy publicznych setterów można już ten model wprowadzić w stan niespójny, co nie jest OK, dlatego przy DDD nie powinno ich być.

Czytałem DDD Vrnona i Evana ale jakoś nikt nigdzie o tym nie wspomnieli raczej pachnie mi to Fowlerem i jego wywodami na temat Anemic Domain. Które i tak są trochę bezsensu bo to biznes deklaruje złożoność modelu a nie czyjeś zachcianki.

Jeśli masz taki z tym problem to przecież możesz zrobić sobie dwa konstruktory jeden pusty dla ORM i chronione propertysy i drugi constructor dla twojej dyspozycji wtedy nie będziesz mógł zmienić stanu po stworzeniu obiektu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1