Where to perform state changes with Clean Architecture in Flutter?

Viewed 1546

When using Clean Architecture with flutter we see a diagram similar to this:

enter image description here

(I wrote MobX package as an example, but it could be anything like BLoC, Redux...)

I may have a problem with this diagram since the Store resides in presentation layer and is responsible for changing the state.

Imagine that the app loads a list of todos through a method called "getTodos" implementend in TodosStore. The "getTodos" implementation might be:

 _state = State.loading();
 final result = GetTodos();
 _state = State.done();

(I oversimplified things)

It starts by updating the state to loading, calls a use case returning the list and set state to done.

The problems I found here:

  1. Stores are responsible for calling UC, updating state, handling errors...
  2. Use case is simply a bridge and does not handle the business logic

This is a rather simple example. But let's imagine that I have a view with 3 lists of differents data (it may be an absurd example). The view interacts with 3 differents stores. There's a button in an app bar. Its goal is to clear the 3 lists.

How to achieve that behavior ?

  • The button onPressed method will need to call "clearData" for each store
  • The "clear" method of each store will simply updates its properties

The thing is that the view is not as dumb as we wanted. The store is not even interacting with any use case

Should a ClearLists use case be legitimate here?

Since I do not like having much logic in presentation layer, I tend to follow this diagram:

enter image description here

Each view has its own ViewModel. The VM simply interacts with the Use Case. These UC may or may not return a value. For instance: my UC is a ValidateNumberRange, I might not interact with a store. It makes sense to return a bool. But if my UC is a ClearTodoList, it might interact with a store. The success or failure may be a stored value. That way returning a value may not be useful.

With this new diagram, the "GetTodos" use case callable method implementation might be:

store.set(State.loading());
final result = repo.getTodos();
result.fold(
   (failureMsg) { store.set(State.failure(failureMsg)); },
   (newList) { store.set(State.done(newList)); },
);
  • Use case handles the state management logic
  • The View calls a VM method. The VM calls a UC and observe changes in Store (through MobX here)

I ask myself a ton of questions:

  • Did I correctly understand the role of UC in clean architecture ?
  • Is changing state (to loading, done, failure) considered business logic ?
  • Where would you put state management solution in your app ?

I look forward to hear your thoughts

1 Answers

Use cases encapsulate business rules, and they are platform-agnostic and delivery-mechanism-agnostic (e.g. UI). Use Cases are based on functionality, but without implementation details. Book: https://dannorth.net/introducing-bdd

changing state is responsibility of presentation layer; Presentation Layer != UI Layer

Think as like this:

Domain Layer <= infrastructure layer <= application layer <= presentation layer <= UI Layer

the dependencies always should be inward. imagine like this: Side effects free business logic (functional core) is always in center and the rest (stateful elements, UI, frameworks) surround it.

from your diagram: AppState and ViewModel always reside in presentation layer. Flutter specific classes are belongs to the UI.

Related