I've been programming full time for nearly three decades now. Early in my college days, I learned about structured programming, how to design systems to be modular, and to re-use code as much as possible. In the early 90s, I brought what I learned in the procedural era forward into the object-oriented era. I was a big fan of the Design Patterns book. Over the years, I continued to move this practice forward in some way, shape, or form.
One of the tenets of this style of development was the idea that if applications were written properly, you could replace entire sub-systems without rewriting the entire application. So how many times have I had to actually perform this task? Doing a scientific survey of the various systems I have written over the years; I have come to a final calculated value: ZERO. Until last week that is?
As I took the Tube from Heathrow into Central London, an e-mail from a client popped up on my phone: It read: “We are currently experiencing show-stopping errors for the mobile application for people who upgraded to iOS 13.” As of late, a lot of issues with our HTML 5 application stem from Apple's arbitrary changes to their JavaScript implementation in Safari. My question to myself was “What did Apple do THIS time?”
It turns out that a feature we relied on heavily was deprecated in the latest version of Safari. When we started this offline application, we built the foundation of our application using a feature of the HTML5 spec called Web-SQL. It turns out that Web-SQL was deprecated a few years ago because of browser vendor politics. Apple chose to snuff out this iOS 13 feature once and for all. For those readers savvy about such things, I'm aware of a feature of iOS-Safari called “Experimental Features,” and how I can theoretically turn Web-SQL back on via the simple flick of a switch.
You can theoretically turn Web-SQL back on via the simple flick of a switch.
In our case, turning this feature on didn't fix the issue. We issued an alert to our engineers in the field asking them to hold off upgrading iOS 13 until we could come up with a fix. I thought to myself (actually, cursed to myself), “what am I going to do to solve this?”
Well, lucky for me, those principles I learned early in my education and career finally come into play. Three or four years ago, I rewrote big parts of this system so we could build new features using a “cookie-cutter” approach. The logic for managing our forms library was encapsulated into a common module called baseform.js. This module has three main components: a set of HTML files for the interface, a set of definition files used to define the data used by the form, and a single wire-up file that's used to tell the baseform.js module how to stitch all of these different parts together into a running form. Part of this process is used to create the SQLite tables used to persist our form data. These tables are generated using the definition files required by the base form.
This is where the story really begins. How do we change from a SQL-based storage engine to an in-memory storage engine? Luckily for us, we had a foundation to start with.
Over the last few months, we've been working on a time-tracking application that will provide the foundation for our changes. During the construction of the time tracker, we decided to store its data in memory versus using the SQL infrastructure we'd always used. Basically, we stored all our time data in an array of JSON-encoded data. Could we use this same mechanism for our form data? With this question in mind, I started my investigation.
With this question in mind, I started my investigation.
The first step was to narrow down how baseform.js handled the CRUD (Create, Read, Update, Delete) operations for a given form. Fortune shined upon me and the process of handling these operations was confined to a few narrow slices of code. These slices of code copied the contents of form data into arrays. The original logic then took these arrays and created their respective SQL INSERT and UPDATE statements. With the heavy lifting already completed, I simply needed to create a mechanism for storing the data into a large JSON encoded array. That was the only really difficult part and it wasn't that tough, in all reality. It took around eight hours from start to finish to complete this structural overhaul.
When looking back on this overhaul, I consider that a combination of several factors helped its success, which brings to mind a prophetic saying: "Luck is what happens when preparation meets opportunity." I was both prepared and lucky. When it comes to being prepared, the initial design of the code was modular enough that we had specific points of code. We'd isolated their functions properly, particularly the points that gathered and stored data from forms. This was also lucky. We essentially created our own luck. Finally, the “opportunity” was created by our fine friends at Apple. They broke our code, which created this opportunity for us to switch out our storage engine. As luck would have it, we were prepared to have our theory meet reality head on!