During 2019 I started on the current project. At this project I’m working on, we are building a enterprise system for a government customer. When I got in significant parts had been developed of the frontend and backend system. My role when I started in the project was in order to help develop test automation software for the system. Since I’ve worked on both frontend and backend parts in other systems, I’m able to help out in various parts of the system.
I’m going to talk about one particular issue in the frontend code. When I got into the project, the frontend used mainly Formik for forms. There is significant complexity in the frontend code. Some of the forms are quite complicated and have a lot of behaviour. While debugging we noticed that the frontend started to slow down significantly for the bigger forms. Since the end users was not affected, we hoped that it would be fine. As new requirements got implemented the slowdown during development started to manifest during end user testing.
The question was what to do? The first obvious options are the following:
These options are not very palatable. Changing the design and requirements would require stakeholders to agree on new requirements and a new design. Since there has been a lot of politics involved in getting the current design and requirements approved, changes would require significant amount of time.
We started evaluating different libraries. Problem with that approach is that it requires a lot of changes in the frontend code in order to evaluate if the other library would improve the performance. This could potentially end up eating a significant amount of trial and error (potentially costing weeks of effort).
While looking at the Formik code base in order to optimize it, we noticed that there is a lot of historical luggage that shows up in the code making optmizations quite difficult.
Since there is a lot of luggage in Formik, but we only use selected parts, we realized that given around 20 hours work we could implement a library having the API surface that we use but with better performance. Since we could evaluate different implementation options for the existing code we could do some trial and error (using the existing frontend) without having to do extensive rewrites.
During the implementation I talked to David Wincent (another developer in the team) about React performance and different approaches. We evaluated the following:
Due to the API surface that we used, it did not look as if it was suitable to use hookstate for the implementation (I had some issues getting the API to work using Hookstate). We like Redux, but we wanted to isolate state to avoid changes causing rerenders in unrelated parts of the application ().
There is a lot of code that gets executed during render instead of in the reducer in Formik. There was some insights into getting more performant code:
Since React is heavily inspired by functional programming, we could apply
We could get a library that performed significantly better than Formik for our purposes. The time it took was around 25 hours to get to a point where the performance did not impact the end users anymore. Functional programming patterns are useful for more than the sake of correctness.
Comments or errors? Fork this post and do a pull request on github