Sxndrome
Sxndrome

Reputation: 437

Where to perform state changes with Clean Architecture in Flutter?

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 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)); },
);

I ask myself a ton of questions:

I look forward to hear your thoughts

Upvotes: 8

Views: 3240

Answers (1)

Hashem Aboonajmi
Hashem Aboonajmi

Reputation: 13830

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.

Upvotes: 3

Related Questions