Hi! Any suggestions on dealing with one shot opera...
# android-architecture
a
Hi! Any suggestions on dealing with one shot operations while using clean architecture/repository patterns in a better way?
When dealing with some apps, multiples times I've encountered cases that required the app to notify the backend with an one shot operation, stuff like notifying "user did X", "X has started/finished" or finishing some operations (ex.: user finished a form and submitted it to the server) Most of these, in my experience, were weird to work on since they didn't really fit the CRUD nature of the Repository pattern, since a Repository basically works as a collection of domain models, and it's weird having random methods like "save" in a collection, but in my experience, following clean architecture strictly, the only bridge between the domain model and a remote service is a repo Both solutions that come to mind are either: 1. not worrying about violating the Repository pattern with some of these methods 2. looking at them from a different angle, and creating repositories such as an EventRepository with a .addEvent() method Solution 1 does not look like a great solution to me; and 2 is more of a workaround to fit my problem into a specific pattern, and it also result in multiple classes and boilerplate just to call some endpoints Other solution would be: 3. violate clean architecture a little and create a one shot use cases that calls the API directly I could also (4.) create a new interface in my domain module and implement the API call inside the data module, and then use this new interface inside the use case, or even (5.) declare the use case interface normally and implement it directly on the data module. Do you have suggestions or experiences to share to solve these kind of situations? Is there a pattern I didn't think of that solves this problem?
m
While I don’t have clear answer for this, I would love to see some opinions as well. It’s something I am facing from time to time. The idea that you can only expose repository interfaces from domain is kind of limiting (unless you relax the definition of repository). At the same time I think naming it EventRepository is not that bad, maybe Event is a bit generic so I would probably give it a little bit more context, but at least it makes it clear for someone that reads your code that this your domain boundary. It happened to me also that I have created some other interfaces in domain implemented by data layer like
FeatureStatsReporter
. I would love to hear some voices here ;)
s
There is no rule that says that your use-cases must be some form of a "repository". Your ViewModel can call any type of use case. Eg handling Bluetooth devices, or the use cases you described. Name the classes/interfaces your ViewModel calls appropriately. Don't try to shoehorn them into a "XxxxxxRepository" when it doesn't make sense.
a
@streetsofboston yes, I agree that use cases can represent any relevant domain action without conforming to any pattern. But the use case implementation resides inside the domain module, so it depends on calling services/repositories interfaces declared in the domain module as well; my question is more like how a use case can interact with one shot operations from the data layer without going through repositories? Should they just call classes from the data module directly? Wouldn't that pollute the domain module?
@Marek Kubiczek I've also followed the approach of creating interfaces in the domain and then implement it on the data layer, stuff like
AnalyticsService
and
_Resource_Provider
, but I haven't found a pattern I like to handle stuff like specific HTTP requests yet
m
I usually just create a sealed class representing the possible events i want to collect. Then have interface with method report/add that takes the event as parameter. Then in data layer I implement it with a when statement.
s
Your ViewModel can abstract that out (or if your ViewModel gets too large, a use-case, business-logic). viewModelScope.launch { observerByUi.value.update { uiState -> stateTransition(oldState = uiState, event = someService.doSomeOneShotOperation(...).asSomeEvent()) // <-- doSomeOneShotOperation can be suspend } }
c
Fit the CRUD nature of the Repository pattern
Where did you come across this definition of the Repository pattern? I don't look at a Repository this way. For me a Repository is simply the data layer of my app. That includes this sort of one-shot data operations.
Typical examples refer to Repository as DB/networking and IMO that misses the point. It is anything that gets data for your app. • Want to connect to a BLE device? Repository • Want to know network connectivity status in your app? Repository • Want to react to battery low events? Repository • Observe user location? Repository • Third party SDKs like Analytics? Repository
m
Where did you come across this definition of the Repository pattern?
I think this is how it is described in all the famous books like
Clean Architecture
or
DDD
(the blue book) Where repository is described as a collection like api on your domain entities, so you can abstract how they’re stored/send. At the same time I agree with the examples given by @curioustechizen . All these use cases seem like a valid repositories to me.