Wait, what?

This title needs some explaining ;-p. This article is about how you can apply the strangler pattern on your frontend of a unique monolithic application. Or in other words: how to transition your frontend rendering to a modern technology, without bringing feature development to a grinding halt. There are many examples that show you how to do this with cloud migrations or transitions to a service oriented architecture, but I haven’t seen that many articles on how to do this on a frontend.

Having many teams working on 1 product becomes more and more challenging when you want to increase the pace of releasing functionality. As a result the application will have to be split in many pieces of which, teams and product owners can take ownership (conway’s law).

At Jumbo we’ve decided to split our frontend into graphical components in Vue. We’ve leveraged a design system for a rationale behind each graphical component for a homogenous and omnichannel experience.

So what

Well, it is an exciting development. Compartmentalising our frontend into (Vue) components, enables us to reuse them and discuss them atomically. The problem however, is that Vue is a client library and the more you replace, the less HTML will be rendered on your server. More and more logic will move to the frontend.

That needs to be addressed. Waiting for your application to process business logic on the server, pull in all assets, execute them, apply the output of business logic to templates and have your browser render them while staring at a blank screen isn’t nice. As a mater of fact, it’s costly, because slow performance (and slow perceived performance) is linked 1-to-1 with a loss of conversion.

The more the HTML rendering will be performed on the client, the less SEO friendly the generated content will be. In addition to the reduction of speed, the SEO penalty will be hitting your conversion rate as well.

To get rid of that monolith, you’ll have to assess the responsibility of each piece of logic, and where possible, separate it as an individual atom or blackbox that can be replaced when you have the need for it.

Rebuilding your entire digital proposition doesn’t make any sense. It would stop function development in its tracks and there is no guarantee that the future solution will be better. You’ll need a way to strangle the old frontend piece by piece until there’s no more demand for the support from the monolith. This would be a low cost solution that progressively enhances your website while moving it towards its future.

Okay, now what

Since our eyes fell on Nuxt, we were in love. Nuxt enables you to render your Vue components server-sided after which you can hydrate them in the browser. It’s the future of our frontend.

Law of holes, states: When in a hole, stop digging.

You can extend your monolith in all the ways you want, but deep down you know that it will never solve your situation. You need to break out.

That’s why you’ll have to put a layer on top of the old monolith that serves everything that’s considered ‘the new way of doing things’

This kind of punch-hole replacement has one major consequence that will boost your transition. The ‘new way of doing things’ (in this case Nuxt) will become the dominant platform from the get-go.

By doing this, you basically knock it from its pedestal. All of the sudden, it degraded from being ‘the all knowing unicorn’ to ‘the service that does way too much’. It might not seem that important tech wise, but it means the world in a situation where you feel you have no control on your outages.

The more Vue components you’re adding, the lesser the responsibility from your backend becomes, until it becomes obsolete.

So how does this work?

When the user requests a url on your platform, the request is matched against a set of rules. These rules determine wether or not to immediately consult the old platform (think of generated assets and such).

In case we have a good alternative, render that alternative.

Otherwise, relay the request to the monolith. It will render the page as you expect it to, but this time without the components your new system is already equipped with.

These components are then loaded in your new layer, and the holes in the output the monolith generated will be filled with the output of the components.

How about state and context?

If this all would have been a bunch of string manipulations, we could’ve just ran some regexes and get it over with, but it’s more complicated than that. These components are interactive, and need to be populated with some state in order for them to function properly. That state is usually represented in your monolith’s database. Some parts of it is session logic, some state is determined by running some business logic.

To overcome this, your monolith can simply output its knowledge of the state for that component. Like you would have done if client sided Vue rendering would have resided within the monolith.

Then, when you progress, you could start populating the components with data coming from services.

In example, to transition the template rendering of your topmenu to the Nuxt frontend rendering layer, replace its template with:

<component-header

:current=”{{ session.navigation.menu }}”

:data=”{{ data.menu.tree }}” />

This is not ideal, but it’s a start. If you were to look at the response your monolith sends to your frontend-renderer, you’ll understand the next image

By pulling apart the layers, you can see the glue that’s in between. You become able to see which glue strands are easiest to rewire to a new service and which aren’t worth the effort at this moment.

You gained an opportunity to reason about the stuff that your frontend actually needs, instead of what’s readily available.

Instead of plowing through all code you can now reason backwards to see what you really need to become independent. You can do it at your own pace with no significant impact on your development teams.

By separating your frontend progressively, you’ll be able to migrate your business logic away to services. You’ve strangled your unicorn, and you started at the head.