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?