When we designed our first prototype, we chose Rails to get something off the ground quickly, and the decision paid off. For many years, we ran the system from a single server, until we started to grow —we had some architectural choices to make going forward.
One of them was decoupling the Rails monolith into a GraphQL API in the backend, and an Angular application on the Front-end. That allowed us to take the UX to the next level, as features got more complex, since we wanted to guarantee a stable, fast experience for students and teachers alike.
Early on, we realized that schools in Spain had very poor Internet connectivity, which made using a traditional web application quite slow. After we shipped our dedicated front-end application, we quickly adapted it to be a full-fledged Progressive Web Application, with aggressive caching and offline capabilities. Suddenly users felt the application was snappy and extremely responsive. But this wasn't enough for us —as the front-end application grew in size, updates meant the clients had to download a large JavaScript bundle every time we deployed a new version. With code splitting, we managed to reduce both the risk in every deploy, and kept updates very fast from the client's perspective.
Once we built the GraphQL API, we decided to move from our traditional Heroku deployment to a containerized solution running on Kubernetes —we went from a single point of failure to a self-healing cluster that was able to autoscale as the demand for resources fluctuated.