Flutter TDD Clean Architecture

Fakhira Devina
3 min readApr 13, 2020

--

Three years studying computer science has taught me not only to put things on the code and be grateful if it works, but also to make sure the code I write today won’t hurt my eyes in the future. Just like in this pandemic time, it’s always necessary to clean your code (and hands!).

There are so much to learn about clean code. You can read it all on uncle Bob’s book, one thing to be highlighted for this article is to separate code into independent layers and depend on abstractions instead of concrete implementations. This article is going to explain the implementation of the flutter clean architecture in my current project bisaGo.

Implementing Reso Coder’s Clean Architecture

As you can see from the picture above, there are 3 layers of the architecture: Data, Domain, and Presentation. Each of them has its’ purpose and only can interact like the flow above; Data and Presentation can only talk to each other with the help of Domain. It’s pretty straight forward but still a bit abstract if we don’t implement it.

I’m going to give an example of implementing Search Location feature. Locations provided by the application are gathered in remote sources (REST API). When user clicked one of the location, the application needs to remember the past clicked location by retrieving the list from cookies.

1. Data

The Data layer consists of repository and data models. Repository is where the application gather all data related to the use case, either from local sources (Local DB, cookies) or remote sources (remote API). Data from the sources, usually in json format, is parsed to Dart object called models. It’s need to be done to make sure the application knows what data and variable it’s expecting.

So I created the LokasiRepository to gather all the data from different resources. Data from API is gathered with the fetchLokasi() function, and Data from cookie is gathered with the fetchRecentSearch() function.

As you can see in line 14–15 and 35–36, all the functions return an object called LokasiListResponse that was made by the json data containing list of locations. Flutter makes it easier by using the Json Serializable package. You just have to create a model class consists of variables based on the data from the source, and then the package will generate a .g.dart file for you.

2. Domain

Domain is the inner layer which shouldn’t be susceptible to the whims of changing data sources or porting our app to Angular Dart. It will contain only the core business logic (use cases) and business objects (entities).

Repository classes act as the Data Layer and Domain Layer, each function on the repository class acts as the domain layer that specifies the use cases of the feature.

3. Presentation

Presentation is where the UI goes. You obviously need widgets to display something on the screen. These widgets is controlled by the state using various state management design pattern used in Flutter. In this project, I use BLoC as the state management.

BLoC allows us to know exactly what data is given to the state. There is BLoC implementation that uses event classes to easily predict what state is the application in, but I use the simpler implementation of BLoC (just using streams) to shorten times for other that hasn’t been familiar to BLoC before. But I won’t dive too deep on BLoC because it’s another thing to write (but if you are curious you can read it here).

Something that I want to point out is about using Stream. Stream allows your application to run asynchronously. Imagine stream as a river and the data is the water, so you can always add more data, or in this case, state, and stream will send the data to your UI using StreamBuilder. You don’t just add data to the stream, but you add the data to the streams’ sink.

References

--

--