Który wyjątek powinien mieć pierwszeństwo?

0

Piszę sobie bibliotekę T-Regx i mam funkcję, która pozwala wyciągnąć n ilość znalezionych grup g.
Jak wywołam metodę group('x'), gdy grupy x nie ma to leci NonexistentGroupException.
Jak wywołam metodę only(-2), to leci \InvalidArgumentException, bo ujemny limit.

Który wyjątek powinien polecieć gdy wywoła się

group('missing')->only(-2);

Ktoś mógłby powiedzieć że wyjątek z group(), bo jest wywołana wcześniej (ale dopiero przy only() leci zawołanie do preg_*)
Ktoś inny powiedziałby że ujemny limit to poważniejszy bug, i on powinien lecieć.

Jak myślicie?

1

Moim zdaniem z group() zgodnie z zasadą fail fast.

0
lookacode1 napisał(a):

Moim zdaniem z group() zgodnie z zasadą fail fast.

Tylko że group() to taki builder. Wszystkie operacje dzieją się w ostatniej metodzie - only(). "Fail fast" Twoim zdaniem tutaj ciągle się aplikuje?

0

Moim zdaniem tak. Chociaż tutaj można poczytać, że obie metody są ok.

2

Mam dwa pomysły. Albo wyjątek z grupowania (bo siłą rzeczy musisz najpierw wybrać grupę,a potem wybrać ilość) albo oba w zbiorczym wyjątku jako opis błędu całego wyrażenia. To właściwie powinno się dziać na etapie kompilacji, ale jak rozumiem to PHP, więc nie ma o tym mówy.

0
lookacode1 napisał(a):

Moim zdaniem z group() zgodnie z zasadą fail fast.

też podzielam te zdanie. Skoro jesteś w stanie już na samym początku rzucić wyjątkiem bo JUŻ wiesz, że jest coś nie tak, to tak zrób.
Wyobraź sobie, że ktoś robi takie cuś:

$group = $builder->group("lala");
// some code
$group->only(-2);
0
no_solution_found napisał(a):
lookacode1 napisał(a):

Moim zdaniem z group() zgodnie z zasadą fail fast.

też podzielam te zdanie. Skoro jesteś w stanie już na samym początku rzucić wyjątkiem bo JUŻ wiesz, że jest coś nie tak, to tak zrób.
Wyobraź sobie, że ktoś robi takie cuś:

$group = $builder->group("lala");
// some code
$group->only(-2);

Noo, nie do końca

$group = $builder->group("zła grupa");  // niepoprawna grupa, ale nie można tego jeszcze ustalić
// some code                            // nie ma wyjątku
$group->only(-2); // tutaj się dzieje cała logika, i tutaj wiadomo że grupa jest zła i że index jest zły. 
                  // Mogę wybrać który wyjątek poleci
6

A naprawdę nie możesz rzucać wyjątkiem, który zawiera całą listę błędów?
Bo jeśli jest zgłąszany tylko pierwszy z błędów mimo że można by zgłosić wszystkie to często wygląda to tak:

- Hasło ma ponad 30 dni. Wprowadź nowe hasło.
- (róża)
- Hasło za krótkie.
- (różowa róża)
- Hasło musi zawierać minimum 1 cyfrę.
- (1 różowa róża)
- Hasło nie może zawierać spacji.
- (1różowaróża)
- Hasło musi zawierać co najmniej 10 różnych znaków.
- 1pieprzonaróżowaróża
- Hasło musi zawierać co najmniej jedną WIELKĄ literę.
- 1PIEPRZONAróżowaróża
- Hasło nie może zawierać kolejno następujących po sobie wielkich liter.
- 1Pieprzonaróżowaróża
- Hasło powinno mieć ponad 20 znaków długości.

WsadzęCiwTyłek1PieprzonąRóżowąRóżęJeśliMiNatychmiastNieDaszDostępu!
- Hasło uprzednio używane.
0
Kamil Żabiński napisał(a):

A naprawdę nie możesz rzucać wyjątkiem, który zawiera całą listę błędów?
Bo jeśli jest zgłąszany tylko pierwszy z błędów mimo że można by zgłosić wszystkie to często wygląda to tak: ...

Tylko że to nie jest formularz interfejsu użytkownika, tylko biblioteka z interfejsem programistycznym.

Np powinno się móc zrobić tak:

try {
    return group('missing')->only(-2);
} 
catch (NonexistentGroupException $e) {
  // obsłuż grupę
} 
catch (InvalidArgumentException $e) {
 // obsłuż index
}

więc raczej starałbym się unikać takich grupujących wyjątków. Miałbym potem pisać catch (NonexistendAndInvalid), catch (MalformedPatternAndNonesitentAndInvalid)? Ewentualnie catch (GrouppingException) i potem jakoś ifami rozpracować co się stało?

0

Możesz zwrócić cały stos wyjątków i jak użytkownik będzie chciał, to może je sobie rozwijać i coś tam z tym robić. exception->getRootCause()->getRootCause()->...
Nie wiem jednak czy w swojej bibliotece będziesz w stanie określić co jest "root cause" wyjątku.

0
yarel napisał(a):

Możesz zwrócić cały stos wyjątków i jak użytkownik będzie chciał, to może je sobie rozwijać i coś tam z tym robić. exception->getRootCause()->getRootCause()->...
Nie wiem jednak czy w swojej bibliotece będziesz w stanie określić co jest "root cause" wyjątku.

Np tak?

try {
    return group('missing')->only(-2);
} 
catch (Exception $e) {
    if ($e->getRootCause() instanceof NonexistentGroupException) {
        // obsłuż grupę 
    } 
    else if ($e->getRootCause() instanceof InvalidArgumentException) {
        // obsłuż index
    } 
} 

Moim zdaniem trochę średni pomysł. I potem wyobrażasz sobie testowanie tego w phpunit?

Nie, raczej chce rzucić jeden wyjątek, i po prostu chciałem spytać który powinien polecieć w tej sytuacji?

0
yarel napisał(a):

Możesz zwrócić cały stos wyjątków i jak użytkownik będzie chciał, to może je sobie rozwijać i coś tam z tym robić. exception->getRootCause()->getRootCause()->...
Nie wiem jednak czy w swojej bibliotece będziesz w stanie określić co jest "root cause" wyjątku.

Np tak?

try {
    return group('missing')->only(-2);
} 
catch (Exception $e) {
    if ($e->getRootCause() instanceof NonexistentGroupException) {
        // obsłuż grupę 
    } 
    else if ($e->getRootCause() instanceof InvalidArgumentException) {
        // obsłuż index
    } 
} 

Moim zdaniem trochę średni pomysł. I potem wyobrażasz sobie testowanie tego w phpunit?

Nie, raczej chce rzucić jeden wyjątek, i po prostu chciałem spytać który powinien polecieć w tej sytuacji?

2
TomRiddle napisał(a):
yarel napisał(a):

Możesz zwrócić cały stos wyjątków i jak użytkownik będzie chciał, to może je sobie rozwijać i coś tam z tym robić. exception->getRootCause()->getRootCause()->...
Nie wiem jednak czy w swojej bibliotece będziesz w stanie określić co jest "root cause" wyjątku.

Np tak?

try {
    return group('missing')->only(-2);
} 
catch (Exception $e) {
    if ($e->getRootCause() instanceof NonexistentGroupException) {
        // obsłuż grupę 
    } 
    else if ($e->getRootCause() instanceof InvalidArgumentException) {
        // obsłuż index
    } 
} 

Chodziło mi o to, żeby dostarczyć developerowi informację o łańcuszku problemów, które się pojawiły. Możesz mieć jeden wyjątek z różnymi komunikatami albo rozmnożyć te wyjątki.

Skoro masz dwa wyjątki do wyboru: A i B, to masz możliwości:

  • A jest przyczyną B
  • B jest przyczyną A
  • A nie jest powiązane z B

Niezależnie, który wyjątek rzucisz, to skąd developer ma wiedzieć jak zareagować na błąd bez wiedzy o relacji między A i B ?

Offtopic (w stosunku do pytania: który wyjątek rzucać). Jaki problem developera chcesz rozwiązać? Jak developer nie ma kontroli nad argumentami przekazywanymi do Twojego API, to jak ma niby reagować na wyjątek? Coś innego niż logowanie komunikatu błędu?

Jeśli chodzi o dostarczenie informacji dlaczego dany kawałek kodu się wywalił w trakcie developmentu, to lista komunikatów o naruszenie reguł API w zupełności by mi wystarczyła (posortowane po przyczynach, tak bym był w stanie zorientować się od czego zacząć sprawdzenie kodu).

Na "produkcji" raczej chciałbym mieć możliwość podmieniania komunikatów błędów z wyjątku na bardziej biznesowe i możliwość tłumaczenia komunikatu na różne języki, czyli jakiś domyślny tekst błędu + klucz po którym mógłbym wybierać biznesowy opis błędu, np. Exception=(msg="Invalid argument",rc="RC01") (RC01 - result code 01, używane jako klucz do tłumaczenia na biznesowe/międzynarodowe na jakiejś innej warstwie - Francuzi często chcą mieć logi po swojemu :-) ).

Nie zależałoby mi na możliwości uskuteczniania Exception Driven Developmentu i rozbudowanej hierarchii wyjątków.

Moim zdaniem trochę średni pomysł. I potem wyobrażasz sobie testowanie tego w phpunit?

Nie znam phpunita, więc się nie będę wypowiadał.

Nie, raczej chce rzucić jeden wyjątek, i po prostu chciałem spytać który powinien polecieć w tej sytuacji?

Dostałeś propozycje różnych opcji, ale mam wrażenie, że:

  • pytasz o opinie, żeby zrobić api "dev friendly".
  • odrzucasz propozycje i robisz po swojemu. Twoja biblioteka, więc Twój wybór, tylko czy wówczas jest "dev friendly" ? :)
0
[yarel napisał(a)]

Chodziło mi o to, żeby dostarczyć developerowi informację o łańcuszku problemów, które się pojawiły. Możesz mieć jeden wyjątek z różnymi komunikatami albo rozmnożyć te wyjątki.

Tylko że mój przypadek to nie jest łańcuszek problemów, prędzej szereg :) Nie są swoimi przyczynami.

Skoro masz dwa wyjątki do wyboru: A i B, to masz możliwości:

  • A jest przyczyną B
  • B jest przyczyną A
  • A nie jest powiązane z B

Zapomniałeś o "A i B wynikają ze wspólnej przyczyny C" ;)

Niezależnie, który wyjątek rzucisz, to skąd developer ma wiedzieć jak zareagować na błąd bez wiedzy o relacji między A i B ?

One są od siebie niezależne. Najpierw programista musi się uporać z jednym, potem z drugim. Pytanie z tematu dotyczy, właśnie tego z którym z nich jako pierwszym.

Offtopic (w stosunku do pytania: który wyjątek rzucać). Jaki problem developera chcesz rozwiązać? Jak developer nie ma kontroli nad argumentami przekazywanymi do Twojego API, to jak ma niby reagować na wyjątek? Coś innego niż logowanie komunikatu błędu?

Jeśli nie ma (w co wątpię, bo to developer korzysta z API), to faktycznie NIC. Jeśli natomiast ma (co będzie 99.99999% użyć), to obsłuży sobie to jak będzie chciał, i jestem niemal pewien że rzucenie odizolowanych od siebie wyjątku będzie lepszym pomysłem, ponieważ wystąpienie ich na raz będzie raczej rzadkie. Dużo częstsze będzie wystąpienie tylko jednego z nich.

Jeśli chodzi o dostarczenie informacji dlaczego dany kawałek kodu się wywalił w trakcie developmentu, to lista komunikatów o naruszenie reguł API w zupełności by mi wystarczyła (posortowane po przyczynach, tak bym był w stanie zorientować się od czego zacząć sprawdzenie kodu).

Jak już mówiłem, 99.99999% przypadków to będzie lista wielkości 1.

Na "produkcji" raczej chciałbym mieć możliwość podmieniania komunikatów błędów z wyjątku na bardziej biznesowe i możliwość tłumaczenia komunikatu na różne języki, czyli jakiś domyślny tekst błędu + klucz po którym mógłbym wybierać biznesowy opis błędu, np. Exception=(msg="Invalid argument",rc="RC01") (RC01 - result code 01, używane jako klucz do tłumaczenia na biznesowe/międzynarodowe na jakiejś innej warstwie - Francuzi często chcą mieć logi po swojemu :-) ).

Biblioteka nie dotyczy w żaden sposób warstwy prezentacji, więc odpowiedź nie na temat.

Moim zdaniem trochę średni pomysł. I potem wyobrażasz sobie testowanie tego w phpunit?

Nie znam phpunita, więc się nie będę wypowiadał.

Ok, wyobrażasz sobie testowanie takiej "listy wyjątków" w jakimkolwiek narzędziu do testowania?

Dostałeś propozycje różnych opcji, ale mam wrażenie, że:

  • pytasz o opinie, żeby zrobić api "dev friendly".

No jasne, cytując klasyka, "programy powinny być pisane dla ludzi do czytania, i okazyjnie dla komputerów do uruchomienia".

  • odrzucasz propozycje i robisz po swojemu. Twoja biblioteka, więc Twój wybór, tylko czy wówczas jest "dev friendly" ? :)

Propozycje które są nie na temat, albo nie spełniają pewnych kryteriów, siłą rzeczy muszą być odrzucone.

1
TomRiddle napisał(a):
[yarel napisał(a)]

Chodziło mi o to, żeby dostarczyć developerowi informację o łańcuszku problemów, które się pojawiły. Możesz mieć jeden wyjątek z różnymi komunikatami albo rozmnożyć te wyjątki.

Tylko że mój przypadek to nie jest łańcuszek problemów, prędzej szereg :) Nie są swoimi przyczynami.

Skoro masz dwa wyjątki do wyboru: A i B, to masz możliwości:

  • A jest przyczyną B
  • B jest przyczyną A
  • A nie jest powiązane z B

Zapomniałeś o "A i B wynikają ze wspólnej przyczyny C" ;)

Wówczas masz do wyboru nie 2 wyjątki, a 3, więc tak średnio zapomniałem, ale nie nie wiem czy jest sens drążyć ilość tych wyjątków i rozważać grafy wyjątków. KIS ;-)

Niezależnie, który wyjątek rzucisz, to skąd developer ma wiedzieć jak zareagować na błąd bez wiedzy o relacji między A i B ?

One są od siebie niezależne. Najpierw programista musi się uporać z jednym, potem z drugim. Pytanie z tematu dotyczy, właśnie tego z którym z nich jako pierwszym.

Przecież to będzie Exception Driven Development, które postrzegane jest jako anty wzorzec. Co innego, gdy dostarczasz szczegółowej informacji co poszło nie tak i dlaczego, a co innego gdy wymuszasz na użytkownikach obsługiwanie najpierw czegoś, a później czegoś innego.

Offtopic (w stosunku do pytania: który wyjątek rzucać). Jaki problem developera chcesz rozwiązać? Jak developer nie ma kontroli nad argumentami przekazywanymi do Twojego API, to jak ma niby reagować na wyjątek? Coś innego niż logowanie komunikatu błędu?

Jeśli nie ma (w co wątpię, bo to developer korzysta z API), to faktycznie NIC. Jeśli natomiast ma (co będzie 99.99999% użyć), to obsłuży sobie to jak będzie chciał, i jestem niemal pewien że rzucenie odizolowanych od siebie wyjątku będzie lepszym pomysłem, ponieważ wystąpienie ich na raz będzie raczej rzadkie. Dużo częstsze będzie wystąpienie tylko jednego z nich.

Jeśli chodzi o dostarczenie informacji dlaczego dany kawałek kodu się wywalił w trakcie developmentu, to lista komunikatów o naruszenie reguł API w zupełności by mi wystarczyła (posortowane po przyczynach, tak bym był w stanie zorientować się od czego zacząć sprawdzenie kodu).

Jak już mówiłem, 99.99999% przypadków to będzie lista wielkości 1.

Wydaje mi się, że to estymata z... palca. Skąd wiesz ilu developerów i w jaki sposób będzie korzystać z biblioteki, żeby wyciągać wnioski, że będzie to praktycznie niezauważalny przypadek?

Jeśli jednak tak będzie, to moim zdaniem nie warto dla 0,00001% przypadków komplikować rozwiązania. KISS & fail fast.

Na "produkcji" raczej chciałbym mieć możliwość podmieniania komunikatów błędów z wyjątku na bardziej biznesowe i możliwość tłumaczenia komunikatu na różne języki, czyli jakiś domyślny tekst błędu + klucz po którym mógłbym wybierać biznesowy opis błędu, np. Exception=(msg="Invalid argument",rc="RC01") (RC01 - result code 01, używane jako klucz do tłumaczenia na biznesowe/międzynarodowe na jakiejś innej warstwie - Francuzi często chcą mieć logi po swojemu :-) ).

Biblioteka nie dotyczy w żaden sposób warstwy prezentacji, więc odpowiedź nie na temat.

Czyli zakładasz, że wiesz lepiej od końcowego użytkownika do czego będzie używał biblioteki, a do czego nie?

Moim zdaniem trochę średni pomysł. I potem wyobrażasz sobie testowanie tego w phpunit?

Nie znam phpunita, więc się nie będę wypowiadał.

Ok, wyobrażasz sobie testowanie takiej "listy wyjątków" w jakimkolwiek narzędziu do testowania?

Tak samo jak jakiejkolwiek innej zwracanej "listy". Skoro kontroluję stan wejściowy i oczekuję konkretnego zachowania, to na wejściu spodziewam się konkretnego wyniku ("konkretnej listy"). Jak to będzie wyglądać w z perspektywy użycia jakiegoś frameworka testowego? To zależy od tego co framework udostępnia. Jak pisałem, nie znam phpunita i nie wiem czy jest to w PHP do zrobienia, być może nie, nie wiem.

W Javie można tak (https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html) :

FooException fooExcption = assertThrows( FooException.class, () -> someObject.doSomeMagic(), "doSomeMagic should throw, but it didn't"); 
// fooException daje Ci możliwość zbadania fooException.getRootCause() i jakichś dodatkowych asercji 

Dostałeś propozycje różnych opcji, ale mam wrażenie, że:

  • pytasz o opinie, żeby zrobić api "dev friendly".

No jasne, cytując klasyka, "programy powinny być pisane dla ludzi do czytania, i okazyjnie dla komputerów do uruchomienia".

  • odrzucasz propozycje i robisz po swojemu. Twoja biblioteka, więc Twój wybór, tylko czy wówczas jest "dev friendly" ? :)

Propozycje które są nie na temat, albo nie spełniają pewnych kryteriów, siłą rzeczy muszą być odrzucone.

Moim celem nie jest przekonanie Cię do czegokolwiek, tylko pokazanie innych możliwości. To Ty lepiej znasz kontekst względem, którego oceniasz co lepiej pasuje do Twojego pomysłu i tyle. Rzucaj co uważasz za słuszne ;-)

0

@yarel Dobrze, już pomijając wcześniejsze rozmowy.

Proszę, podaj swoją propozycję co się powinno dziać (np. jaki konkretnie wyjątek powinien polecieć?) w takich przypadkach:

  • group('valid')->only(-1) - co gdy limit jest niepoprawny?
  • group('inavlid')->only(10) - co gdy grupa jest niepoprawna?
  • group('invalid')->only(-1) - co gdy grupa oraz limit jest niepoprawny?
1
TomRiddle napisał(a):

@yarel Dobrze, już pomijając wcześniejsze rozmowy.

Proszę, podaj swoją propozycję co się powinno dziać (np. jaki konkretnie wyjątek powinien polecieć?) w takich przypadkach:

  • group('valid')->only(-1) - co gdy limit jest niepoprawny?
  • group('inavlid')->only(10) - co gdy grupa jest niepoprawna?
  • group('invalid')->only(-1) - co gdy grupa oraz limit jest niepoprawny?

Masz w głowie jakąś wizję/kryteria i pytasz co będzie lepsze jabłko czy powidła? Ja nie znam tej wizji, czy kryteriów lepszości rozwiązania.
Dla mnie podstawowym sprawą jest cel rzucania takich wyjątków. Co moją usprawnić/ułatwić? Innymi słowy, jak wygląda przypadek użycia?
Żeglując bez określonego celu, to każdy kierunek jest tak samo dobry/zły.

Chcesz wymusić Exception Driven Development, to mnożysz wyjątki:

  • IncorrectLimitException
  • IncorrectGroupException
  • IncorrectGroupAndLimitException

Chcesz poinformować co poszło nie tak:

  • FoobarException("Incorrect limit"),
  • FoobarException("Incorrect group")
  • FoobarException("Incorrect group and limit")

Chcesz poinformować, ale jednocześnie dać możliwość uniknięcia parsowania tekstów:

  • FoobarException("Incorrect limit",SomeEnum.INCORRECT_LIMIT)
  • FoobarException("Incorrect group",SomeEnum.INCORRECT_GROUP)
  • FoobarException("Incorrect group and limit",SomeEnum.INCORRECT_GROUP_LIMIT)

Do tego wariacje z chainowaniem:

  • SpecificException("message",RootCauseException("blah"))
  • FoobarException("message",FoobarException("blah"))

group($some_input_from_user)->only($some_other_input) - i jaką tu strategię przyjąć naprawy wyjątku/ów ? ;-)

Masz sporo propozycji w tym wątku, to coś sobie wybierz, albo wszystko odrzuć i pochwal obranym rozwiązaniem.

0
[yarel napisał(a)]

Masz w głowie jakąś wizję/kryteria i pytasz co będzie lepsze jabłko czy powidła? Ja nie znam tej wizji, czy kryteriów lepszości rozwiązania.
Dla mnie podstawowym sprawą jest cel rzucania takich wyjątków. Co moją usprawnić/ułatwić? Innymi słowy, jak wygląda przypadek użycia?
Żeglując bez określonego celu, to każdy kierunek jest tak samo dobry/zły.

Mam kierunek - rzucić wyjątek, kończąc funkcję bez zwracania wyniku, rzucając wyjątek - innymi słowy, zapobiec używania tej funkcji ze złą grupą i złym limitem.

Chcesz wymusić Exception Driven Development, to mnożysz wyjątki:

  • IncorrectLimitException
  • IncorrectGroupException
  • IncorrectGroupAndLimitException

Wyjątek IncorrectGroupAndLimitException to głupi pomysł. Gdybym miał 4 przypadki to miałbym tworzyć 12 kombinacji różnych możliwości wątków? I 12 bloczków catch? Raczej nie.

Chcesz poinformować co poszło nie tak:

  • FoobarException("Incorrect limit"),
  • FoobarException("Incorrect group")
  • FoobarException("Incorrect group and limit")

Nie. Nie ma możliwości osobnej obsłużenia wyjątków, chyba że chcesz pasować messgae, co też odpada.

Chcesz poinformować, ale jednocześnie dać możliwość uniknięcia parsowania tekstów:

  • FoobarException("Incorrect limit",SomeEnum.INCORRECT_LIMIT)
  • FoobarException("Incorrect group",SomeEnum.INCORRECT_GROUP)
  • FoobarException("Incorrect group and limit",SomeEnum.INCORRECT_GROUP_LIMIT)

Ten sam problem co wyżej, tylko teraz trzeba sprawdzać error code'y. Odpada - mógłbym niechcący złapać wyjątek który nie powinien być złapany.

Do tego wariacje z chainowaniem:

  • SpecificException("message",RootCauseException("blah"))
  • FoobarException("message",FoobarException("blah"))

Lepiej, ale pojawia się pytanie z myślą o którym założyłem ten wątek - który z nich powinien polecieć gdy i grupa i limit jest zły?

group($some_input_from_user)->only($some_other_input) - i jaką tu strategię przyjąć naprawy wyjątku/ów ? ;-)

Właśnie o to pytam w tym temacie.

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