Our team at Deegloo started working on a new project in September last year. The goal of the project is to develop a React library that will simplify the steps necessary to implement feature pages in a web app for our client Dairy.com.
By providing appropriate configuration and HATEOAS links, the backend drives the look and feel of different pages inside the web application. Developers need to follow simple steps on how to include a library in their projects and follow a simple tutorial on how to set up frontend code for all of it to work. That way, backend developers who are experts in domain and backend technologies can quickly and easily implement new business requirements without the extensive knowledge of the ever-changing frontend ecosystem.
Working with the old
Before starting the project, the prototype of the solution was built and it was using MobX to handle the app state. Since MobX is something our client was using before in other projects, we stuck to it and started integrating new features into the library on a prototype base, and so continued to use MobX as a preferred way of managing state. From start, we adopted a single store for handling all of the necessary application states which needed to be shared between different components and which relied on multiple sources of data.
By following this approach, fetching different data from multiple endpoints also looked simple and easy to do, just fetch the data and store the response in a MobX store. Components could then get the data from the store.
As the requirements and complexity grew so did our store. Since our library has mainly consisted of two parts, lists and details, we split the store into two stores – one for the list page and the other one for details. But soon, the new requirement came which required us to display the table which was already presented on the list page and on details also. With our current approach, we were left with an option to extract the common logic into another store or to do something else about it.
A different approach
We took a step back and created a meeting with the whole team responsible for creating the library. In that meeting, we came to the conclusion that our stores could be split even further, but in a different direction – every store could have a single responsibility and provide just a chunk of functionality. That way we could compose different stores and provide the needed functionality. This approach looked really similar to using custom React hooks, which provide functionality based on some input data. The idea was then to see how common code from stores could be extracted into custom hooks, and only share the most necessary data between different components using React context.
The goal of the next sprint was to “kick” MobX out and rewrite everything using the hooks approach. And the goal was reached 🎉. By removing MobX we got rid of external dependency and also created a solution that is in line with the current best approaches from React team on how to build React apps. That way we can quickly adapt to new patterns and best practices from React team and minimize the impact of external dependencies on our project.
Advantages of abandoning MobX
It all seems great, but before doing something similar, it is a good idea to have at least some formal advantages and disadvantages of one approach over the other. The advantages of ditching MobX from our project could be summed up as follows:
1. Project doesn’t depend on external libraries anymore (MobX and MobX-React) – by managing state locally using API provided by React itself, we don’t have to rely on additional libraries, our project or library has a smaller bundle size (less included code), we don’t have to keep tracks of which version are we using vs. which version is the latest, deal with breaking changes in the library, potential bugs or missing features, etc. Outrage with faker.js and log4j was a reminder that businesses rely on software which is maintained by a small group of individuals (which they almost always do that in their free time and without any compensation) and could potentially contain vulnerabilities caused by lack of resources, or in more extreme cases, by individuals who are not satisfied with the situation, they are currently in and want to take it out on the world.
2. Current and new developers don’t need to learn how it works – it’s all great when the library used to provide a solution to a problem works with minimal configuration and understanding from developers who are using it to get things done. But almost always, there comes the time when we as developers get stuck solving a particular problem with a particular library (in our case it was MobX). Then, we need to spend some time searching through documentation and hope that documentation is well written (which in the case of MobX, it is) to find out if a library can be used to achieve what we want it to achieve, and how. Additionally, we don’t or can’t expect that every developer who will join us on that project will know (or want to know) MobX. With that in mind, their onboarding will surely be a bit longer as they will first need to familiarize themselves with MobX, which is not the case with simpler state management provided by React.
3. It’s mostly unopinionated – unlike Redux, which forces developers to follow particular guidelines on how to write code to manage state, MobX doesn’t force them to follow strict guidelines. It just provides APIs to simplify the job, but how will you create state and managed it in the end, is up to you as a developer. In this case, it’s similar to React approach with context and state, so one can make an argument why that approach is not used then.
4. Global state management can grow quickly if not maintained – this one happened to us on our project, the single store which had some state and methods logically grouped was reused over and over again for different stuff, which at first all looked like they belong there, and then size and complexity of store grew larger and larger by every new feature. This one is a bit of a stretch, as we can (and should) point out that this wasn’t the best developer practice and that we should enforce separation of concerns during peer reviews to keep complexity in place. But as we all know, sometimes developers need to be pragmatic, and balance the deadlines with best programming practices to achieve the best possible time to market with the least technical debt – this depends on every single individual and business needs, and that should be taken into consideration.
Disadvantages of abandoning MobX
As we discussed what are the advantages of ditching MobX from our project, it would only be fair to also point out some of the disadvantages (or let’s call them compromises) which needs to be taken into consideration when doing any of the transitioning to pure React solution:
1. Developers must know React in-depth – to achieve the best possible solution, developers need to know how React works, how it detects changes that will trigger re-rendering, how state and context work, how to use hooks effectively, etc. As project complexity grows, so does the code. There are more components, components are more complex or consist of simpler ones. Whichever is the case, if best practices are not used, potential bugs and problems could crawl in a codebase and could be potentially hard and expensive to remove, and could require a big chunk of code to be rewritten.
2. You’re on your own – apart from company or project guidelines on how to manage the state, you as a developer, who is fixing a bug or developing a new feature, must find the best way how to achieve it and combine it with an existing solution, which could be harder to do from time to time.
3. Quality of end result depends on developers skills – guideline from an experienced developer who knows React in-depth and how to design a good software is a must for this kind of solution, otherwise it can quickly turn into a mess.
We would like to point out that we didn’t start with our current solution, and that it’s reasonable enough that this solution will need to be revalidated and polished further out as time passes, new requirements emerge, and current best practices on building frontend apps with React change. We took state management library early in the project and took it for granted and in some cases treated it as a silver bullet. What we realize now is that React is really powerful as a view library and also as a state management library, so our advice before starting a new project is to revalidate your current (and future) use cases and see if (and what) state management libraries would be best applicable in that case. Even if the current solution you have is not something you’re really satisfied with, let this post serve as an example that it’s never too late to get it back on the right track!