142 comments

[ 5.3 ms ] story [ 217 ms ] thread
Micro-anything tends to cause engineering orgs to spend more time drawing boxes and fantasising about what tech would be 'just-perfect' for that particular box than actually considering their users needs.

The killer truth is, the connections between your components start to become more important than the components, and the work to maintain this system is only really justifiable if the components can be worked on in parallel.

But that never happens, and now you spend all your time trying to herd cats. Embrace a monolith, modularise the code, discuss your work with your colleagues so you don't step on each others' toes.

We're here to build systems, not pet-projects/fiefdoms. There is no software architecture that will allow you to work in isolation.

Separate services helps a lot with bigger teams. No matter how much you modularize code -- which will gradually fall apart anyway unless you have custom tooling that enforces API boundaries programmatically -- you're still tying people to the same runtime environment, which means you're tying people to the same libraries and underlying framework/operating system. Which means major library upgrades become nonstarters (too much code to test/change), and runtime upgrades are rare and challenging (hello, enterprises still running Java 6/7).

There's a balance and the "every function should be a microservice" approach is kind of insane, but "just use a monolith for everything" falls apart pretty quickly at larger team sizes.

You're right, I didn't give any numbers. IMO for every dozen engineers you are allowed one monolith (but now you call it a service).
> but now you call it a service

What is a problem in itself. On every sane place, most of the "services" aren't providing any on-demand service, instead they are just thematic monoliths doing all of a part of a task.

I'm settling on the opinion that a service-based architecture is always wrong. But people keep calling the good architectures by that name.

Well, you’re almost at the moment of enlightenment.

Yes, all the good architectures are service based. And all service based architectures are wrong. Because all architectures are wrong.

In the sense that there’s always another way you could have architected it that would be better for where you think you want to go next, than the way it is architected.

Learn to accept that an evolving software system is always going to have a suboptimal architecture.

Hum... No.

You are misinterpreting my words here. I'm saying that I now strongly suspect that biasing the way you divide your software on a direction that gives you services will always make your life worse (probably by a lot). There's no philosophical allegory about perfect things not existing.

There are a few things that really want to be services. You'll settle those on services whatever way you decide to architecture your software. But those are very few, and any push into doing it for more than the absolute minimum is harmful.

I've seen microservices with inadequate boundaries, much like what you just described with monoliths. This was due to product evolution, or maybe initial requirements were not fully understood when the new architecture was implemented. Only in microservices fixing these boundaries is much more difficult than in a single codebase.

> "just use a monolith for everything" falls apart pretty quickly at larger team sizes.

Absolutely! Don't put everything in a single monolith, develop several mediumliths with lower requirements for coupling code together, but keeping it small enough so that upgrades are bearable.

I'm a fan of libraries, not modules, for hard API boundaries. A library, developed and compiled separately and published with versioning, gives you a lot of the clean separation of services without the networking and system overhead. Dependencies should always point from the app to the library as much as possible, so the library should bring it's own dependencies instead of trying to reuse the app's framework/libraries.
Libraries sort of help but not really. In the end, if the main app is on Python 3.10, all libraries it uses must be capable of running on Python 3.10. And if you want to upgrade the app to 3.11, first you have to upgrade all libraries to support 3.11 (in addition to 3.10, since you'll likely have to do it piecemeal and not a single big-bang).

This is to say nothing of the classic dependency hell[0] where the main app depends on library X and Y, but library X depends on Z==1.0.0 and library Y depends on Z==2.0.0. At which point you have to do some hacky stuff like JAR shading (which has its own problems, see log4shell) or vendoring the dependency under a new namespace.

For a lot of use cases, specifically at larger orgs and where highly optimized performance isn't a big priority, the networking and operational overhead is a small price to pay for decoupling.

[0] https://en.wikipedia.org/wiki/Dependency_hell

Python and any other popular language will try hard to stay backward compatible, so that shouldn't be a problem. I have encountered in the other direction where a library wants to use new language features but the app's runtime doesn't support it yet. That can be considered a downside.
I’ve tried this but did not find it worthwhile in practice. Either you end up running multiple versions of the same library, which sucks terribly unless your library doesn’t have side effects, or you end up doing a huge versioning dance at every change for no benefit
You say that like it’s a fact but Facebook has a humongous monolith and it works fine with tens of thousands of engineers working on it at the same time
These blanket statements on Hackernews are so frustrating to read. Every one of these articles is bait for these type of comments. The comments fill up with people saying microservices suck, then it fills up with comments saying those comments suck.

Please understand that every environment, company, and project is different.

After years of working with various microservice-based systems, I got the impression that the whole idea of "microservices" means ignoring various nuances of particular products and organizations and just splitting your system in a pinky-sized codebases and services.

You are completely right, every project is different, and that's why the general idea of microservices is bad. Split your services where there are technical or heavy political and organizational reasons to do so, but don't go for splitting as your default solution.

Your code structure should match your org chart is the best advice I've seen for splitting code. Each team in the org maintains their own micro service. They do whatever they want within it, but when going to a different one they go to an interface. It isn't perfect, but it seems to work the best.
There are interfaces besides RPCs
Until the org chart is reorganized, then what?
Then you reorg the system. Note that this can go either direction - you can also change your system to how you want the org chart to look. Generally it goes one way because engineers rarely have the power to change the org chart, but sometimes we are consulted and can suggest 'improvements'.
Org charts tend to change faster than services can possibly be re-architected in a large scale system that is growing quickly. Honestly you need a critical mass of engineers who can think end-to-end with a product and business-first mentality, they should decide what tradeoffs make the most sense taking into account a broad range of hypothetical future requirements and what makes sense given current domain knowledge. They must do this with real expertise and ownership, not basing it purely on a 3-year roadmap from non-technical PM. Then teams should be organized around the design of these systems (not the other way around). This overall process should be repeated iteratively as the product and business scales.
> Your code structure should match your org chart is the best advice I've seen for splitting code.

I've seen that so often it now feels like a sarcastic meme to me.

The org structure changes much faster than your code structure does. Good luck getting those two to stay in sync longer than the CTO stays in their role.

> Please understand that every environment, company, and project is different.

No doubt, but my point is there is a unifying metric that we can use to evaluate the effectiveness of these environments, Percentage of time spent on the environment itself versus on user needs. I think that number is too high for any system that is overly-decomposed.

> modularise the code

You mean…

spend more time drawing boxes and fantasising about what tech would be 'just-perfect' for that particular box?

Won’t that mean the connections between your modules start to become more important than the modules, and the work to maintain this system would only really be justifiable if the modules can be worked on in parallel?

It means the interfaces become important and you can work on the internals in parallel.
Just like in a microfrontend or microservice architecture
A function boundary in a compiler is a lot easier to work with than a network boundary for a service in another repo in another language on another kernel. Those false equivalencies are what drive the cost.
Interfaces are hard. If you can avoid doing them that is a good thing (that is the interface is whatever someone who writes both sides of it wants it to be, and it changes as that person feels free). However on large projects you cannot do that, you can try but eventually some interface is used by so much that changes becomes difficult just because of the other code you need to change. (additions are easy, but if you want to change something like the arguments to an existing function that is hard just because of all the users who need to change)
Version your API, and talk to your consumers before building it so you can design an API that meets their needs. Run a pilot with at least two consumers before even announcing it.
Those are good best practices, but they don't solve the problem. If nothing else you end up supporting a V1 API that is now very unlike how you want people to use your system.

Often the pain of supporting this is so high you will just refuse to ask if the API can be improved despite the pain of the bad API.

Hmm I wouldn't say it never happens we are building a large system (in cybersec space) and there is like a dozen + teams that are delivering their respective frontend functionality as microfrontends. The experience has being fairly reasonable so far. Very likely because each team's app is fairly isolated.
Microfrontend was such an obviously dumb idea. It's just a pretty name for tech debt.
> So let’s say our frontend app is a hairball that’s full of interdependencies. How do we break that link? I think engineers - and managers! - are so excited about the prospect of escaping the monolith, they forget about the intermediary stage of actually chopping up the hairball.

Absolutely this, true in both the back and front ends. The first step to breaking apart any monolith is the extremely boring refactoring process. People want to skip over this because it's not the sexy cool part where you're using Kubernetes and lambdas or whatever other tech will look great on your resume. But I'll say that every monolith->microservice (or MFE) move that I've seen, whether or not it was successful was entirely determined by if the upfront refactoring work was done.

I am always frowned upon when I describe our product as a monolith with network hops. These just add more network hops, complexity, latency and projects to upgrade every 30 seconds.
thankfully the network never fails, is fully synchronous, and doesn't require any configuration
My persuasion is opposite. As software development gets easier we should expect the pendulum to swing back to custom apps that are fit for purpose, and those have a natural gravity towards this style of architecture.
I think there's more fruitful discussions to be had, e.g. which editor is to be preferred or which programming language is best.
Spaces are superior over tabs
Years ago, long BC, I was at a tech conference and the CTO of a local tech giant gave a talk on micro services that was very good and touched on some of these same points. They, in fact, refactored in the monolith and then broke it out into micro services but, surprisingly, never shipped the refactored monolith ... they just kept it running full test suites as more and more of its features were carved off into micro services until the test suites were running entirely on the micro services. They shipped that.

During the Q&A somebody asked a question about their company's struggle to move their monolith to micro services and the CTO asked two questions that, at the time, was very illuminating: how many teams did they have and how many developers were in their tooling team. When they said they had a relatively small team the CTO said "you don't have any of the problems micro services solve, why are you switching".

I worked at a place that added micro frontends and it made an already horrible app and stack an order of magnitude harder to work on.

Avoid unless you know you reallllly need them.

> Microfrontends are very popular on the conference circuit, so I am probably about to make future job interviews awkward by criticisng them.

This has been my experience with conferences lately: Way too much emphasis on the next big trend, to the point of being counterproductive for actually getting work done

Certain teams and companies live and die by conference trends. If you can't also show interest in those trends, they don't want you.

I was asked to review hiring practices for the front-end team at a company I worked for a couple years back. They had a long list of questions about the latest web technologies and frameworks that they used to screen candidates. I was puzzled because we didn't use many of the technologies they listed. Several of them weren't even stabilized standards that could be used in production. The team lead explained that knowing about them was his primary signal for someone's overall competence.

They hired a lot of "smart" developers, but they also took forever to ship anything. They were always trying to do things like micro front-ends, rewrite part of the app in the latest framework, experiment with new web technologies that were too immature to ship, and other things that weren't really related to getting product out the door.

> The team lead explained that knowing about them was his primary signal for someone's overall competence.

God help us.

> God help us.

Good luck, I think God is too busy refactoring his Perl code.

I think we both know it’s all lisp.
The worst thing about configuring emacs is when you accidentally create a pocket universe and now you have to keep that process running.
> "Truly, this was the language from which the Gods wrought the universe."

> "I mean, ostensibly, yes. Honestly, we hacked most of it together with Perl."

Does God write in Perl 5 or 6?
Black holes look like million dollar mistakes so probably something else, but the rest keeps working so probably not a monolith.
I feel like buzzword bingo in conferences is unavoidable.

The three easiest ways to get someone's attention in a title are: being a well known speaker, talking about a giant project, or talking about a trend.

As much as there is value in "tricks to avoid false negatives during CI" it just isn't as catchy.

> knowing about them was his primary signal for someone's overall competence

I don't know if it's the primary signal, but I think you need a balanced team. It's a good idea to have at least one person on your team who's staying on top of what's going on in the front-end community. But you have to be careful that person isn't blindly trying to apply every trend in your product, e.g. resume driven development.

This is a double edged sword unless you plan to allow them room to experiment. If all the work is in older technologies with no short term or middle term plan to upgrade, you will be hiring people who aren't going to be satisfied with the day to day duties and looking to change teams to a team who is using new things or leave. I think teams being honest and self critical about what their actual needs and day to day operations include is an important part of figuring out what skill sets should be on the team. Too much optimism leads to constant turn over.
> you will be hiring people who aren't going to be satisfied with the day to day duties and looking to change teams to a team who is using new things or leave

I don't know about this. I've been able to convince several developers to put down their shiny in favor of trying out some classic options. They seem to enjoy their newly-discovered traction. Progress feels good regardless of how you're achieving it after a while.

I did have to provide starting points & patterns, but it didn't seem to take much. I think they key is proving the value around why the old tools are (likely) better. Just lecturing a young person verbally about this and that is almost certain to send them even deeper into their rabbit hole.

If the mission is vague with uncertain upside associated with completion, you will absolutely find everyone fucking off in different directions as convenient. If you somehow frame the mission more like "ship by Christmas and everyone gets a 50k bonus", you can usually convince even the biggest 'not my job' assholes to adapt to changing realities.

Leadership is at the heart of why some companies are simple and others are running a technological clown show.

> you will be hiring people who aren't going to be satisfied with the day to day duties and looking to change teams to a team who is using new things or leave

Awesome. There are plenty of programmers who aren’t magpies distracted by shiny trinkets. I hope they get jobs. They can take the seats of those people who can’t bear not wasting time on the next new fad.

> It's a good idea to have at least one person on your team who's staying on top of what's going on in the front-end community.

Keep your friends close and your enemies closer.

I don't blame conferences for that. Conferences should (often) be a good place for more out there ideas, more experiments, experience sharing with new ideas, etc. It's the fault of viewers for thinking "I'm gonna do this thing without really evaluating it for my use case", which is a generally large problem in tech.
I think certain companies / people tend to dominate conference topics.

Most developers / teams / companies are just working rather than doing conferences. There's a whole world of development that is sort of opaque / assumed to be backwards.

I would argue that you should do the opposite.

Ask, "Pick a popular buzzword that you think is often a bad idea. Name it, explain what it was, explain why people like it, then explain why it is often a bad idea."

If they hesitate, reassure them, "It will be fine even if I disagree with you. I just want to see that you can think for yourself."

> This has been my experience with conferences lately: Way too much emphasis on the next big trend, to the point of being counterproductive for actually getting work done

I've been going to tech conferences for 25 years. This isn't a new new trend. :-)

>They hired a lot of "smart" developers, but they also took forever to ship anything.

Oh man does this resonate with me. Some of the "smartest" people we've hired have also been the slowest to deliver as they waffle and perfect and theorize and play with the tasks they have.

But then their playtime projects may turn into your next big product :)
That's something I didn't get for a long time

There is a difference between being smart and effective

I love the word effective and use it all the time.

It almost immediately gets rid of a lot of idealism.

Yep, more and more I think of the engineers I want on my team as "product engineers" over software engineers.

Overengineering is the devil

My go-to line is "I don't like working with geniuses, they're idiots."

Of course I don't actually think that, but there does seem to be a kind of parochial navel-gazing that comes with the high intellect territory, and in tech that manifests itself in absurdly over-engineered solutions.

Disclosure that I'm closer to full stack/generalist than frontend engineer.

Have you tried not going to conferences? I'm saying that with a good bit of sarcasm, but frankly look at where a lot of these things occur and who speaks at them. They occur in huge cities that curiously have beaucoup tech companies; companies that we know incentivize promotion based on things like "personal brand" and new project development as opposed to impact. Companies that often time give lots of money to those same conferences.

My point here is that conferences today are inherently inorganic and you'd get a lot more value reading long form blogs and going to meet ups to talk to people about the curious problems they have.

Also, those sexy companies want you to use the hot new thing because they’re selling the pickaxes. AWS sponsor a lot of educational platforms and conferences on cloud for a reason, for example.
> lately

always has been dot jpeg

I remember GlueCon 2012, just wall-to-wall NoSQL hype, with a dash of microservices on top. Anyone who ran home and implemented stuff from those talks was absolutely wasting their time (me included).

I see orgs trying to use micro-things to solve problems caused by a lack of high-level direction, architecture, design and organization.

The problem is, micro-things require better high-level direction, to avoid becoming a tangle of poorly integrated, poorly performing, expensive things.

If end users can tell you're using micro-frontends, you've done it wrong. If you need 20 people in 10 meetings to change your app's chrome, you've done it wrong. If you don't know how and why these problems won't crop up for you before you've gotten started, you're going to be doing it wrong.

You need a strong architecture group, and the buy-in of the micro-thing implementors to take responsibility for their place in the whole to pull off.

FWIW, these architectures tend to follow the org or business entities (there must be a catch name for that phenomenon).

Solving a balkanized, poorly integrated services often goes through restructuring the business teams and realign them under a single umbrella. I see it as the poster child for "solving technical problems through social solutions"

Micro frontends are mostly trying to solve organizational issues, from what I’ve seen. You have some teams or individuals who really want to use a different tech for their project, or get away from legacy code without rewriting it, etc.

I interviewed at a place a couple months ago that was looking for an front end architect, and all the assumptions and questioning were that their use of microfrontends (both angular and react) was a good thing and how would I make teams follow this approach.

They passed on me when I made it clear that I didn’t think it was a very good approach for their smallish team, and in general that the challenges they were experiencing were mostly because of this architecture, not solved by it.

I think it's less about the technology than the organizational structure. If you have more than one monolith (aka any company with an acquisition) you either have to have it in code in two places (gross) or as a library. If you have it as a library, then you have N version bumps to do an N pipelines to deploy. Not hard technically, but tons of overhead.

This means that you lose independence and doing A/B testing becomes very difficult when you can't really control what the user is seeing because the version is pinned.

A micro front end allows you to deploy independently, test independently, and truly own your code. Network hops are reasonably cheap for most consumer applications and collaboration on a shared component is very expensive.

I'm speaking from the perspective of a checkout flow, which my company is actively ripping out from the monolith in order to ensure people outside the monolith can use it AND to ensure we're able to do the price testing/conversion rate testing at a level that doesn't need a separate suite of tools for each business unit. This also has the benefit of reducing integration points with the billing system leading to better standardization and consolidated data in one billing system.

I have designed and built something that could be described as a microfrontend system (though it's much more restrictive than "do what you like within this part of the page") and though it's been pretty successful I agree totally with the article. It's a lot of complexity if it isn't definitely worth it. Our "microfrontends" are really dynamically-loaded JavaScript modules of a particular type. They conform to one of a small handful of well-defined extension points, including defining UI (in React components, as it happens, but clearly this isn't React-specific). In this way engineers stay more or less on the golden path, and we can do some runtime checks to try and give better error messages. I think if we'd built something more general it would have been a mistake.
I’ve worked on two 100+ weekly committer monoliths and two similar sized MFE architectures. I think the article hits good points though I’d add some acutely painful ones it misses[1]. I’m someone who is by gut now squarely in the pro-monolith camp, but I think that in the comment thread of a similarity anti-MFE article it’s worth steel manning the pro-MFE arguments rather than characterize it simplistically as cargo-culting or resume-boosting.

First, MFEs solve organizational issues by cheaply offering release independence. An example is when teams that do not overlap in working hours. Triaging and resolving binary release blockers is hard to do correctly and onerous on oncall WLB. Another example is when new products want to move quickly without triggering global binary rollbacks or forcing too fast a release cadence for mature products with lower tolerance for outages or older test pyramids.

Second, MFEs are a pragmatic choice because they can proceed independently from the mono/microrepo decision and any modularization investment, both of which are more costly by several multiples in the cases I've seen. Most infra teams are not ivory towers and MFEs are high bang-for-buck.

Finally, MFEs are a tool to solve fundamental scaling issues with continuous development. At a certain level of commits, race conditions cause bugs or build breakages or test failures, and flaky tests cause inability to (cheaply) certify last known good commit at cut time. You can greatly push out both of these scaling limits with good feature flag/health-mediated releases and mature CI, but having an additional tool in the kit allows you to pick which to invest in based on ROI.

Advocating for modularity is nice but I've never met an MFE advocate who didn't also want a more tree-shakeable modular codebase. We should not jump to the conclusion the MFE as bad or a "last resort" because there exists another solution that better solves an partially overlapping set of problems, especially if the other solution doesn't solve many problems that MFEs do or requires significant more work to solve them.

[1] Runtime JS isolation (e.g. of globals set by third party libraries) is hard and existing methods are leaky abstractions like module federation or require significant infra work like iframing with DOM shims. CSS encapsulation is very hard on complex systems, and workarounds like shadow DOM have a11y and library/tooling interop issues. Runtime state sharing (so not every MFE makes its own fetch/subscriptions for common data) is hard and prone to binary skew bugs. Runtime dynamic linking of shared common code is hard to reason around and static linking of common code can result in the same transition of a lazy loaded module to go from taking 10kB to 1MB+ over the wire.

I agree with a lot of this - MFE are much harder to pull off than the backend services, and I have yet to see a successful solution based on how they are often presented at the bleeding edge. We have had moderate success with pretty rudimentary implementations (think: iframes) but it is definitely not pain free. I'd highly recommend you look for this sort of architecture to STOP contributing to the monolith before you look to fix it, which I think aligns with the author's recommendation to get your sh!t in order before you distribute your monolith, which will be a Vietnam for your team.
I think microfrontends are the ultimate extension of what I call "the myth of code reuse".

Everyone thinks because they can create "small reusable slices" of full frontend code that this comes for free without a load of problems that get in the way of the mythical land. The only issue is everyone who has tried microfrontends is universally full of regret.

Other attempts at this are:

1) having an enforced centralised library of components (this just about works) - how this is managed and the engagement with other teams is critical.

2) turn everything into an npm package and create version hell at the end of a sprint as hundreds of devs try to version bump everything and the main package.json all at the same time.

3) free for all with moving people regularly between teams. This is the best solution because best practices automatically filter their way through each team through the people and everyone learns and gets on with each other in a human way that allows real collaboration.

4) splitting vertically rather than by components so one team does the search UI another does the homepage another does the product detail etc. but hopefully in the same technology!

Or you could probably just reduce the number of people adding pointless features to your ecommerce site... Ah there is five of you and you did microfrontends didn't you, I can't and won't help you then :-/

Microfrontends are about independent development, not code reuse. They work fine if you understand their purpose.
I was on an MFE team earlier this year. It was sold to higher-ups as being for both, but I think in most cases it's bad for both. IME, it was sold in terms of code code-reuse by providing things like shared navigation bars, shared authentication logic, etc.

My team, at least, did not have the necessary support structures in place to help others who wanted to maintain their own UI. I see this mostly when crossing framework/language boundaries (mixing React + Angular in a SPA, as it was in my case). They declare microfrontends, but then all the component libraries were all React-based anyways.

It just ended up being a mess of N deployment processes, N build systems, N storage buckets, zero standardization whatsoever, and mountains of technical debt, all without much benefit.

...but if you're all working in the same language/framework where that component/style-lock-in is acceptable, why would someone use a microfrontend to begin with? Can the organization not set up a single repository with different teams contributing to it? One deployment, one build system, one storage bucket, and standardization?

IMO CODEOWNERS is the original and best "microfrontend" solution for small-to-medium-sized teams working on a single product. If you have hundreds or thousands of engineers (think FAANG) working on a single experience that just HAS to be a SPA, then maybe you have the resources to build out those support structures and actually get MFEs to work on an organizational level.

In the vast majority of cases, however, I see it as a bandaid on an organizational problem that's eaten up because it's an interesting technical challenge for senior engineers to think about (someone made a great comment about "drawing the perfect box"), and because management thinks it's a cool trend with benefits they can grok.

(comment deleted)
In that sense, when the UI is a browser client UI, I'm immediately suspicious of such isolation plans.

When you're building server architectures, it's fine... You have more storage than every book ever published in the 1800s on each machine you're deploying to, you can afford to have microservice A depend on library set Q and microservice B depend on library set R and as long as the public-facing contract doesn't change, nobody cares. Your deployment infrastructure does something to get all those dependencies in place (possibly even something hugely inefficient) and you're happy.

Efficiency of deployment still matters for the client. It is not okay to be shipping four different date libraries because your client is an MFE and the different departments in your company can't agree on what core library to use. That scales in the reverse direction: you're paying for bandwidth (and your users for time waiting for your site to load) per user. It's waste you can feel.

Yes, I agree. Microfrontends can be very useful if a small team needs an app quickly the same day, but can't wait for 2 years for the central IT department to deliver the tool.
How many times per second do you think awk, grep, sed, et al are being used right now?

Composable tools exist. Whatever horseshit is going on around ANY bigger sized application is not. Excel, any random React app, GIMP… sure, compositional engineer might be taking place WITHIN the application, but it is barely composable beyond a Copy, Paste, Save As dialog and the ability to arrange the window with other windows.

Can’t you see how things immediately invert and turn inwards, away from interaction, away from composability, the moment the turn towards structured interfaces begins?

An API is a narcissist. You have to live in its world. A Unix pipe is a communist.

Think, aggregate vs combined in terms of the GPL… pipes vs APIs…

"Microfrontends" is a new term for me. Are there specific frameworks that embody the concept (and if so, where on GitHub would I look)? Is it more of a broad architectural pattern?
It’s not really a framework. I mean that’s the whole point of not being so tightly knit.

Imagine you have a website with some kind of router for different paths. You might also have a unique domain per market (e.g. amazon.co.uk or amazon.jp)

/ -> home page repo

/search -> search repo

/products/xyz -> products repo

/products/xyz/review -> product review repo

It might seem crazy to have so many repos, but each of these pages already imports so many different components from different teams, and separating them is an easy way to make sure you don’t accidentally separate something else.

You could use Gatsby to prebuild all the products pages when there’s a change in the CMS and serve them on S3, and you could use a Next.js project to handle the /search page. You could use Vue to do the reviews page, or just have a normal create react app SPA. It gives you flexibility to experiment and lets teams not stop all over each ofher.

If your build step results in 20 * 300 product pages, then you’ll be glad to not have other stuff in that repo.

Of course you could accomplish this in a monorepo, but I’m just using project & repo to mean the same thing (a micro frontend)

It gets easier to A/B test and you could deploy a different site version for different markets (e.g rollout a new search result layout in Ireland and see if there’s a difference in click through rates). It’s just easier to deploy a MFE to serve that route in that market and have the old MFE still deploy to other markets.

Thanks, that's helpful.

Amazon famously built the company with OBIDOS, a monolith; these days, backend microservices abound — as do what we’re calling here microfrontends, although my understanding is at AMZN they are granular not just to market-specific domains or route prefixes, but sometimes also to pre-defined sections of a final rendered page. Would love to hear from AMZN engineers that work on such things.

Personally, I wouldn't call it a "last resort", but I definitely agree that keeping a functioning monolith is preferred.

Nevertheless, one thing to keep in mind (and I do consulting on MF for the last 5 years) is that most projects / teams are not well prepared and actually not at all suited for MF. MF solutions are usually just done from a technology POV, which is already a problem. Next thing is that the used technologies are often also not well suited. People tend to use strongly coupled things that just create hidden monoliths. In the end projects fail often because either the organization is not ready to have truly independent teams or / and because the software has just become too complex and unmaintainable.

To end with something positive: We also know many success stories in that area where people spent the right amount of research on what technologies to use and where everyone in the organization was prepared to accept the new teams setup.

We’re about to embark on the MFE journey and I’m concerned about pulling it off in a way that will have justified the effort. Our motivations are pure, we have many feature teams, we’re driving toward team independence, already breaking up the monolith into Microservices, etc. But on the FE we have the standard requirement to maintain eventual (definition tbd) UI consistency and so intend to continue to maintain a large number of build-time dependencies between MFEs and shared libraries. So I’m not sure exactly how to pull this off.

Are any of these “many success stories” talked about online? Case studies we can get pumped on?

This gets you most of the advantages of a microfrontend:

1) Monorepo with multiple workspaces

2) With several separate independently deployed applications, each maintained by a separate team

3) That share a set of common packages for common stuff (auth, etc) with full typescript definitions

4) Add CI to typecheck if any shared package changes types you get errors

5) Preferably with the packages being able to be independently run for development (something like storybook, although I don't recommend it)

6) Preferably with the packages being kept small, lean, with limited number of external dependencies (ie, settle on the cross-team deps to use, so framework, routing, data-fetching, etc)

7) Some kind of pre-commit git hook or CI script to validate a set of core shared dependencies used by packages are kept in sync (ie, everyone is running the EXACT SAME React version). I use this one: https://gist.github.com/DanielHoffmann/a456aadb2f27880d59241...

8) Shared build configuration and tools, all apps are validated, built and bundled by the same code.

9) NO PACKAGE PUBLISHING/VERSIONING, all dependencies are workspace:*

For example:

  folder-structure:
  /apps/{team1-app-name}/
  /apps/{team2-app-name}/
  /packages/auth/
  /packages/some-util-lib/

  /package.json
  "scripts": (test, lint, format, typecheck all done at the top level package.json)
  "workspaces": [
    "apps/*",
    "packages/*",
  ],

  /packages/auth/package.json
  "scripts": (dev to run in development mode)
  "devDependencies": { "some-util-lib": "workspace:*", "react": "^18.0.0" }
  "peerDependencies": { "some-util-lib": "*", "react": "*" }

  /apps/{team1-app-name}/package.json
  "scripts": (dev to run in development mode, build for production builds)
  "dependencies": {
     "auth": "workspace:*"
     "some-util-lib": "workspace:*"
  }

This doesn't give you 100% of the independence of microfrontends, but it does give you quite a lot of bang for your buck. Depending how much independence or reuse you want you might want more or less shared external dependencies (for example your shared packages could be framework agnostic and just use raw JS)

The build/bundling configuration can set up separate chunks for the core set of shared dependencies (react, router, etc) to improve build times, load speeds and caching*

First off, I appreciate the thoughtful write-up, under different circumstances this is the direction I’d probably be heading. However our web Frontend code is all currently in a large-ish (500 packages, 100 apps) monorepo and we’re actively pursuing breaking that up into a hybrid repo model, largely in the interest of true team autonomy. We want our code organization to better reflect our Eng org structure and to establish much stronger lines of ownership and responsibility. Obviously we see other compelling reasons to take this big step, but there’s also a lot of risk involved, particularly around dependency management and figuring out how to accomplish eventual UI consistency across our web apps, all of which will use a large number of shared libraries/components that will be broadly organized into a handful of repos (likely monorepos) representing domains and owned by different teams. The intent is for this evolution to culminate in a microfrontends architecture as a way to support collaboration across autonomous teams without the need for built-time coupling.
Fair enough, probably far bigger scale than I am used to. But I wonder why move away from a monorepo? Publishing and versioning common packages is a huge pain in the ass, especially for JS projects where you need transpiling, sourcemaps, etc.

Some smart branch management so teams can work independently seems better for me. For example each project gets their own production branch and development branches to trigger deployments and can pull changes from master as they see fit.

If you are planning on these shared components and dependencies be versioned I highly advise against that, the permutation of versions of underlying common libraries (like React) can make an incompatible versioning hell where component X works on React ^16.0.0 but in practice was tested in React ^18.0.0 only. In my own project I explicitly force all shared dependencies (which I try to keep to a minimum) to be on the same version.

> without the need for built-time coupling

There are two ways of having build-time coupling:

1) Shared build/bundling code, configuration and tools

2) Single build/bundling for all the code

You can most definitely have independent projects sharing the same build/bundling code, configuration and tools while every project is built separately and independently. This can make it hard to integrate with solutions that rely on taking over your bundling though.

Most of the implementations of MFEs I've seen are reliant on webpack or Single-SPA (which by default uses webpack under the hood).

vite, esbuild, parcel etc. have not adopted anything around this.

To me, that says that those putting out the nuts and bolts work that having been leading this space for several years either haven't spent alot of time evaluating them, or have found them overly complex for what they are, or perhaps think there is a better way to accomplish their goals.

I'm not sure MFEs are the best tech, to be honest. I've seen demos where it seems to be an addition (bootstrapping speed, neat tricks with routing etc.) but I've never seen them demonstrated in practice. I'm on a team now that is adopting MFEs and our payload is somehow considered acceptable at 8 MB. Given this is a behind-the-login app, I think somewhere between 300-500KB bootstrapping and getting to interactive with the rest lazy loaded is fine, but 8 MB to boot the app seems like we aren't doing even basic optimizations (I unfortunately do not have the control I wish I had on this)

I'm really unsure about MFEs, they seem like something looking for a problem in practice. They certainly appear hard to get right

The examples that are publicly available and written about, are in my opinion all suffering from a too low level of abstraction. They are more tech demos of possible implementation options, for such an architecture, but as they are all contrived to demonstrate some mechanism, but the not a single of the examples would be actually justify that kind of architecture.

I am working on a MFE shell application for a product (or rather a suite of closely related applications/products), that need to be presented to the users as a single system. Ballpark figure of the business unit 400+ software developers and 80+ modules/sub-products.

I think the MFE architecture was a justified trade-off, given our organizational structure and product landscape, but one should be very cautious if it is presented as a some kind of default solution.

That is what I think MFE is meant for, where you have entirely different parts of an organization working on an application but you need it to feel the same to the user.

That feels right.

Another I've been apart of is applying it to a given codebase post acquisition, helps speed up integration in some respects

One example I've seen floated though is remote modules for design systems. This one I'm unsure about. I can only speak from one experience when this was tried and it was a disappointing result.

Víte has a Module Federation plugin that's interoperable with webpack with some effort

And according to some folks on Vite conf it will be soon supported natively

I would rather see articles about "How to do Microfrontends right" rather than all these "X sucks" articles.
There's a million of those. Certainly, having a few dissidents is _expected behaviour_.
This is mostly skill issues.

There's not much magic or difficulty with MFE.

It's the same as when you break your program into multiple libraries, and you just do it all the time.

The moment you do npm install, pip install, cargo install,... you're basically doing the Micro-program already.

Micro anything is only useful if your company is big and has a lot of separate departments. It solves a real organizational issues.

If your company is small, don't bother with any of these micro trends. The overhead of micro architecture is non-trivial: telemetry, tracing, test infra, build infra, non-prod environment setup, etc.

Isn’t a “micro front-end” just like a Turbo Frame in Rails now? Except, easier to manage within a monolith?
The microfrontends that OP is referring to are generally standalone single-page apps which sit underneath some kind of top-level router that loads the correct MFE as needed. Often these are split up by functional area or product at a company with multiple products.
Microfrontends are so nice because you get to experiment with different tools more frequently with less risk.
Microfrontends require modularized behaviors with zero cross grained abstractions.

It’s often referred to as Packaged Business Capabilities.

The MFE is an adapter pattern that hosts discrete modules deployed from their own repositories and configuration should be automatically integrated.

But as the OP states, there are many ways to do this badly. A strict non-abstraction discipline is required. No shared utility libraries between modules.