What do you do when you have a large system that has been built up over many years, services a huge amount of your customers, and you want to improve conversion?
Over the last 18 months, we have worked to rebuild the user interface of trainline so that it appears more modern, whilst still working on top of the codebase that has worked for many years. We transformed our core booking flow UI to go from something that came out of the early 2000s, into a modern responsive website. This all with the help of great frameworks out there like Bootstrap and Knockout, along with Jasmine and CasperJS for our testing.
So for our customers, this fresh coat of paint helps our website work well from mobile, tablet, and desktop, and it has had a greatly positive impact on our customers.
However, our shiny new user experience quickly showed how our technical implementations were far from the ideal.
- We were still on our original codebase for our server side handling
- Our testing was producing a lot of interference with each other
- Knockout’s two way binding wasn’t entirely efficient
- Our code was dumped into one big bucket
- And no server side rendering
In our quest in trying to break away from a monolithic approach, we ultimately built another.
So we started to look outwards and see what others were doing. The new kid on the block is React. There are many tutorials out there about it so I won’t go into how to use it, but the primary benefits to us were:
- Ability to start thinking about componentization
- Unit testing exact components
- Creating compositions of many components to be another component or a page
- Server side rendering
- And greater code reuse for both server side and client side
Internally, we have now set up TeamCity to build many small components and publish them to an internal npm repository. This is then consumed by other React components, and built outwards to compose our pages.
With pages that are currently on our existing code base (which we are not yet able to rebuild entirely), reuse is key for server side logic whilst also making use of the newly created React components. Reactjs.net allows us to do as such, whilst providing us with the server side rendering feature through the use of managed V8 engines. However, we found issues including large memory footprint and sporadic failures occurring.
Another great library is edge.js which allows for interoperability between .NET and node.js. With node.js being more production tested and able to handle the large amount of traffic, it took one developer a couple of days to put together a wrapper to achieve the same result that Reactjs.net performed.
So how do you move from a solution written in .NET to node.js without a big bang approach?
With pages that we are looking to use node.js for, node.js will handle the initial request, executing validation and surface level business logic. On the same web server would be an internalised WebAPI which acts as a middleman to the existing .NET solution. This would look to take care of session state, authentication, and other remaining services, up until a point where it can be replaced by a node.js approach. We can also look to call code in the existing .NET solution for further reuse, however this will be kept to a minimum so we’re not coupled to it.
Having this clean layer of separation allows us to see the clear divide between the old and the new, whilst allowing business to carry on as usual. Furthermore, this divide establishes the parts to replace as our architecture within the company changes.