Hi Patryk, thanks for sharing your opinion. One thing I would like to share is that the concepts of the NetworkResult class came from Monad (or Functional Programming - https://en.wikipedia.org/wiki/Functional_programming), and Railway-oriented programming - https://fsharpforfunandprofit.com/rop).
The principle of the Monad might be super complicated for beginners, so I would use simple examples for explaining the basic concept of handling the responses in the Monad way and focus on the Retrofit. Surely you can map or process the NetworkResult to pure data before transmitting it to the presentation layers, as you can see in this demo project - (https://github.com/skydoves/pokedex)
As you mentioned, you can also utilize the `CoroutineExceptionHandler` for handling exceptions with Coroutines simply, but we still need to use the `CoroutineExceptionHandler` for each launch of the coroutine scope or we need to extend "something" in the presentation layer such as `ViewModel` (not a "network" layer) for reducing the code repetition.
So the solutions really depend on how much the project layers are complicated and how the data must be processed/flowed between layers. It might be helpful to look at other solutions like Arrow-kt (https://github.com/arrow-kt/arrow) or RxJava (https://github.com/ReactiveX/RxJava).
I hope my answers might help you understand what I wanted to elaborate on in this article and thank you again for sharing your nice opinion!