Flutter Mobile — Clean architecture (part 2)

AbedElaziz Shehadeh
3 min readFeb 1, 2022

--

In the previous article, I explained the theory of the proposed approach to build Flutter applications with clean architecture. In this article, I will show a sample implementation and the steps taken to perform a task following the proposed architecture.

For this demo, I want to retrieve the most emailed, shared, and viewed articles using NYTimes API, and then save the articles to a local database. Let’s get started.

Note: Add your NYTimes api key while calling the apis in remote/lib/src/api/endpoint_provider.dart if you want to try the demo app yourself.

Before diving in, it is important to highlight that mockito is what I am using for testing and get_it with injectable for dependency injection.

  1. Create a new Flutter project.
  2. Create a new Flutter package and choose the save location to be inside the created Flutter project, call it data.
  3. Create another Flutter package and choose the save location to be inside the created Flutter project, call it domain.
  4. Create another 2 packages following the previous steps, call them, remote and cache.

I beleive the first step is to always define the buisness logic and create tasks accordingly, therefore, we will start with Domain.

Domain

First step is to create the described logic as a use case at Domain layer:

  • Create an interface (abstract class as Dart does not support interfaces) that contains all the functions to be performed such as getting the most emailed articles and saving them to cache, etc. as follows:
  • Create a GetArticlesUseCase and provide the created repository; the use case will first check if the articles are saved at cache, if so, they will be fetched from DB, otherwise, it fetches them from remote and saves the data in cache. The use case accepts:
  1. RequestType to determine if most emailed, shared, or viewed should be fetched.
  2. ForceUpdate which tells if we want to force fetching data from remote.
  3. And the results callback functions that are onSuccess and onFailure which are self-explanatory.
  • Testing this use case is straightforward now, we just need to prepare the mock objects and test the use case as follows;
  • Now we are done with the Domain layer and we can proceed to the Data layer.

Data

In this stage, we will implement the domain repository, choose the data source to fetch the articles.

  • Create a Data source Factory. This class will be called to choose a data source.
  • Create Articles Repository implementations (implementation to the repo which Domain defined) and provide the Data Factory and any necessary mappers that would convert entities to models which Domain can recognize and work with;
  • Create Articles Remote repository that Remote layer would implement, and Cache Storage repository that Cache would.
  • Now we can test the remote data source for example as follows;
  • We are done with Data, we can now perform the articles api retrieval and offline data persistence by implementing the abstract class in both Cache and Remote modules.

Remote

  • We can create an API service anyway we want, using https, websockets, etc. It does not really matter, what matters is the Data repository implementation;
  • Testing this class can be done as follows;
  • We can do something similar in Cache now.

Cache

  • We can create storage services anyway we want. It doesn’t really matter, what matters is the Data repository implementation;
  • Testing this class can be done as follows;
  • Cache is ready now and we can go to the presentation layer to call the use case.

Presentation/lib

In this module, we use BLoC to call the use case and then emit the states to the listening UI.

  • Articles BLoC (or Cubit which is a lighter subset of BLoC) can call the get articles use case and pass ArticlesLoadedState if it is successful to the UI;
  • The UI would listen to that state and do something based on it is status;
  • We are done with fetching the articles flow.

Conclusion

This article demonestrates the steps taken to perform getting the articles. The full source code can be found here:

--

--