During the global COVID-19 pandemic, I worked for Airfinity, a disease forecasting company that rapidly adapted to the fast-moving nature of the outbreak. As we collected and aggregated various data, it became clear that we needed to move quickly. Our small development team innovated to meet these challenges. Although the platform initially struggled, with some pages taking an unacceptable 28 seconds to load, we were able to solve these issues effectively.
During this time, requirements changed within days, and the shape of data varied significantly. At its simplest, we provided tables with powerful search and filtering systems. We also delivered many custom dashboards, graphs, and analyses daily, often tailored to specific entities' needs.
To meet these demands, we built a custom platform and utilized other tools like Tableau and Shiny dashboards, depending on the best fit for the required data.
One key challenge was serving this ever-changing data in a timely manner. We addressed this through our "configuration over code" approach.
While this term isn't widely explained online, it essentially means preferring to use a set of settings instead of code to modify a program. For example:
Preferring:
const paragraphs = [
"Hello",
"World"
]
<>
{paragraphs.map(paragraph => <p>{paragraph}</p>)}
</>
Instead of:
<>
<p>Hello</p>
<p>World</p>
</>
This simple example illustrates a concept we applied throughout the platform.
A crucial decision was choosing the form of our configuration object. We opted for TypeScript for its type validation, allowing us to move quickly without unknowingly breaking things. We validated routes, data columns, and even smaller elements with features like string unions.
This approach made it easy to add content while maintaining strong type checks. Importantly, we could compose our configuration in various ways, abstracting and reusing similar configs across pages. However, we approached this carefully, as shared elements don't always warrant combination.
While this method proved great overall, it did have some limitations:
In some parts of the system, we implemented strict checks to avoid common errors. This involved a pretty complex set of types. This worked well but required developers to understand the types to make changes, presenting a challenge for those without TypeScript knowledge. Despite this, we felt it was a fair trade-off.
The ease of adding new configurations led to daily additions. However, this also made it easy to leave unused elements in the system. Periodically, we had to clean up these unused configurations to maintain easier system maintenance.
Using TypeScript allowed us to include non-serializable elements like functions and classes in the config. While convenient, this came at the cost of serializability and the ability to perform static analysis.
Our rapid development occasionally required implementing quick solutions. One such instance occurred when users reported extremely long load times on certain data-heavy pages. The ideal solution of fetching only necessary data from the backend wasn't immediately feasible due to complex data manipulations and user customizations. So we made the call to handle this on the frontend.
We implemented an incremental loading and caching system using web workers and IndexedDB for storage. This system loaded data incrementally using exponential backoff through a web worker to avoid blocking the UI thread. The data was then cached in IndexedDB, allowing us to perform needed manipulations without significant performance penalties and allowing us to reuse data on subsequent visits. This approach also required us to manage cache invalidation, but that's a story for another time.
Implementation was challenging, with many moving parts and obstacles like the serializability issue mentioned earlier. The diagram below illustrates the approximate structure of this solution.
After implementing these solutions, we achieved:
Airfinity has since then won the Tech Champions 2023 award and was shortlisted for the DataIQ Awards 2023 ‘Best Data Story or Data Visualisation’ award. They have also expanded their operations to the US and Japan.
Hire Me!
Currently looking for a remote contract work
Michael is a full-stack developer and the founder of Recall and DbSchemaLibrary.
He primarily works with React codebases but is proficient in all aspects of the stack, including back-end development and system operations.