36 comments

[ 4.1 ms ] story [ 90.0 ms ] thread
Why does the example use different domains in the base URLs? Does the app do hard navigation between those?
It looks like the code is running in iframes, so yes it would do hard navigation, but it would not change the domain the user sees.
(comment deleted)
We've using iframe to extend legacy apps for at least 10 years. And I don't think this approach that needs rewrite the of the base router really brings a benefit. Very often is really problematic to change the base router.
There are two types of engineering. Additive and subtractive. All software problems can be solved with either:

1. Some abstraction. 2. Replacing the existing "thing" with a new one that had more functionality.

Building layers of abstraction is typically safer and easier, but the abstractions aren't free. There's a really performance and completely tax to using the additive approach. Just take a look at the Win32 API. So many calls are slow AF and just reading a file off the disk in Windows requires 1000s of syscalls and confext switches- because of too much "safe" abstractions built over the years.

Compare this to Apple's engineering strategy, where they often deprecate and replace an APIs. This is obviously more abusive to the developers, and the users, but arguably better for the long term stability and performance of the system.

> Just take a look at the Win32 API. So many calls are slow AF and just reading a file off the disk in Windows requires 1000s of syscalls and confext switches- because of too much "safe" abstractions built over the years.

Windows, like any big system, has problems, but not this one. Its FS is slow, but not for this reason.

What's the reason? Genuinely curious.
sometimes i wonder why does explorer listing 100k files in a path can take minutes.

And searching the whole disk for a partial filename? tens of minutes.

I can do both in a database on the same machine in seconds...

You might like Voidtools Everything, a free tool that does partial filename searches in milliseconds. It's incredibly useful for finding files.

https://www.voidtools.com/

At least part of the reason is flexibility. For example Windows has the File System Filter Driver system [0] which allows you to execute arbitrary code to observe, modify or prevent any (filesystem) I/O action. That's for example how a virus scanner can scan any file before it's opened (and of course any Windows system nowadays has a virus scanner running, even if "only" Windows defender. But you can have any number of such modules running (for logging, encryption, backup, etc), each being called for every file access.

Another problem is that the Windows Api is designed differently from the Linux Api. Windows is optimized for network drives, Linux more for local drives. Software designed for Linux often hits access patterns that don't perform well in Windows.

0: https://docs.microsoft.com/en-us/windows-hardware/drivers/if...

Incremental vs disruptive innovation

Disruptive has a distribution problem - how do you get people to use it

Vertical integration can be "10x better" and if you meet that threshold, maybe people adopt it, like iphones

Or maybe you have existing distribution networks or power to get people to act

Right, and ensure you never can fix anything and hire generations of people who slave over the old crappola until they give up. Meanwhile you wind up with legacy code from multiple languages/language versions all mixed up like a junkyard sculpture.

I worked at a major travel company (you know the brand) that ignored its legacy web+backend for almost 10 years until our parent company basically gave us away to our biggest competitor (the tech was all abandoned as unusable) who made us just a marketing brand (also 100% of people laid off in the process). We couldn't keep up with our competitors as everything was impossible to fix any more. On the other hand the mobile team I worked with replaced everything and we were extremely agile in competing (other than being limited by the crappy back end).

It's not always a good idea to replace everything, but it's also not a good idea to live with shit either.

My thoughts (as someone who worked at a brand of the same parent travel company as you): It is definitely NOT a good idea to live with shit as it will kill your velocity long term, so the question is how to replace it? Every single "big bang" replacement I've done, while not exactly a total failure, was extremely painful. If a tool like this made it easier to piecemeal replace your legacy code, while showing business value more incrementally, I'd be all for it.

I agree leaving your house in this "junkyard sculpture" state indefinitely (love that analogy) will eventually kill your business.

> Every single "big bang" replacement I've done, while not exactly a total failure, was extremely painful.

The bigger question might be how much more painful was it than continuing to try to be competitive (react with new functionality, deliver ongoing value, etc) in the previous codebase, and how much more painful over trying to plan out small incremental refactoring changes during the same time? And... after a certain time period of going through that pain, was the end result quantifiably more useful (testable, fewer bugs, faster, easier to grok/extend/etc - choose your metrics) than if that big change wasn't undertaken?

I think the problem here is that we often ask the questions too late. Things went wrong a very long time ago. A rewrite is declaring bankruptcy, but often the same actors barely change their behavior and you end up in the exact same spot again.

I’m starting to fear that the right response, especially considering the Big Picture, is to let it die. Let some other competitor with fresh ideas eat your lunch. I suspect these problems are symptoms of a deeper, terminal illness and palliative care is the best you can do.

I agree. I've worked at a company where the plan to migrate from a legacy system to the green architecture was planned to take a decade. With large systems, you will always be in a state of flux. It's simply impossible to replace the entire system in one swoop. Libraries like this acknowledge the incremental nature of accepting a migration path over time.
I had an experience like this early in my career and for a very long time I fought to avoid this by insisting that there is a world of difference between learning to work faster (through craft and mastery) versus faking it. You see this in sports, where one team is ahead and loses in the final minutes because they have ground themselves down. The other team wins on stamina.

But the number of people who want to hear this is depressingly low. It’s more common in younger people, but they have no clout, so I get mentees easily enough, but they take a long time to become allies.

The places I look back on fondly, I had a boss who agreed, but often their skip level boss was having none of it, so the work was still... well, work.

I've been prototyping this approach recently -- I think you can go simpler / leaner yet.

The iframe angle is probably the most universal, and easiest way to include legacy apps / sites. It does present challenges with authentication, as cookies cannot be persisted by a framed context. Local storage still works, but that requires some changes in the legacy apps.

As far as the "orchestrator" goes, I don't see the point of using a nearly-legacy framework (yes, a jab at Angular) when this can be done in plain vanilla JS with postMessage. Some balk at using events, but in this context messaging between clients could be a light, elegant solution to the communication / synchronization problem.

Finally -- this is bound to fail in actual real-world applications, because legacy apps are very likely to include everything and the kitchen sink, and simply wrapping them in frames doesn't solve the problem of a bloated do-everything spaghetti monster.

As an architectural approach for developing new, modular front-end solutions, this is promising. Multiple small teams responsible for small, single-purpose apps, stack-agnostic in aggregate -- this way of handling scale could reduce the overall complexity, making development and maintenance a little easier.

This feels like as a solution to the problem that does not exist. This just increases the complexity and makes the interface horribly fragmented and hard to develop for after a while.
> This feels like as a solution to the problem that does not exist.

While I'm not sure this is the right solution, the problem absolutely does exist. There are loads of companies that have to deal with extremely shitty, brittle front ends that are confronted with a difficult "scrap the whole thing and rebuild it" vs. "incremental improvements" challenge.

If this tool is used appropriately as a way to piecemeal replace parts of your website, then I think it could be very useful. While I love deleting old crappy technology as much as any other developer, I've seen more than my fair share of "big bang" replacements fail miserably and result in huge team burnout and reduced trust between the business and technology sides of a company. On the other hand, I would only support this tool if the end game was indeed getting rid of all the crappy old stuff. Living in a world with umpteen different languages and ways of doing things on the front end is a recipe for extremely low productivity.

Thus, like most tools, something like this can easily be misused but there is certainly a place for it if used appropriately.

The problem this solves is having different teams in the same company perfectly happily developing away on their own stacks when a random business requirement needs that they get their components in the same browser window such that neither team is tied to the other's deployment cadence.
Having worked at multiple engineering organizations, I could see how some people might question the value of this. For example, A big N company I worked at went all in on React. Top down, no ifs-ands-or-buts about it. I'm biased and like React, so I didn't mind the decision. Today, I'm in an engineering organization where we have teams using React, Vue, and Angular, with no foreseeable convergence on one. Each team feels most productive in its preferred stack. A solution like this allows us to at least ship our code together, instead of having everyone maintain CI/CD on top of their application code. It buys us additional developer productivity. We don't need to be duplicating deployment pipelines.
Be pretty sure about needing this when you do it, because it might be your biggest mistake ever if you're not sure about the implications.
Using iframes, for most apps, usually brings more pain than benefits.

If an app is partially build with React, Angular and/or other lib/frameworks, that is in itself a red flag. You might be dealing with legacy code while moving to a newer stack. Using the same lib/framework brings you less mental overhead and quicker development speed, developer onboard, etc. Unfortunately I worked in some places where this was a sad reality and it was never easy to fix simple bugs due to the lack of structure, architecture, code conventions, etc . A refactor is your best friend but good luck convincing the product owner that you need X amount of time to bring 0 new features to the business.

Downsides of Iframes:

1. For each iframe you use, you'll use more memory, more CPU, bandwidth, increased TTI, etc.

2. You'll have to deal with subdomains authentication

3. Data over fetching, each iframe fetch its own data without sharing with another iframe. Trying to cache this is a sure way to chaos.

3. Breaking an app into tiny packages might be overkill when compared to having a proper folder structure, specially for UI.

4. Now you have a Content Security Policy to maintain, it gets trickier over time.

5. You’ve N CI pipelines, some repos will be “forgotten“ -> older React/Angular versions, packages that never got updated because you don’t work in that repo/“microfront”.

6. More DevOps overhead

7. Forget about good UX and be welcome to the world of redirects -> a “microfront” that takes you to another “microfront”

In my experience, breaking the business logic into packages is great since the logic is self-contained with unit testing, etc but placing the UI components there will bring you the problem of not having atomic UI components. Now if you want to change a UI component in just 1 package, good luck trying to figure out which pages could be broken.

You’ve to be very careful on how you break your app into packages, it only takes 1 bad design decision to make the whole thing a nightmare to work on. Not to mention when you’ve packages that depend on other packages, you haven’t written anything about versioning which is critical.

It is much easier to look at page built with React/Angular where you can see the exact definition of the UI versus jumping between several packages to try to figure out where do things come from. Put the UI components and pages in a single folder/package. If you something like StoryBook and create your package for UI components, even that brings some work to get right and maintain, you split these components into more than 1 package and you’ll be running in hell for simple changes.

Reduced mental overhead is a precious luxury I strongly value.

edit: formatting

In most cases this doesn't work at all - flash, ActiveX, ...
Silverlight with WCF RIA services...
Much needed! For those questioning the use case: there are unique components (say rich text editor like draftjs) that are better in one framework (React) than in others. If your app is built in Vue, but you really want to use DraftJs because it's the best rich text editor, and the proper tool for the job regardless of it's backing framework, this project becomes invaluable.
There is another use case, that happened in my last job: migrate from one framework to another.

We were using EmberJS, which is a framework that I liked a lot, but it was just almost impossible to hire frontend developers to work with Ember. It is such a niche framework that it is basically asking developers to compromise their future career prospects to work on it at this point.

We used Single SPA to make an organized and gradual transition from Ember to React.

So having a solution to run different frontend frameworks is a way to avoid lock-in on a single framework (which can go out of favor in the future for whatever reason).

Micro-frontends are indeed a solution looking for a problem as others have noted. They remind me of the ball of mud that was Java portlets.

No team(s) wants to maintain a SPA written in multiple frameworks. If you truly must, embed a component written in framework X into a component in framework Y.

The embedding of components is a good way to re-factor your way out of having multiple frameworks and migrating towards a single framework. We've been doing this successfully at work where we're incrementally migrating our AngularJS + React SPA to Vue one component at a time.

This is a good solution, but only for transitions, you should strive to get rid of the older one as soon as you can develop. But at least you have an incremental path rather than a big bang at the moment you need to switch and that can be a huge advantage. Another HN'er here did a port like that on a pretty big website and nobody was the wiser change was happening until it was all done.
Exactly that. We used Single SPA to go from Ember to React incrementally, makes total sense and it helps a lot.
For those who may not know, here's a similar library: https://github.com/CanopyTax/single-spa

I'm glad to see two solutions out there, because there's a lot of variety in how this problem can be solved. For example, single-spa recommends (but does not mandate) using import maps [0] using SystemJS (to get better cross-browser support) The idea is, each application says they want 'react-dom' or '@angular/core', and it is resolved to a URL.

However, if applications are built expecting, say, different versions of dependencies, a naive approach to import maps won't work (e.g., the import 'react-dom' is requested-- how do we know which version to serve?).

At my employer, we take each frontend application and transpile to ES Modules and then combine via webpack. It's not what's recommended in Single SPA, but it greatly simplifies the deployment architecture for us.

We don't have to worry about hosting a CDN that can resolve import maps, everything's just in the bundle.

I think there are multiple solutions out there.

Our solution is called Piral, https://github.com/smapiot/piral, however, we do not believe that mixing technologies should be a solution - it's rather a workaround (which we also support). The real deal from our point of view is in independent development, deployment, and modular, decoupled thinking.

I don't ever want whatever problem this is solving .