In the chapter "Business Rules" of his book "Clean Architecture", Robert C. Martin comments on the relationship between use cases and the UI:
[...] the use case does not describe the user interface other than to informally specify the data coming in from that interface, and the data going back out through that interface. [...] Use cases do not describe how the system appears to the user. Instead, they describe the application-specific rules that govern the interaction between the users and the Entities.
Context
For some context, I'm writing a simple client app (Android) using Clean Architecture + MVP in the presentation layer. Though MVP combines the controller and presenter, I'm still trying to think of them as independent aspects of the "interface adapters" layer in Clean Architecture.
In my app, users can create new events or edit existing events via a simple form UI. Each event has a start date, an end date, and a description. In my "domain" conventions (what I understand to be the convention convenient for doing useful operations uninfluenced by any one framework), an event is a simple Kotlin data class:
data class Event(
val startDate: LocalDate,
val endDate: LocalDate,
val description: String
)
My form has simple behavior:
- Show a loading spinner while an existing event is loaded from a remote data source.
- If the selected start date is after the selected end date, then the end date is moved to be equal to the new start date. For example, if the end date was set to 2020-06-01, then I set the start date to 2020-06-02, the end date would now also be/show 2020-06-02.
- Show a loading spinner while the event is being saved to a remote data source.
My understanding is that Clean Architecture describes the "business rules"/"use cases"/"domain" of an application to be application-specific behaviour implemented using conventions that will not be influenced by frameworks chosen to implement details such as UI. In my case, that means working with events treating dates as LocalDate
s, even though my UI inputs dates as year, month, and day Int
s and ouputs them as String
s.
On one hand, handling the loading state and relationship between date inputs seems like a presentation concern because my use cases shouldn't know anything about the UI. However, leaving the controller and presenter to be interface adapters which simply translate from a framekwork-like conventions to domain-like conventions and vice versa, and leaving them unaware of each other, the domain seems like the only place left to implement these behaviors. That leaves me with a use case output port something like this:
interface EditEventOutput {
fun showLoading()
fun hideLoading()
fun renderEndDate(date: LocalDate)
}
My Question
That looks like a presenter's view interface to me, but my presenter is unaware of this behavior. I tried using more generic terms, like an isLoading
Boolean
instead of the terms "show" and "hide", but that's not solving my issue.
The interface I've ended up with looks like a UI! It doesn't discuss details about the UI, like what "show loading" means (i.e. it could be a line of text in a terminal, or a fancy UI widget), but it still implies the existence of UI.
So, even though use cases do not describe how the system appears to the user, do they imply the existence of some user interface? If they should not, and we should be capable of implementing the output ports on any sort of interface adapter (maybe it doesn't even output to a UI), then where do I implement behaviors such as handling a loading state and the relationship between my start and end date pickers?