How adopting Microservice architecture helped us not only in backend and front end scaling of the application .. but also how going micro teams helped us scale our processes and engineering teams
Throw everything away and start again
Massive waste
Upgrade to Angular 5 or Vertical scaling
Too cumbersome to migrate
Maintaining two apps in parallel is not easy
Split resources for bug fixing
The awesome third option: Micro frontends
Throw everything away and start again
Massive waste
Upgrade to Angular 5 or Vertical scaling
Too cumbersome to migrate
Maintaining two apps in parallel is not easy
Split resources for bug fixing
The awesome third option: Micro frontends
They solved the problems we had...
Ownership
Code Conflicts
Keeping developers interested
Plug-in multiple frameworks
Futureproofing
Gradual migration
This level of code sharing between deployable artefacts, libraries and plugins lead to a situation where the blast radius for even the smallest changes became quite large. Here, the blast radius refers to the number of deployable artefacts that have the potential to be impacted by any given set of changes.
As a result, we had to install updates manually - combing through a manifest file which would locate recent changes, and pull from each location manually, or risk missing changes with automated installs.
But how did we get here?
As is always true, our priorities have changed dramatically through different stages of our growth. While in Beamery’s infancy (our seed round, for example) a MVP was the most important goal and some cut corners in our codebase were just the price of doing business. Now we’re quickly growing into an enterprise software company and our concerns are different - not only managing our new size and usage but continuing to scale efficiently.
Interlinking dependencies are a known problem in Node.js codebases, particularly at this early stage. If you’re ticking off features, on-boarding new engineers to the team or even building new teams entirely, futureproofing your code is probably low on your to do list behind making the whole thing work. But, in the process, you’re building a web of dependencies which takes ever longer to get comfortable with. What starts as 3 or 4 dependent repositories turns into 10 or 20, and before long you’ve got no time to untangle it all when you’re still hitting feature deadlines.
Although there are certainly arguments both for and against a Monorepo, we made an early decision to go Meta, which is probably another whole article in itself. Versioning all our repos properly would have required a transition to a more complete continuous integration tool (we were using Jenkins at the time).
Both options felt like serious structural changes, which would have brought their own set of problems, not to mention the downtime when implementing them. Ultimately, we built Story to let us continue to move quickly and scale without stopping production, since we just couldn’t make the business case to down tools and change tack. We might be a few years older and wiser, but some pressures never change.
Founders obsessed with culture.
A strong sense of self
Rituals
========
As you move up the ranks of leadership at a product org you quickly learn the most important product to get right is how you organize your people. How you structure your org can be a force multiplier or an incredible hindrance to achieving your mission. From my experience there are a number of key ingredients to successful org design:
Optimize for dedicated cross-functional teams with a clear mandate. In my experience this is the single most impactful thing leaders can do when setting up a team. You want self-contained teams that can move as autonomously as possible, towards an agreed upon goal. Any missing resource (e.g. designer, DS, budget), additional cross-team dependency, or conflicting surface area, cuts the team’s impact by an immense amount (this is often invisible until later). Think through all the times a team will need to meet with or wait for another team and make that number as small as possible. Well-functioning teams feel like a black box that outputs regular updates and amazing work.
Get the goals right. A lot has been said about goals (e.g. SMART goals, OKRs), but I think teams still underestimate the power of getting goals right. In my experience the right goal is the difference between incredible progress and unending churn. What has worked best for me are goals that (1) are as few goals as possible — ideally just one or two, (2) have quick feedback loops so that you can see impact immediately, (3) have a direct connection to top-line business growth, (4) are easily understood, and (5) are uncomfortable.
Be aware that there is no perfect org design, only the best idea you have at that time. While at Airbnb I’ve been through almost a dozen re-orgs. In that time I’ve never seen a single org plan that addressed every issue and that everyone was happy with. Make sure you’re addressing the biggest pain points, future proofing it as much as you can, and then just move forward. It’ll have flaws (e.g. overlapping product ownership, two teams with the same key metric, a team owning far too much), so note them and put systems in place to work around them. Set expectations that the org will change again in the future.
=======
Premature scaling troubles are everywhere in startups. In the early 2010s, SQL databases were shunned partly for the (perceived) infinite scalability of NoSQL databases like MongoDB and Cassandra. The startup productivity benefits of monoliths was lost in the excitement around microservices. For years, Rails has been called unfit for startups because it is slower than other frameworks.
=======
Each of these engineers has their own risk for a startup:
Large company engineers are often exposed to scaled systems and may not feel comfortable with hacky code. They are much less likely to be exposed to their users.
Elite computer scientists get bored by the plumbing-type engineering that typifies early startup tasks, leading to overengineering.
Junior engineers, who are often attracted to startups, may inject too much new technology and poorly architect their systems.
Development shops often favor technologies that let them be productive across many clients. These shops have no incentive to learn new tools for a particular client, and they also don’t have the long-term skin in the game needed to make critical early tech decisions.