Piszę nowy projekt w Kotlinie i zastanawiam się jak zamodelować jego architekturę i obsługę błędów. Po pierwsze, na pewno chciałbym skorzystać z sealed class
do obsługi błędów, zamiast Javowego podejścia z rzucaniem "biznesowych" RuntimeException
.
No i mam powiedzmy dwie klasy które wykonują jakąś akcję, np. zapytanie do innego API, walidacje jakiś parametrów, czy zapis do bazy danych, nie ma to znaczenia, w każdym razie zwracają one jakiś sealed class
który może oznaczać poprawne wykonanie operacji, albo jakiś błąd
sealed class FirstServiceResult {
object Success: FirstServiceResult()
object YNotFound: FirstServiceResult()
}
sealed class SecondServiceResult {
object Success: SecondServiceResult()
object InvalidArgumentX: SecondServiceResult()
}
No i te dwie operacje są składową jednej większej operacji, czyli np. FirstService
wyszukuje coś korzystając z zewnętrznego API, a SecondService
waliduje wynik wyszukiwania. Całość jest jednak wołana z jakiegoś MainService
, który musi zawołać najpierw jeden a potem drugi serwis i zmapować to na swoj rezultat, czyli np.
sealed class MainServiceResult {
object Success: MainServiceResult()
object YNotFound: MainServiceResult()
object InvalidArgumentX: MainServiceResult()
}
Co potem w warstwie wyżej controllera, mogę mapować na odpowiednie kody HTTP, np. 200, 404, 400
Tyle że jak widać na powyższym przykładzie, MainServiceResult
musi duplikować wszystkie wartości z FirstServiceResult
i SecondServiceResult
, gdzie w realnym przykładzie jest dużo więcej wartości które trzeba powielić.
Jest jakiś sprytny sposób jak to rozwiązać? Myślałem by ewentualnie FirstService
i SecondService
, które tak naprawdę obsługują wyjątki rzucone z warstwy infra (DB, API), po prostu propagowały te wyjątki wyżej i wtedy MainService
mapowałby te wyjątki na odpowiedni sealed class
, jednak wydaje mi się to brzydkie z dwóch powodów - po pierwsze, wolałbym te wyjątki obsłużyć jak najniżej się da i nie propagować ich wyżej, a po drugie to troche mieszanie dwóch podejść. Z drugiej jednak strony, sealed class
poniekąd wymusza duplikacje różnych rezultatów w dwóch różnych miejscach. Dlatego pytanie, jak inaczej podejść do rozwiązania tego problemu?