Microservices to Monoliths
When I was working at Expedia Group, it was primarily a microservices based architecture. There was a big monolith and then it got pulled apart into smaller services. Towards the end of my time there, these small services were being compiled back into a new monolith as the current trend was to return back to the monoliths or rather labelled as monorepos.
Moving to Atlassian I got introduced to my first "real" monorepo. It contained all the frontend code for all its products. The backend was still micro-serviced but the services were quite large and was divided by domain. At first glance and one paper it felt like the perfect ecosystem. In reality, the frontend was a nightmare.
The backend made sense. We were in a large team that owned the domain. Those who worked on it were in this large team of ~50. Changes to production can be done quickly and easily, with little conflicts or interruptions when trying to merge a pull request. It was not the same for the frontend.
The frontend monorepo had 1000s of developers. It has a platform team that would maintain it and be very responsive to helping solve developer issues. This is good so far, here comes the bad. The repository is primarily TypeScript, and the language server is slow. Indexing took quite a bit of time and would sometimes crash. Trying to navigate through the code or write code with this slow language server was painful. This caused me to lose my flow state and would often have to restart VSCode or debug some editor issues because of things crashing.
The platform team constantly made major changes. This may be the cause of the rapid growth of the repo and they are trying to fight fires as well as reduce load on their team. However, these major changes affected everyone. Your PR that's approved and was previously ready to merge is now broken. Fixing these changes may lead your PR to lose your approval and require another request. This may take you into the next day. The other issue with frontend builds is that builds can be flaky. Meaning that they may fail for a reason that's not your cause. Sometimes there were cases when a PR got merged but it was broken. Causing all PR to now fail when merging with the master branch. It felt like hell. Even when taking the initiative to fix it, other developers are also doing the same and a lot of stepping on toes occurs.
I strongly believe that the frontend should not be a monorepo but rather be domain specific repositories, like it is for the backend. If design consistency is a concern then a component library can be the shared resource to help provide it. Small companies should not worry about such concerns, this would only be applicable to large enterprise organisations. What I have witnessed in the monorepo is that it is already separated into domain level and team level packages. Within these team defined packages fall into different code styles and varying levels of testing. Platform teams can argue to define rules but it will cause friction to teams and their deliveries.
Engineers want to be owners of their craft. If a new feature or a problem is to be worked on, engineers want to jump in without too many unknowns and provide estimates without worrying about unforeseen platform issues.
Don't lean into trends from a known company that works for them. Rather lean into what works for the organisation. Focus on the product and see if the platform can scale with current architecture or the next 3 to 5 years, and if not fix early, but not rebuild the whole thing unless it's completely necessary.
My overall opinion, microservices or monoliths which is better? The best is the one that lets the domain team own it. Only bridging platform libraries should be monorepos to provide organisation consistency. Repositories should not be owned by less than 3 developers at absolute minimum. 5 developers minimum, 10 or more ideal and no more than ~100 developers. This way knowledge should be transferable with engineers leaving and newcomers starting.