Value objecty - walidacja

Odpowiedz Nowy wątek
2019-08-12 10:50
0

Dzień dobry
Value objecty to świetny sposób na modelowanie domeny, np. klasa Pesel jest o wiele bardziej prezycyjna niż String i łatwiej będzie zrozumiec o co chodzi. Jednak pojawia się pewien "problem".
Jesli mamy taka klase:


public final class Pesel {
 private final String value;

private Pesel(String value) {
  this.value = value;
 }

public static Pesel of(String pesel) {
  return new Pesel(pesel);
 }
}

Czy to nie powinniśmy w takiej metodze wytwórczej sprawdzać czy wartośc jest prawidłowa? Jesli tak, to co zrobić jeśli jest to wartośc nieprawidłowa? Wyrzucac runtimowy expetion?


Nie pomagam przez PM. Pytania zadaje się na forum.
Pokaż pozostałe 16 komentarzy
@danek: no i właśnie to miałem na myśli pisząc o przesłanianiu. - Wibowit 2019-08-12 15:08
Nie używam jak nie muszę, bo mi się nie chcę, ale uważam, że z this jest czytelniej. Narzucanie innym swojej estetyki w tak mało istotnej kwestii jest słabe. Ważne by było spójnie w całym projekcie. I też nie zawsze przeglądam kod w IDE, aż takie to dziwne? - nalik 2019-08-12 15:43
Ależ przeżywacie. Na szczęście z nikim nie musiałem się dogadywać w takiej kwestii, bo nie miałem w projekcie nikogo, kto by nadmiarowe this. wklepywał. W Scali to już absolutnie się takich ludzi nie spodziewam. Nie widziałem ani jednego kawałka Scalowego kodu z nadmiarowym this. - Wibowit 2019-08-12 15:47
W swoich własnych projektach wybieram konwencję z this, w pracowych jak wyjdzie, jest generalnie pół na pół. - somekind 2019-08-12 16:17
Co do review - jak znam taska (bo nad nim na bieżąco współpracowałem albo konsultowałem), to nie muszę kodu uruchamiać. Większość tasków jest jednak na tyle trywialna, że wystarczy rzut oka na GH, żeby stwierdzić, czy jest OK. Poza tym ja zazwyczaj robię PR Hindusom, więc najpierw odrzucam tak długo, aż doprowadzą go do stanu czytelności. Kodu niespełniającego konwencji, norm estetycznych albo zawierającego elementarne błędy (np. brak walidacji wejścia) nie ma sensu pobierać ani uruchamiać. - somekind 2019-08-12 16:17

Pozostało 580 znaków

2019-08-12 10:57
2

To zależy co rozumiesz poprzez prawidłową wartość. Jeśli to czy taki pesel faktycznie istnieje i aby to sprawdzić musisz komunikować się z jakimś serwisem to nie. Natomiast jeśli chodzi o walidację struktury samej wartości (np. czy ma określoną długość) to tak, powinieneś to sprawdzić i rzucić wyjątek jeśli wartość się nie zgadza. Value Objects podobnie jak "zwykłe" klasy powinny strzec swoich zasad.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.

Pozostało 580 znaków

2019-08-12 11:17
0

Natomiast jeśli chodzi o walidację struktury samej wartości (np. czy ma określoną długość) to tak, powinieneś to sprawdzić i rzucić wyjątek jeśli wartość się nie zgadza.

O to mi dokładnie chodziło, są reguły walidacji, np. w przypadku PESEL jest to suma kontrolna. Widziałem w kodzie takie obiekty których nie było to sprawdzane i stwierdziłem że coś nie tak


Nie pomagam przez PM. Pytania zadaje się na forum.

Pozostało 580 znaków

2019-08-12 12:27
3

A moze w takim razie:

public static Optional<Pesel> parsePesel(String pesel){

?


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2019-08-12 12:38
1

Jeśli te dane pochodzą gdzieś z frontu to to, że są nieprawidłowe wcale nie jest jakimiś wyjątkiem ;) Tak jak Shalom napisał albo Optional z SDK albo jak chcesz iść dalej w to to Either, gdzie możesz też zwrócić powód dla którego nie udało się coś wykonać


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.

Pozostało 580 znaków

2019-08-12 12:43
0

Ja bym w konstruktorze wytwórczej dał co najwyżej null/empty checka z runtime exception. Jakieś walidacje czy prawidłowy pesel etc do osobnych metod/klas

edytowany 1x, ostatnio: baant, 2019-08-12 12:51
powinno się bić po rękach za przekazywanie dalej nulli :P - danek 2019-08-12 12:44
przecież napisałem, że dałbym sprawdzanie nulla na wejściu - baant 2019-08-12 12:45

Pozostało 580 znaków

2019-08-12 12:44
0

No to ja wiem że jesli to wartośc z frontu to lepiej nie rzucać zawsze wyjątkiem, zawsze można zrobić 2 metody fabryczne ;)


Nie pomagam przez PM. Pytania zadaje się na forum.
edytowany 1x, ostatnio: scibi92, 2019-08-12 12:54
no właśnie odwrotnie. Jeśli spodziewasz się że wartość może być zła, wtedy to nie jest wyjątkowa :P - danek 2019-08-12 12:45
nie musisz sie spodziewac, mozesz sie przed nia bronic po prostu - baant 2019-08-12 12:46
@danek: tak, zjadłem "nie" :D - scibi92 2019-08-12 12:54
@scibi92: teraz ma sens :P - danek 2019-08-12 12:54

Pozostało 580 znaków

2019-08-12 12:47
1
baant napisał(a):

Ja bym w konstruktorze dał co najwyżej null/empty checka z runtime exception. Jakieś walidacje czy prawidłowy pesel etc do osobnych metod/klas

Skoro jest metoda wytwórcza to czemu pchać walidację do konstruktora? Jedną z większych zalet metod wytwórczych jest to, że dzięki nim można uniknąć efektów ubocznych w konstruktorze.


"Programs must be written for people to read, and only incidentally for machines to execute." - Abelson & Sussman, SICP, preface to the first edition
"Ci, co najbardziej pragną planować życie społeczne, gdyby im na to pozwolić, staliby się w najwyższym stopniu niebezpieczni i nietolerancyjni wobec planów życiowych innych ludzi. Często, tchnącego dobrocią i oddanego jakiejś sprawie idealistę, dzieli od fanatyka tylko mały krok."
Demokracja jest fajna, dopóki wygrywa twoja ulubiona partia.
chodziło mi o wytwórczą a napisałem konstruktor, pomyłeczka - baant 2019-08-12 12:49

Pozostało 580 znaków

2019-08-12 12:51
1

Według mnie, w takim przypadku konstruktor klasy powinien być prywatny (tak jak jest w Twoim przykładzie) i jedna metoda tworząca dany obiekt z pełną walidacją. Jako wynik albo Option, albo Either w zależności czy zależy Ci na przyczynie błędu czy nie. W ten sposób masz pewność, że w każdej metodzie przyjmującej typ Pesel masz poprawnie skonstruowany obiekt.

Pozostało 580 znaków

2019-08-12 12:58
0

Typowym rozwiązaniem (zaimplementowanym np. w Paths.get) jest metoda wytwórcza rzucająca wyjątek, np. IllegalArgumentException. Ja bym poszedł w tą stronę. Walidacja dla użytkownika może być przecież w całkiem innym miejscu. Dołożyłbym też pewnie statyczna metoda 'validate`.

edytowany 1x, ostatnio: tdudzik, 2019-08-12 13:03
To zły przykład, bo to API powstało przed JDK8. - nie100sowny 2019-08-12 14:05
Już pisałem, że w Scali stosuje sie podobne rozwiązania ;) - tdudzik 2019-08-12 14:15

Pozostało 580 znaków

2019-08-12 13:06
1

@tdudzik: to jest imo najgorsze rozwiązanie, bo robi coś czego się nie spodziewasz. Patrząc na sygnaturę 

public static Path get(String first, String... more)

Nie powinieneś się spodziewać (no dobra, większość się spodziewa, ale imo nie powinno sie) wyjątku w momencie raczej dość standardowym czyli podaniu złej ścieżki. Z resztą w jednym wątku podobnym podałem przykład

int parseInt(String s); //w sumie nie wiesz co się stanie bez czytania dokumentacji jak podasz "a"
Optional<Integer> parseInt(String s); //tu brak info o błędzie, ale już wiesz, że jakiś błąd może wystąpić
Either<ParseError, Integer> parseInt(String s); //info o ewentualnym błędzie. Wada: mało popularne podejście

Dokładnie tak samo można zrobić w przypadku tworzenia obiektów. Jedyne gdzie wyjątek faktycznie może zostać użyty, to przy "ponownym" sprawdzeniu czegoś w prywatnym konstruktorze, ale oznacza to, że musiałbyś dwa razy sprawdzać to samo i za pierwszym razem źle.

Co innego jeśli masz założenie, że dane wejsciowe będą poprawne (np wczytanie pliku konfiguracyjnego) a ich tam nie będzie. Wtedy to jest sytuacja wyjątkowa


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
edytowany 1x, ostatnio: danek, 2019-08-12 13:07
Pokaż pozostałe 20 komentarzy
Jasne, bardziej chodziło mi o to, że w niektórych językach (np. Scala czy Haskell) masz natywne wsparcie i wtedy kod może wyglądać ładnie - DisQ 2019-08-12 13:51
@danek Jeżek tak sobie wyobrażasz pracę z value object typu Pesel to ok. Ja raczej widzę to jako obiekt który będzie przerzucany po całym systemie w różnych kierunkach i kontekstach. Dlatego też warstwę domenową utrzymywałbym wolną od tego typu rozwiązań. Co do obycia - miałem okazję pracować z kodem gdzie Optionale były wszędzie, głównie dlatego, że taka była domena i jedyną alternatywą był null. Nic przyjemnego. ;) - tdudzik 2019-08-12 13:52
ale tu chodzi o sytuacje kiedy w ogole nie chodzisz do domeny, bo dane wejsciowe są złe. - danek 2019-08-12 13:53
Ale temat jest przecież o warstwie domeny: ...Value objecty to świetny sposób na modelowanie domeny... - tdudzik 2019-08-12 13:55
Jeżeli do obiektu domenowego dołożysz taki parse to nic nie będzie stało na przeszkodzie żeby używać go też w domenie. - tdudzik 2019-08-12 13:56

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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

Robot: CCBot (2x)