In the middle of 2013, I was hired to lead the engineering team at LearnZillion–a digital curriculum for K-12 Math and English subjects composed of videos, slides, documents, and images. At the time, there were several applications in support of the business:
- 2 Ruby on Rails web applications: the content authoring platform for a select group of users and the content consumption platform most teachers and students used
- 2 native mobile apps: 1 iOS and 1 Android for students only
- 1 API inside the content consumption Rails app, which served data to the 2 mobile apps and the web application
After a few months, momentum led us to build a publishing API so that the 2 Rails apps could talk with each other. (Before this second API, we were painstakingly moving data between the two apps via CSV and file exports and imports.)
Having recently left a company where we were migrating from one monolithic application into dozens of microservices, the momentum felt right. It was the in thing to do. Microservices were hot. However, as time moved forward, it became increasingly clear at LearnZillion that a microservices architecture came with a non-negligible overhead cost: the cost of keeping not 1 but 2 Rails apps up-to-date with dependency upgrades, authoring 2 APIs internal APIs, 3 API clients, and often changing all 5 when adding or removing a feature, all to pass data around. On top of the software management overhead, there was the overhead of hosting each and bending over backwards at times to make sure that APIs never called themselves. The benefits of having separated apps and APIs were dragged down by the cost.
We didn’t want the over-complexity and overhead, so over an 18-month period, we did a 180. We brought content authoring into the content consumption app, killing-off 1 Rails app, an API, and an API client. We also transitioned our iOS and Android native apps in favor of a cross-platform Ionic app that WebView-ed our main Rails app on both iOS and Android, killing-off an API and 2 API clients.
We now have 1, hosted app, built the Rails way, that has a median response time of 75ms, 2 hybrid mobile apps that look and function identically, and whenever a feature is deployed to our main web application, it is immediately available inside the mobile apps. No extra moving parts, no coordinated deploys. Most importantly, this setup allows us to scale the impact of each member of the Engineering & Design team by keeping each one focused on the features, not on a microservices architecture.
Our course, there are plenty of valid reasons to have microservices, purely native mobile apps, etc., but this is not always the case.
I’m merely warning against jumping on the microservices bandwagon because it’s the in-thing. And this is a concrete example of where microservices were hurting a business not helping it. Thankfully, it wasn’t too late to reverse course. And I don’t think our team could be happier with the results.
As one of my colleagues says, “you have to use your brain.”