Progressively migrating an enterprise SaaS product to Ember

This multi-series blog will focus on how we are migrating our Freshservice (Rails Application) frontend codebase, which was based on legacy technologies to, Ember.js. This part focuses mainly on the challenges we faced in Freshservice while sticking to legacy frameworks, how we integrated Ember into our legacy architecture, and how we plan to move the Freshservice frontend from a legacy architecture to a single-page architecture.

With a lot of rich User Interfaces across the product, we were facing many challenges while sticking to our older architecture. Some of these challenges were:

  • Unmaintainable codebase causing cyclic impacts.
  • Core framework upgrades were costing a lot of time and effort due to the large codebase.
  • No frontend test cases to ensure engineering efficiency.
  • Reusing code mostly meant duplicating files and missing impacts, adding to the maintainability.
  • Unable to adopt any modern tooling that makes life better, due to incompatibility with legacy frameworks.
  • Challenges in maintaining the single-page experience whenever newer modules are added.
  • Challenges in keeping the team up to date with the latest happenings in the JavaScript world.
  • Platform teams had to provide a separate version of their package to support our legacy codebase.

So, we thought of moving to a scalable framework that makes our lives easier by solving the above problems. We chose ‘Ember’. But, we didn’t want that to happen as a one-shot migration blocking our entire roadmap progress. We wanted to integrate Ember such that we can progressively approach the Ember migration itself.

To integrate Ember inside a Rails application, we thought of two approaches. One was to render the Ember app inside an iframe, and the other through Thoughtbot’s EmberCLI-Rails gem. We avoided the iframe approach for better user experience and to avoid unnecessary URL state management problems.

Thanks to Thoughtbot’s EmberCLI-Rails gem, which helped us to integrate Ember inside the Rails-based architecture. This gem helped unify the Ember and Rails workflow by mounting an Ember app to a Rails route. The diagram below shows the high-level overview of the actions done by the gem.

Architecture Diagram

Flow Diagram

In Freshservice, the top and side navigations are supported by legacy frameworks, and the center part is where we have integrated our Ember app. Based on the link clicked, the center part will be either served by legacy or by Ember. For eg: when the tickets tab is clicked, the center part will be served by legacy and when the solutions tab is clicked, the center part will be served by the Ember app. 

We have built new modules like Software Asset management, Purchase orders, Alerts, and so on directly in Ember. We already have an Ember app running inside our RAILS app for these newer modules. Our plan henceforth is to migrate the older legacy modules of the product to Ember, and progressively get the entire Rails app converted into a complete single-page application. 

In the legacy app, we already have a jQuery based PJAX plugin to maintain the single-page experience. Now, we are running an Ember app inside a Rails application. This should not cause any navigation slowness while transitioning from legacy to Ember and vice versa for fetching assets between the app transitions. To support that, we enabled the access of router transitions from outside of the Ember app. During the first hit to an Ember module, Ember assets are requested. Once the assets are ready, the Ember page gets rendered. Any route transitions within the Ember app will be taken care of from within. Any outside transitions from Ember to legacy or vice versa will also behave like a single-page experience since the assets are already available. This paved the way for super-fast page navigations between Ember and legacy pages.

In the second of this multi-part series, we will talk about the ongoing challenges faced in our Ember migration.

This post was co-authored by Vishnu Balaji and Vigneshwar Krishnamurthy.

 

Cover image: Vignesh Rajan