Hi.
Enough of last week’s management talk. Back to making, back to code. Well, talking about code. I’ll tell you about a design decision we made while developing a mobile application at Rakuten, the underlying rationale and the unexpected side effects.
In a recent mobile application we use the Redux pattern. We considered other popular patterns including MVP, MVVM, Viper, RIBs, VIP and Mobius. These patterns dictate how to organize the application’s responsibilities into object archetypes. For example the MVP organizes the application into model, view and presenter. The goal is separation of concerns, in particular separating framework specific code (UI, networking, persistence) from business logic. At least that’s how I read them, because they only concern themselves organizing UI behavior. Most of these patterns don’t offer any advice on how to manage state. Not UI state (e.g. checkbox selected), business logic state (e.g. user logged in, user name, user ID). In those patterns managing state is the model’s duty. That and all other business logic. It’s up to the implementing team to manage state in a predictable & consistent manner.
Redux, on the other hand, only does one thing: manage application state. Redux imposes no structure on the application other than how to read & change the application’s state. Without a premeditated approach to state management Android and iOS applications often maintain state in instance variables. Sometimes in Activities / ViewControllers, that was common in the dark ages. Other times those variable live removed from the framework code: in presenters, interactors or view models. On rare occasions we find state in the model layer, the part of the application that is concerned with business logic.
Now what is the problem with storing state in instance variables?
It obfuscates the source of state change.
Example: A view controller with 7 UI callbacks, all of which potentially modify an instance variable. You see a crash in production, you trace it to an unexpected value in that variable. What caused that crash?
That’s hard to troubleshoot, especially if you cannot reproduce the issue on your device. You don’t know which of the 7 UI callbacks caused the error, moreover you don’t know how they interact.
Angular 1 developers will remember similar bugs. Hard to understand, caused by implicit bi-directional data binding. If anybody can mess with your application’s state it’s hard to pin down who’s broke your app.
At some point, you no longer understand what happens in your app as you have lost control over the when, why, and how of its state. When a system is opaque and non-deterministic, it's hard to reproduce bugs or add new features.
— Redux Motivation
We chose Redux because of one clear advantage over the other patterns: single-source-of-truth, read-only state with predictable state transitions. (To be fair Mobius does that too). We use libraries (ReKotlin and ReSwift) to facilitate this pattern, which had some surprising advantages:
Just because we have pattern to manage state doesn’t mean the whole team sticks to it. Using a small, single-purpose library makes it easy to spot when somebody is trying to cheat. If new code doesn’t use the library objects it’s not following the pattern.
Using an external library also increased the cost of hacking it. I have seen teams adopt MVP and Redux in their mobile app, with internal library code. In other words, they wrote some general purpose library code in their own project. That’s easy and flexible, so flexible that in both cases the teams found a way to break the pattern. In one case the team re-purposed the redux store as an engine to run asynchronous code, similar to many people abused RxJava for the sole purpose of threading. By using external libraries we effectively prevented our team form breaking the pattern by hacking the libraries.
Redux forces you to write explicit state models, state transition functions and actions. Admittedly that is boilerplate and nobody likes boilerplate. But that is a great forcing function, forcing every developer to think about the application’s state. What is part of the state? What is not? Moreover it encourages a minimal state model, because a smaller state model means less boilerplate. That prevents the code smell of defining multiple representations of the same state. For example when you see booleans for isValid, canSubmit and isReady and only after reading all of the code you realize they all mean the same thing 🤦♀️. A developer (or 3 different developers) introduced variables because it was easy but never bothered to refactor their code. An explicit state model surfaces that design problem by making it more painful.
All of the above factors introduce friction into the development process. Friction gets a bad rep, it is often seen as a thing that slows us down. However in this case friction nudges developers to do the right thing™️. Friction is not always bad.
Hyperlinks
How can we get from a monolith to micro-services quickly?
Can’t answer that question. First, “quickly” is right out the window. You didn’t make this mess in a month; you’re not going to fix it in a month. Second, you want some benefit you aren’t currently getting that you expect from micro-services. What is that benefit? Micro-services aren’t the point.
Preach. Kent Beck tears into hype-driven re-architecting of software systems. In just under 700 words.
Some Thoughts on the Principal Role
Often, teams don’t need help because they lack expertise or experience, but because the problem they are facing may be bigger than the scope they know. For example, when designing a piece of infrastructure that affects many teams, you need to have a good overview of the technical landscape. But teams naturally are most familiar with their team’s scope. A principal can bring this oversight and help the teams to master the challenge.
☝️ This is the situation I find myself in most of the time. This year my self perception changed from “my superpower is deep technical knowledge” to “my superpower is facilitating communication between teams and extracting knowledge”.
Later = Never
Career Progression
That’s it. If you enjoyed this ☝️ subscribe or share it with a friend.