Post Mortem: Modernising an insurance system
23 Feb 16–03 June 16
Note to the casual reader: This is pretty boring, you might want to skip over it, it’s just self documenting what I’ve worked on and probably isn’t even written well.
At the end of February I returned to Tasmania and met up with a few old work colleagues for lunch. After a catch up I was asked if I’d like to come on board and help out with their new customer facing quoting website. I had a couple of projects I had to tie up first but a couple of weeks later I got stuck in.
It was built on top of bootstrap, however it had one main large less file that did the majority of styling. This file was over 8000 lines long and was littered with `!important` statements. It was completely unmaintainable.
The site was functional and working well, but the rich functionality was kind of at its limit. The most complicated page was an assumptions page, this page consisted of a list of options the insurance company makes about the quote. The user has the option of changing any assumptions that are not correct. e.g. it might be assumed that the policy holder will not be driving a high performance car.
The way it worked was a bit horrible, the user would change an option in a panel, that panel had it’s own form and that form would be submitted. The server would send back the updated html for that entire panel and replace it. This is pretty typical of old .NET Ajax forms but it had it’s issues. Already there were 7 or 8 forms on the page, that is pretty difficult to manage and elaborate on.
Another problem it caused was due to the fact there were a lot of third party jQuery plugins that used the horrible method of decorating and adding event listeners on the document.ready event. When the ajax form replaced all the html in these panels these components were no longer decorated or had any of the required event listeners to work properly. So the code had some work-arounds that would fire these plugin methods when the panel is replaced with new html. It was quite clear that this page would be hard to improve if there were any new requirements.
When a new requirement came up to to allow the user to save their half finished quote it became tricky, you can’t easily submit the 8 ASP forms in one go, one of the reasons I dislike Microsoft's forms framework, it abstracts a lot away from what makes the web great. So trying to implement this feature was already proving tricky.
I spent the next few days thinking about what I wanted to change and writing down the reasons why. I then presented my arguments to the existing developers to convince them of the path I believed best to go down.
The first thing I wanted to do is get the spaghetti nest of client side resources under control, so I suggested using Webpack. There really isn’t anything better at the moment for managing client side code than this tool, there are other tools but they aren’t as powerful. The main thing Webpack does that other tools do not is code splitting. Which is incredibly useful when you want to optimise your site later on.
I then began getting all the legacy code that’s been copied and pasted on every page into modules that are compiled with Webpack. I moved stuff around so that code that was quite obviously copied and pasted was then put into a shared module. This was an incredibly tedious process but it was beginning to get a handle on the code base.
This tested my Webpack understanding as there were a whole bunch of different client resources. Custom fonts, less, sass files, images, etc.
Webpack also had the added benefit of being able to bring in ES6 to write all code going forward, which is amazing for doing more with less code and keeping your code base easier to reason about and read.
The assumptions page had lots of little bugs that made it feel clunky. This was mainly due to how it worked. It was a mess of jQuery, lots of functions that ran based on different events and user actions. The user would click something which caused lots of other functions to fire off and change strings in the UI or do something else. It was in dire need of something better to manage it’s state. So I convinced the other devs that bringing in redux to handle the state would solve a lot of these problems. Redux’s one way data flow really helped simplify things here.
I had a mix of jQuery built DOM components and React components so I had to manually subscribe to redux’s store for the non React stuff and I used `react-redux`’s `connect` method for the React components.
As bugs were fixed and the ui improved, gradually the application became more and more React orientated. I put in a few extra hours to switch over bits of the application that weren’t already React. As having it all working one way greatly simplified the code base. It also meant we could switch to a single page app and drop some of the legacy dependencies that were hugely inflating the client bundle size and causing annoying bugs.
With everything made up of React components, all the styling for each component lived in a CSS file coupled with all the resources needed to build that component. This was much easier to maintain, if you need to update a style the developer knows straight away where to go and what to update. I could then drop the 8000 line less file that was littered with `!important` statements that caused a huge amount of grief.
Eventually the site became a single page app which gives the perceived performance of almost instant, this is because only content is fetched when it’s needed and full page refreshes are no longer needed.
With the front-end greatly simplified and no reliance on MVC (apart from using the model for validation server side) it created opportunities to simplify the backend. There’s now no need to distinguish methods that work for certain pages, you can have generic methods that are not constrained by the structure of your architecture. e.g. Instead of methods to save the data on the address page or the assumptions page, Instead you can have one ‘save quote’ method that you can reuse. This reduces the complexity of your backend and makes your code way more maintainable. I spent the remainder of my time here before moving on to another project.
I worked incredibly hard converting the application over to fully react and put in a few extra hours to move things along quicker.
Overall it was hard but worth it, the application works lightning fast. It was challenging convincing my colleagues to use ES6 and go fully react but I’m grateful they came on board with it.
I think the results speak for themselves. In 3 months the perceived performance is instant, due to going single page and code splitting. And the client side code base has been reduced from 31k to 6k lines of code.
What was hard and what I learned
State and validation are the most difficult things.
Doing validation in react, still unclear of the best way to approach this. We already had a lot of business logic written in server validation code that was heavily baked in to how the MVC model validation worked that existing developers didn’t want to re-implement in client side code.
So I elected for creating redux actions that validated and saved the data. It would post some data over to the server which would either return nothing (success) or validation errors. The validation errors were then put straight into redux state where components could re-render themselves to display the errors, this worked really well and I’m pretty happy with the simple flow. The only draw back is the latency of server side validation.
In some cases simple client side component validation was added, I stuck functions calls in the render methods of components that would figure out if the props passed in were valid or not and consequently display errors on the screen if that was the case.
This also caused some heated debate with other devs about what gets stored in redux state. I was of the opinion that it’s okay to store invalid data in state, as state is not a data store and should at any one time describe your application completely whether it’s valid or not. I often found myself thinking this definition a lot in my head to reason about where to put state.
I found that 99% of the time if you're using redux with React and a component has state, it’s probably wrong and should be put into redux state. The only valid case for component state is for something like a dropdown being toggled open and closed, that could be component state, but still probably shouldn’t be. It’s easier to be rendered based on props poked in with redux. Once you try writing some code to close that dropdown from higher up the component tree it becomes very convoluted if it’s in component state.
In the future I’d consider using a React alternative that doesn’t have component state or just write my code without using component state, unless absolutely necessary. In summary don’t use component state, let redux handle all your state and keep your redux structure really minimal, don’t convolute it.
Looking for a company to take on your next project? Try us out www.lunait.solutions