A project initiated by a high-profile client in the pharmaceutical sector, required significant new functionality for our production monitoring web application, the WebViewer. As it is often the case with projects that involve a considerable amount of work, we faced the classic dilemma: should we implement the new functionality using technologies we had already used thus far or should we adopt a more modern approach? In this particular case, the question mostly involved the UI of the web application and, therefore, it could be rephrased as: should we maintain (and possibly further establish) the convoluted jQuery, Knockout, you-name-it-Javascript-library status quo, or should we transition to a modern front-end framework or library? Expectedly, the major front-end technology contenders, in the case of a technology transition, were Angular and React.
The main tradeoff between the two approaches should be well understood by any software engineer who has been around long enough to have migrated successive technologies. Either stick to what you know, avoid the learning curve and the infrastructure setup involved in adopting a new technology and be productive right away, at the expense of staying with obsolete tools and eventually being less productive in the long run, or suffer a significant lead time, but enjoy higher productivity in the future. The main factors contributing to this decision are:
- Lead time until the team becomes productive with the new technology: The longer it is the less appealing it may be to adopt the new technology.
- Productivity of the old vs. the new technology: The greater the difference in favor of the new technology the more appealing adopting the new technology may be.
- Amount of anticipated future work: The greater the anticipated future work the more appealing adopting the new technology may be.
The above explanation could be simplistically formulated as a linear function: a = -b + cx, where b the lead time, c the productivity difference, x the amount of future work and a the gain from adopting the new technology. If a>0 then switching to the new technology is beneficial. In any case, eagerness of the developers to get their hands on the latest, shiny and cool technology may very well shortcut through the above rational process and prompt a leap of faith even if it turns out to be an overkill in the long term.
From RAD to Front-end Development
Before delving into the details let’s first visit some background information about the WebViewer. The first incarnation of the WebViewer was created nearly ten years ago and it started as a simple WebForms application, whose main role was to display various .rdlc reports via a Report Viewer control. Similar functionality had already been part of our desktop application, so by exploiting the web-based version of the Report Viewer we could serve the already existing reports over the web with little additional effort. In the course of the years, Rapid Application Development (RAD) web technologies (mostly relying on server-side components) began to show their limitations and people started to embrace Javascript as the tool of choice for web application front-ends. Although, the WebForms with Report Viewer combination did a good job as regards to implementing off-the-shelf functionality, things started to get messy very quickly when more subtle customizations were needed. An example representative of this situation is that in order to customize the reports we often had to resort to embedding significant amounts of VBA code into the .rdlc files; in an environment with virtually no documentation and debugging capabilities.
With these considerations in mind, we decided to gradually steer away from RAD tools and started building new functionality separately for the back-end and the front-end. The introduction of a Web API controller and various Javascript libraries was part of this strategy and signified the second wave of functionality enhancement for the WebViewer. Our first steps in the world of front-end development involved a commercial charting library, an open-source charting library, JQuery and sprinkles of various smaller libraries when deemed necessary. In those days, the front-end arena was overwhelmed by a large number of small players competing for prominence. The outcome of this work involved three multi-function pages, each with a JQuery-based options panel at the top and a specialized chart control at the bottom. By the time the need for a fourth page arose, the front-end landscape had started taking shape and many more options were on the table. Our experience with WPF and MVVM lead us to selecting knockout.js, a small MVVM library backed my Microsoft. Knockout.js was selected over angular.js (also supporting MVVM and much more), on grounds of smaller complexity and ability to use only where applicable (check out a relevant discussion or google for “library vs. framework” for more information). The outcome of this third wave of functionality enhancement was a reporting page with the same JQuery-based filtering panel at the top and a configurable, paginated, tabular report based on knockout.js at the bottom.
At this point you would be justified to think that the creation of a Frankenstein monster was underway. In our defense, our resources were extremely limited (1-2 developers) and our development efforts were distributed over three applications involving four development frameworks (MFC, Windows Forms, WPF, ASP.NET) and four programming languages (VC++, C++/CLI, C#, Javascript). As such, it was impossible to remain in accordance with the developments in the world of web applications by regularly refactoring our codebase. The arrival of the fourth significant wave of functionality enhancement brought us to yet another technology selection crossroads. The application was growing and it would soon become unmanageable, unless we took some drastic steps. This necessity for a robust and extensible codebase overshadowed the additional effort required to learn the new tools, despite the timeframe for the new project being extremely tight.
Why React
In the meantime, knockout.js had left the picture of the global front-end landscape and React.js was the new cool kid on the block. This time around the contenders for our front-end developments were Angular and React. Prior to making the final decision we experimented with embedding both React and Angular front-ends in our application. Already having a WebForms application in place meant that the layout of the application was determined by the master pages functionality of ASP.NET and the Site.Master file. In our strive to incorporate a front-end framework we identified three alternate strategies:
- Maintain the current layout and embed a separate front-end application on each new page. This would be a straightforward solution; we would just need to create a new .aspx file for every new page and include the front-end application bundle for that page in a <script> tag.
- Re-create the layout in the new front-end framework using a router to support the paging functionality and embed the pre-existing WebForms pages as an IFrame for the applicable routes (mainly those involving the ReportViewer stuff).
- Have both frameworks working side-by-side duplicating the same layout in the front-end application. Then, use multiple .aspx pages for the WebForms part and a single page with routing for the front-end part.
The third solution seemed too complicated so it was abandoned rather soon. For each of the first two solutions however, we were able to create a proof-of-concept scenario both with Angular and React. Ultimately, we selected the first solution as it wouldn’t require redoing the layout neither resorting to IFrame hacks to host WebForms pages within front-end components. On the downside of this solution, we would not be able to reap the benefits of a single page application to the fullest, especially with respect to transitioning between pages (i.e. we would not be able to use a router for page transition, but rather reload the entire page from the server).
Having decided to embed a front-end app onto each of the new pages tipped the scales in favor of React. The main reason for that being, again, related to the library vs. framework discussion. We needed a small dependency that would not bloat our javascript bundles as it would need to be included on each new page we added. Also, we did not need routing, and possibly other features, that Angular provided out-of-the-box. Had we decided to go with the second approach, Angular could be the more compelling option. For the details of how we integrated React with WebForms check out the next post. For a generic article of how to integrate React in a Visual Studio application check out this.