Unidirectional flow to tame the state
Unidirectional architectures are here to stay. Web development is full of successful cases based on Flux, Redux, Elm, React among others and some of them have been ported to mobile dev with really nice results. But, are these ported frameworks enough mature to be used into a production environment? Is it worth it?
At Fidesmo we think it is, but there are some considerations about our app that make the decision easier. Our app is a kind of bridge between Fidesmo devices and a whole remote platform to interact with them. So, for our app:
There are many (and well defined) states triggered by the three different inputs: the user, the network and the device. Most of the time we could describe our app behaviour as a finite state machine.
It is developed using Kotlin and Swift and both languages are suitable for a functional programming approach.
It doesn’t have many screens so the whole application state is not too nested.
At the time to select a framework, we opted for ReSwift as the most mature option for iOS and ReKotlin for Android, in order to use almost the same definitions in both platforms. Both (ReSwift and ReKotlin) are implementations of Redux.
Following the Redux patterns our application architecture looks like this:
Besides the standard Redux components (actions, state, reducers) we want to highlight the role of middlewares inside the architecture. They catch actions and according to the state at this moment, perform async operations and generate new actions. For example:
Both Kotlin and Swift have structures to define algebraic data types (like a real funcional language) and therefore to describe complex states as we need. In case of Swift, we can use its fantastic enum implementation and using Kotlin, we can achieve almost the same using sealed classes:
The delivery state of our app described in Swift
and the same state translated to Kotlin
Although Kotlin and Swift are not as similar as we thought at first, implementing the same patterns with them is a little step forward the dream of “write once, run anywhere”.
The current codebase is really enjoyable, besides the advantages of the functional approach and the unidirectional data flow: simplicity, predictability, ridiculous easy testing.
You should give a try for sure! :)