The Mobile Architecture

When a short-Circuit comes to the rescue

André Mion
Taager Tech Blog
4 min readJan 10, 2023

--

📋 Overview

In Taager mobile projects, we use many concepts of Clean architecture as a whole, and structure them into basically four layers, whereas only one contains platform-specific code:

Multiplatform layers

  • Data: Where repositories, cache, API, workers, and most of the framework components are placed.
  • Domain: Containing the use cases of our business and the domain entities.
  • Presentation: Where Presenters, View States, View Events, and Side Effects live.

Platform-specific layer

  • UI: Platform-specific layer containing mainly UI and navigation code.

✨ The Clean Architecture

The project components are defined with the overriding rule of that architecture in mind, which enforces that the dependencies must always point inwards in the layers.

The outer layers can only depend on the inner layers. Therefore, the inner layers know nothing about the outer layers. The further you go towards the concentric circles, the higher the level of abstraction.

Applying this rule makes our software more robust, scalable, and testable.

The mobile architecture tiers

🔁 Dependency Inversion

A few cases occur when a high-level component depends on a low-level component. In such situations, how do we avoid breaking the Dependency rule?

☑️️ Dependency Inversion principle to the rescue

Instead of expecting and directly referencing a low-level component — e.g. a use case depends on a repository —, the high-level component references an interface that must be implemented by the low-level one. This way, the conventional dependency relationship is inverted and the high-level layer is decoupled from the low-level one.

♻️ Circuit

Building components that act between the UI and the domain layer is tricky because we might end up with so many data entry points that make it harder to maintain and prevent bugs.

Choosing the right architecture that reduces those entry points by giving the components clear responsibilities to act on data is the key to a healthier project.

So we decided to apply a Unidirectional Data Flow approach to solve this problem and named it Circuit.

🤔 Tell me more about that…

The Presenter (former ViewModel) may hold a View State, react to the View Events, and emit Side Effects.

Presentation data flow

View State

  • Represents the UI to be rendered.
  • Must be immutable.
  • Presenters are responsible for holding and emitting new values.
  • The latest value must be emitted whenever the UI subscribes to it.
  • Only distinct values must be emitted.

View Event

  • It usually represents any user interaction event, e.g. Click actions, Input text changes, etc. It can also represent the initialization of the presentation component, namely, Init events.
  • Presenters react to the View Events by mapping domain entities to view models, executing use cases, applying presentation logic, updating view states, and/or emitting side effects.

Side Effects

  • Presenters may emit side-effects as a result of View Events, whereas they might represent navigation (namely GoTo events), or any non-sticky dialog, Snackbar, and Toast (namely Show events).
  • UI that subscribes to it must only receive new values.
  • The same value must be emitted as many times as needed.
Presenter behaviors

🤩 Conclusion

Using Clean Architecture + Circuit has helped us to create a scalable, maintainable, and more readable codebase, by having components that are more cohesive, less coupled, more shareable, and have clearer responsibilities.

You can find more about how we do Kotlin Multiplatform in Taager below:

--

--

André Mion
Taager Tech Blog

🇧🇷 Android Engineer living in 🇵🇹 • Full time Husband and Dad • Occasionally Drummer and Inline Skater… I write mostly about Android and Tech…