In the last few chapters, we’ve reviewed several kinds of technically or practically must splits. In Mutually Changing: Applicative Physical Boundaries we’ve split away the UI, which formed a client-server relationship between a tuple of a backend and a front application. It was a unique split, causing our deployed applications to have a physical boundary between them. One would be deployed to our servers, the other to our customer’s browsers. In the followup chapter, we’ve seen that splits also occur due to virtual boundaries such as organizational structure, which creates Rollouts and Delays.
Afterwards, we explored another technical/practical split, between our application and its data. In order to differentiate between the two, we’ve first persisted our data with files and only then encapsulated it with a database.
These splits do have a negative effect on our development workflow and complicates it. We haven’t disregarded it, but we’ve said it is not an Inefficiency. There currently is no technical solution or practice to completely overcome it, although we have seen some use cases where it is avoidable, and techniques to ease it.
But what about splits that are optional? To answer this, we’ve first had to clear out all the hard technical considerations, for that we reviewed the technical/practical musts. But before that, we’ve learned of our development workflow. On how any split affects its Bottlenecks and Throughput. And we’ve seen how splitting deployments and splitting Throughput affect it as well. And somehow everything always had something to do with the frequency of Change and the unsteadiness of the Change Stream.
In the next three chapters, we’re going to put it all together. We’ll be reviewing several use cases, to learn when an optional split would be an eventually beneficial one, or otherwise.
Although RapidAPI’s backend had been split according to an early domain driven design, its frontend was not. The practice and technology that enables such splits was not in existence yet, only emerging around the time I joined the company in 2020.
One of these domains was owned by the Monetization team. Their products’ UI was scattered across and embedded within other groups/domains’ frontends. All bundled together into an extremely complicated frontend application. Its design had weared off through the years and the application experienced a combined Throughput of about 15 engineers. It caused it to evolve way beyond a Monolith, into one big Bottleneck.
When Ellah from the Monetization team had to make a Change to the frontend, she had to wait for a few days as we were deadlocked with our fellow engineers. A Delay was created as it was owned by another team. And it was followed by a hard deployment, which bundled together many Changes. Multiple Bottlenecks resulting with Back Pressure all the way through the business – our inability to ship reliable features to our customers on time.
The Bottleneck was a technical one and it required a technical solution for it to be removed. Our solution was based on a micro-frontend infrastructure. It allowed our smaller frontend applications to be hosted in larger ones. A kind of reverse dependency which enabled the applications to split into mutually exclusive ones.
The split had allowed the Monetization applications to be independently deployed and developed from any other frontend application, the main one included. It entailed a Throughput split for the Monetization’s team, away from the rest of the teams.
For the Monetization team it was a Bottleneck removed thus their Throughput was increased. Their applications were no longer bundled with the main application. It also made the deployment far easier and shorter. Back Pressure was relieved through the entire development workflow. All resulting in us better delivering on time. The Monetization team ended with an entire workflow with no Bottlenecks, without loss of Throughput.
Unfortunately, it wasn’t so for the rest of the company. The main application indeed consisted of less Modules and it was hit with less Changes, but just by a little bit. Just by the Throughput of the two frontend engineers of the Monetization team. The main application’s design had not Changed, and it was still a Bottleneck. A split does not guarantee a deceleration of evolutionary processes.
The main application was later refactored to ease the Bottleneck somewhat and some Throughput was indeed regained. The new Monetization micro-applications were also refactored a little, but it was done along the way with the split. It was less of an immediate need, because from now on they would need to withstand less Throughput. At least for a while.
Let’s recall the Change Stream model, and see that our frontend application now better matches it. It shouldn’t come as a surprise, because Monetization was always an entirely independent business domain. It was always an independent cut within the Change Stream. Monetization never had any Cause to Change together with other applications and shouldn’t have Changed together with them.
We were just technically limited from allowing it to be so. It was the micro-frontend infrastructure that enabled the applications to be independently deployed and developed, which enabled it to turn into a Direction of Change. Only this time, it wasn’t for a composition of Modules in a single application. It was for a composition of applications, one nested/hosted within the other.
Same as with any two mutually exclusive and independent applications, each would have its own evolutionary process which would be slower. In the short term, each would be free to grow, be modeled and use different technologies. One could use the React framework and other Vue.JS. In the long term, it makes our frontend better prepared for technological shifts.
Splitting our frontend is not a technical must, but up until it was technically possible with micro-frontends, it was also not feasible. On the other hand, we’ve seen the results have been beneficial. Although it always had a negative effect on it, only from the moment it was feasible/optional until we were getting it done, it was an Inefficiency and a Bottleneck to be removed in our development workflow. Question is, how did we know in advance a split would be eventually beneficial? To answer that, we need to examine the Change relationship between the micro applications and the main one.
When there is a Cause to Change them together, they must be deployed one after the other while maintaining backward compatibility between the two. This creates an idle time for an engineer, and requires planning ahead. They can not also be Changed at once and are owned by different teams, so there would be Rollouts and Delays. It sometimes was indeed the case.
On the contrary and although independent, they still did intersect and share commons such as UI Components or plain business logic. Once split, they are both Modules to be shared and distributed between multiple applications. In this case, these Modules were extracted into an independent Module that is not an application – a Package. And it required quite the initial effort.
Sometimes in order to complete a Task, Ellah from the Monetization team needed to make a Change to the UI Components package. A bug fix to a UI component used by one of the Monetization’s micro-frontends. As it is owned by another team and it still sustains the entire company’s Throughput, when Ellah wishes to do so it would be a Bottleneck for her. She’d experience a Delay, until the Rollout is done. It would have been no different from the baseline workflow on the one single frontend. A no-lose situation.
Sometimes she would experience a Bottleneck, sometimes she would be on the fast lane for delivery. How frequent each and both would happen, is a question of frequency of Change. If she’d experience a Bottleneck on each and every Task, that would be an Inefficiency. All we did was replace one Bottleneck with another, dooming the split to being non-beneficial. On the contrary, if she’d need to do so only once a month and the owner would merge at most after 24 hours, this would not become a Bottleneck, not be an Inefficiency and it would be deemed a beneficial split.
Greg from the Marketplace team would be experiencing something else entirely. As the owner of it, he now has a Cause to Change the UI Components Package A Product Manager decided that all of the company’s dropdowns would now have a curtain revealing visual effect. Greg had indeed made a Change, but as it is no longer a single application, he can not deploy it to everywhere on his own.
As other applications are owned by different teams, he would experience a gradual Rollout for his Change, with a Delay. Multiple deployments would be required, instead of just one. And until the Rollout completes, the company’s UI/UX would be inconsistent.
Even for him it is a question of how frequently a Change to the entire UI would occur. If Greg has to do so once a day, it is a Bottleneck for him, an Inefficiency and a non-beneficial split. If he’d have to do so once in a few months and Ellah would be reacting fast enough, then it would be a beneficial split. In the once in four years scenario of a company going through an entire redesign on the UI, maybe a gradual Rollout of small Changes instead of one big Change would be most beneficial. It could be true also from the product’s perspective, as it is beneficial to get Feedback sooner than later.
In the end, we’ve seen that both for Greg and Ellah and their highly frequent and daily Tasks, a fast and independent workflow would open up for them. And for the non-frequently ones, we’d be mostly in a no-lose situation. That would ensure it would make the split into a beneficial one.
If it has something to do with the frequency of Change, it has something to do with the Change Stream thus with Cohesion of Change and Cohesion of Causes. What cohesion has to do with it, we will see in the next chapter with another use case from RapidAPI.