This is my solution to the Fetch take-home exercise.
Here are a few thoughts:
I based this on a (very) simplified version of an architecture I use when building applications. Whereas I would normally make use of things like Dependency Injection (via Hilt), Single Source of Truth (via Retrofit -> Room for local storage), Functional Programming (via Arrow.kt) and several other libraries, much of that has been stripped out here. Hopefully this is acceptable for the purposes of this exercise.
Instead of Dependency Injection I have just created a singleton that instantiates Retrofit, Webservice, and so on. This is an approach I wouldn't likely use in a production app.
I usually use Arrow.kt's Either and Ior classes for monadic manipulation of RESTful data, here I am just using Kotlin's Result class instead.
Although the endpoint supplied is a direct link to a JSON file, I'm treating it as if it were a RESTful call to get data.
I use a form of MVI in which views (in this case, Jetpack Compose screens) have no direct reference to a ViewModel. Conversely, ViewModels cannot directly manipulate variables/controls in a view. Instead, the view communicates to the ViewModel indirectly though a series of Events, and the ViewModel manipulates data in a state data object which is then consumed by the view. Certainly overkill for this example but shows the approach I'd take in a larger application.
I am a proponent of separating data from domain and presentation. This is why (again, a bit overkill for this example) I have a FetchRepository and a FetchRepositoryImpl class, as well as (for example) a "RemoteItem" class as well as a (domain) "Item" class. I keep these separate so no part of the domain relies on (for example) any Retrofit classes or annotations, which would allow a completely different RESTful library to be swapped in with minimal pain points.
As for testing: There was not a lot of business logic in this example so I kept the testing as simple as possible, writing a few simple tests for my "Mapper" class. Obviously this would be inadequate for an enterprise application but hopefully the few tests that I included are enough to get a sense of my approach to testing.
As for the Compose methods -- The first pass of writing Compose views always tends to be pretty messy. Knowing that I tried to clean things up a little bit but I am aware that there is a lot of room for consolidation here!
Coverage of error messages and loading indicators exists but is pretty light. A connectivity error will display a snackbar but doesn't make the message "pretty" in any way.
I remain available for any further discussion/questions!
Best,
Scott Slater
codepunkllc@gmail.com