In our recent hackaton we pushed hard with the Immer team to rebuild Idea Growr to add online accounts. We had some challenges regarding ‘Offline First’, but found a new path.
In earlier articles I’ve written about the the conceptual aspects of the app. Now we can get into the actual building of an improved app.
From a technical perspective, the current offline android app (from now on I’ll call Classic) is quite simple. You store texts, images and audio and are able to retrieve and edit them.
The Medium article is more elaborate on app architecture, illustrations of team members, etc. Here I'll focus on the tech side; offline first.
A new way of thinking is starting to emerge in the web and mobile development scene, called Offline First.
We live in a disconnected & battery powered world, but our technology and best practices are a leftover from the always connected & steadily powered past.
Offline capability is a key characteristic of modern Progressive Web Applications. Offline first thinking must learn from and further what we’ve seen work with Responsive and Mobile First thinking.
On closer inspection, they really are talking about what I call Offline Second. A web-app dealing with connectivity dropping, should at first work online.
My definition of Offline First, means you first build it offline. Without internet, without online accounts. Then when the whole app works, build on top of this code to add online capabilities second.
There is an architectural challenge in creating an offline first app; how do you synchronize the data? I’ll describe two different strategies in as much as a non-technical way as possible.
One way to look at is, is to see the online database as the sole truth. You can ask questions (queries) to this database, and when the connection drops, you locally remember what the answers to those queries used to be. You use the cache storage to keep answers to the database around.
We use Apollo for our data management and have to be careful about how to use this cache. When you are offline, the last answer to a question is not always the correct answer.
To deal with this problem, you have to do some coding by hand for each query. You write resolvers that make sure the correct thing happens. The conversation then becomes like this:
After this conversation, the server could come back online and the local storage of answers to the queries would be used to sync the data to the server.
The nasty thing about this approach seems to be that you have to do create resolvers for every query and slowly start to build a local database in the form of resolvers. A local database full of entanglements that is hard to manage.
My biggest hope 🙏 is that I’m ignorant and someone comments that we just need to do X and Y to get a clean manageable architecture.
While the first strategy leans on providing the online server with a list of changes to the local understanding of the database, the second strategy is to use an actual local database.
Of of the advantages is that it simplifies offline behavior. The app just uses a routine way to talk with the local database (SQL queries). Then a general piece of software, I’ll call a syncer, is placed between the local database and the online server. It keeps track of what is out of sync and makes updates if required. It wouldn’t matter what SQL queries you write to make changes to the local database, so now resolvers, the syncer would just look at the state of the database to see what is different.
This kind of solution reminds me a lot like how how version control like Git works for code management. Git is a tool that keps track of your code and make sure you have a copy on your computer that you can use offline, but is also able to sync with the code on a server.
You to start coding locally and then tack on Git aftwerwards. In the same way I’d like to first create an app using the local database, and then tack on a syncer later.
What could we have done better? It seems we may have tried to tackle to much at once. The ideal process keeps the momentum. At every step our team enjoys visible progress and we can keep learning and improving.
In hindsight, I should have aimed for the team to build an Offline Only app. We did a short evaluation, and this is our new roadmap:
- Offline Only (simple Sqlite database) Get the React Native app as soon as possible in the Apple store so we can start learning and improving. This means we start storing the ideas on the device only. While the classic Android app is also Offline Only, we don’t have an iOs app yet, so we can roll it out there first.
- Back-up the full database The current would be greatly helped if they could have a simple back-up feature for all their ideas. Now there is a quite tedious export/import feature. A decent back-up feature would give us the opportunity to learn about our users needs in this area and dealing with the server side, analytics, etc.
- Sync Once we have the core working, we can build smart sync capabilities on top of that. Even before that, we can start experimenting with this right now in our one-text-app POC.
- Teamwork Then we move forward along the path discussed in earlier articles. Starting with teamwork.
We had fun, made good progress, took two step forward and one step back. We calibrated our plans and now focus hard on first taking the app to the Apple Store as soon as possible.
If you have any suggestions for us on the Offline First challenge, please share your wisdom in the comments. I’ll keep this article up to date, incorporating new insights from you and others.