Config-driven layouts for faster experiments

--

Over the last few years, our John Lewis website (johnlewis.com) has been growing in ambition and scale, including allowing us to tailor our customer’s shopping experiences depending on what they are buying. We serve a different page if you are looking for a new sofa, or if you are browsing the latest fashion or make-up, or shopping for a new TV. We give you the relevant tools you need to make an easy purchase for each type of product, such as size and colour options, key product details, the ability to add accidental damage cover and so on.

This tailored approach had become incredibly popular with our customers, so we started building more and more of these bespoke applications which, honestly, has got a little out of hand. This is the story of how we’re making it better…

A brief history

Sand timer on a wooden desk
Sand timer on a wooden desk

Around 5 years ago, we had already started adopting micro-services across our (multi-award winning!) digital platform but we had one front-end monolithic application serving the whole of the customer journey, from the homepage to checkout (which we now lovingly refer to as Browse Classic).

We found this approach was causing us a lot of friction and pain points, which you often see with multiple teams working on the same codebase, including long CI/deploy times, multiple merge conflicts and teams being constrained in when they could deliver changes to our customers.

We decided that we wanted to enable teams to scale more, move faster, deploy when they wanted and build differentiated experiences for our customers, so we adopted a micro-front-ends architecture, with React, Next.js and TypeScript as our front-end technologies of choice.

Fast-forward a few years, and we now have over 25 teams building micro-front ends, including the fragments like the header and full-page apps like the checkout and homepage, all with hundreds of deploys a year, as well as 7 different applications serving Product Details Pages (PDPs).

Yes, that’s right, 7 individual applications, all serving very similar but slightly different pages, with 7 different codebases to develop, maintain, apply security patches to etc. Each application was also taking longer than we’d like to build and get in front of customers so we can start testing our ideas.

A typical Product Details Page (PDP) on the johnlewis.com website
A typical Product Details Page (PDP) on the johnlewis.com website

A new approach

In order to tackle this problem, we spun up a team called Web Architecture (WA) to help make things better.

We wanted to:

  • Decrease time to market and cost of ownership
  • Provide a consistent experience for customers
  • Make building new experiences and capabilities easy
  • Build components for use across product categories

Whilst retaining:

  • Team autonomy and accountability
  • Our core principles of being Lean, Simple and Fast in everything we do

The new architecture

The WA team created a new architecture that allows teams to control the layout and components on a page with configuration files, instead of building entire applications.

A diagram of the JL Web Architecture, with labels for the constituent parts
A diagram of the JL Web Architecture, with labels for the constituent parts

The system is comprised of 5 parts:

  1. Scaffold — a Next.js powered application owned by the Web Architecture team.
  2. Route Config — a JSON file to specify which Page Config to use based on product data.
  3. Page Configs — multiple JSON files, stored in a bucket, and each owned by different product teams. These identify which layout to use, and which components to display in each slot in that layout. A slot can contain as many components as they need.
  4. Layouts — React components that contain the main HTML layout of the page, and define where the various slots are placed on a page. A layout can contain as many slots as they need.
  5. PDP Component library — a shared library built on top of the JL Design System, to provide the building blocks for PDP pages.

Layouts

Currently, there are 3 base layouts to choose from, all named based on the column sizes, fifty-fifty, sixty-forty and single column. Teams are able to create new layouts to experiment with if they need to.

3 layouts, fifty-fifty, sixty-forty and single column
3 layouts, fifty-fifty, sixty-forty and single column

PDP Component library

Our JL Design System (JLDS) contains the atomic building blocks for our teams to build all of our of Front-end applications, such as buttons, form controls, modals and accordions. We use JLDS to give us the ability to scale, reducing duplication and maintaining consistency across our front-end applications.

The PDP component library is built on top of this, providing larger, more complex components specifically for use in PDP applications, such as image carousels, add to basket controls and size/colour selectors. We chose to create a single place for these components so all PDP teams have visibility of which components are available and which experiments being run on them.

Workflow

The WA team own the infrastructure, the routing config and the PDP Scaffold UI application, which is the Next.js app that builds the whole page.

A PDP team, such as Team Fashion, own one or more slot config files. The team can add/remove components to a slot, change the order of the components or add new slots, changing the way the page looks and behaves just by changing a config file, no other code changes needed. They can create more configs and run A/B tests to experiment extremely quickly and they can iterate on the components that relate to their specific customer journey, all without having to run and maintain an application and codebase.

Testing

Given the almost infinite number of possible combinations of components and layout, we are moving away from a whole-page testing paradigm to a component-based approach. As long as a component has a solid set of automated tests, including unit tests and visual regression tests, we can ensure that they all play nicely on the page.

We use Storybook to display our components, React Testing Library for our Unit tests and Percy for visual regression. We find that this gives us the confidence we need to push frequent changes to our customers with high levels of quality.

So far, so good…

It’s been 5 months and the team have already migrated the first PDP application, the Retired Product page, which is performing brilliantly and we’ve improved our Core Web Vitals metrics along the way 🎉.

We are already working on the next PDP application, with the aim to complete the migration in the next few weeks. This will allow us to answer some of the trickier questions, such as how easy is it for multiple teams to work with our new architecture or what the optimal number of config files might be.

Have we met our initial goals though? Well, we can now spin up a new PDP application in under 10 minutes. We’re running and maintaining only one production application and a component library, instead of 7 full applications. All of our PDP components are in one place, making it easy for our engineers to work with and iterate on them. We can experiment and try new ideas in minutes rather than weeks or months, and every team has their own set of configs and can choose to build their own templates and components if required. So, in short, I’d say yes we’re doing well!

The future is bright 💡

Once we have migrated all PDPs to the new stack, we’re going to tackle another type of page, the Product Listing Page (PLP) to make sure our new architecture is suitable for multiple purposes. After this, we will start introducing the new stack to other parts of our Digital estate across the Partnership to help increase our agility and experimentation.

Watch this space for an update soon!

--

--

Owen Nicol
John Lewis Partnership Software Engineering

I’m an Engineering Lead looking after front-end engineering and mobile apps across the John Lewis Partnership