In an online world with synchronous operations, everything is easy. In reality, things tend to be messier. Assuming that the internet is going to be always available for something like a calendar is not an option. So how to store the data?
Today I spent the time trying to see how the data will be store. How different sources will interact with each other during offline mode and online mode.
Let's think about what are the problems before jumping to the architecture:
- A browser cache can be wipe at any moment and recreated from the source.
- It can handle offline/online in a way that is easy to understand for the user (Ideally transparent)
- Enables the addition of backends and sources without too many problems.
With that in mind, I take paper and pencil (or surface and surface pen) and start drawing.
Ok. So I need several building blocks. Ideally, all of them are easy to change for one another, so they need to follow the same interface. After all, this are normal events, so I need an interface that covers all CRUD operations:
- get(id): Get an event by its id.
- find(criteria): Get all events that match some criteria.
- put(event): Create or update an event by its id.
- delete(id): Deletes an event.
Now, the app should not know about the internals. Should not even care if the events are coming from a cache, from the Backend, from Google calendar, or from Microsoft outlook.
Let's see the different components:
- Events Source: This could be a future Backend, Google calendar, Microsoft Outlook or a simple Caldav connector.
- Events Cache: This is a storage that is within the browser. This one should return within < 100ms every query.
- Events Sync: This merges the previous two. So there is one for each Backend.
- Events API: This abstracts all Events Sync, so the app does not need to know where the events are coming from.
Other design considerations was the nature of the browser. A browser can have several users, so the data should be cached based on the user, and give the user the option to wipe out all the cached.
Let's start looking into the Events Cache component. There are two main options to store data in the browser:
Browser provides support for WebStorage: localStorage and sessionStorage. It works quite well for most of the cases, but have some challenges:
- It does not have an out of the box migration system.
- It does not have support for several tabs (what if you migrate one tab while accessing the app from another)
- It does not have support for native types (I need to serialize and deserialize on each operation)
- It does not have any search or reduce function.
I think indexedDB should have been developed after, as it solves all these problems.
Ok. IndexedDb seems to cover all my pain. Let's start coding and run some test.
IndexedDB is not supported in node, meaning that I can't create tests that use indexedDb. It should not be difficult to run the test in the browser... but, You know what: It is.
To solve that I found several tools. The ones that look more promising were: cypress, karma and testcafe. Sadly they need some setup or ejecting the react app — things I didn't have time to implement.
So let's make it work and see how it goes.
If you have any experience with such frameworks, let me know:Tweet to @guillermooo