migrating-our-supplier-administration-to-a-vue-js-and-node-stack
Engineering
Apr 12, 2021

Migrating Our Supplier Administration to a Vue.js and Node Stack

Mohamed Sadek
Senior Full Stack Developer
No items found.

The Supply Tools team is responsible for our Supplier Portal, a platform that enables our partners to bring their tours and activities onto our marketplace. Supply Tools handle the platform’s experience, insights, data, and overall performance.

Mohamed Sadek, senior full stack developer, and his team were faced with a challenge: They wanted to collect more information about each activity from suppliers — while simultaneously improving the overall experience. Find out how he and his team came to a solution that led to migrating their supplier administration to a brand new frontend stack.

To deliver travel experiences to our customers, we work with suppliers (also referred to as local partners) who add their tours and activities to our travel marketplace. These partners need to manage their inventory, accept or reschedule bookings, and generally get an overview of their business with GetYourGuide, and they do that through our supplier administration portal.

Built over nine years ago, the original version of the portal was written using Symfony with Smarty as the templating engine of choice. For those nine years, the portal was doing what it was intended to do; however, it was tough to work with this app or update it with new features. As part of a bigger monolith, it shared several modules with other applications within the same monolith, which made every change risky, especially for new engineers joining the team.

{{divider}}

{{quote}}

The lack of test coverage of any kind certainly didn’t help with that risk. The application became stale, new features were added by several teams without having one clear owner of the system until the Supply Tools team was created in 2018.

The team's mission would be to kill two birds with one stone: the usability of the system would improve in a way that serves our users (suppliers) — at the same time, increasing our velocity and ease into creating and maintaining various supplier administration features.Mohamed Sadek, senior full stack developer, and his team were faced with a challenge: They wanted to collect more information about each activity from suppliers —

The case for a migration to Vue.js

In the last quarter of 2018, the Supply Tools team had two equally important but seemingly contradictory goals on its roadmap. We wanted to:

  1. Collect more information about each activity that was being onboarded on our system
  2. Improve the overall experience of adding an activity to our inventory

The purpose of collecting the additional information was to have a standardized set of data for each activity that we could use to provide customers with accurate and tailored recommendations. Additionally, we wanted to allow them to filter a set of activities based on more granular data. This could be something like whether drinks are included in the experience, or which level of the Eiffel Tower was included in the activity.

There was just one problem — the two goals appear contradictory. If we are adding more mandatory fields for the supplier to fill, then we were negatively impacting how fast they could go through that form. This would impact their overall experience with it. For a form that already contains nine steps and includes over 20 questions, it seemed that our second goal of improving the experience of filling this form would be difficult to achieve.

The old activity on-boarding flow
The old activity on-boarding flow

As we thought about the problem, the general idea of a solution began to unravel:

1 - We have to improve the experience of going through that flow to such an extent that the overall experience improvement counterbalances the user's effort to fill the new mandatory questions.

2 - If the experience of filling the field is seamless regardless of the number of questions required, then any additional mandatory field will only minimally impact the overall experience.

3 - We can’t achieve a seamless experience without rewriting the foundations of the original form and how its UX is constructed. Instead of a linear flow with minimal guidance, a wizard or a setup assistant would lead to a seamless experience for the user.

Such an overhaul of one of the administration's key features signaled the perfect time to use our newly adopted frontend stack for the rewrite. Around that time, the company had decided to adapt Vue.js as our frontend framework of choice, combined with Koa, and a culture that strongly believed in testing, monitoring, and iterative improvements. We were ready to give our beloved supplier administration a much needed overhaul.

Thus began our supplier administration's migration from a nine-year-old Symfony/Smarty application to a sleek Vue/Koa application which ended last year. This is an overview of our priorities and our most consequential decisions during that migration.

Introducing Vue.js

One of the many UX issues we identified in our old activity onboarding process consisted of several steps. These steps needed to be filled out in order, starting with the activity title, all through descriptions, meeting points, and pricings without the ability to jump back and forth between steps. It required the user to know exactly what is required and to fill it in the order we decided for them.

By giving the user as much freedom as possible while still guiding them through the form, we could already make a big step towards improving this flow. The user should be able to skip steps, go back to an already filled step, leave the process completely and come back to find everything from their previous session ready to be picked up where they left.

Combined with Vue Router and Vuex, Vue.js offers a strong foundation for Single Page Applications, allowing us to do just that. The pieces were coming together nicely.

The backend (for the frontend)

Koa is our node framework of choice at GetYourGuide. It is lightweight compared to Express, and the support for async functions allows us to write code that is easy to understand and control through shareable middleware. Our Koa application running on the server would handle requests from the client-side and serve the appropriate assets. The intention was to have a minimal layer on the server-side, as the application was meant to be REST-based, with the API residing (at the moment) in the monolith.

However, this is changing with the extraction of various parts out of the monolith and into Java services; the Koa layer would do a bit more heavy lifting through an aggregation layer that will act as our API for the client composing data from various other services.

Principles: What did we want out of the system?

From the start, we were faced with several decisions regarding the structure of the new system:

  • Did we want to have several repositories or have all our pages live in one repository?
  • Did we want to use server-side rendering, and what benefits would it give us?
  • What would be our approach to bundling, testing, and so on?

Simultaneously, we did not want to abandon bigger company initiatives or put our product in a feature freeze until the migration was completed. We needed a way to iteratively migrate pages while also providing valuable new features for our users.

We decided on some principles to guide us through these questions, based on what we want out of our new system:

Simple to work with, yet scalable

We wanted both new and experienced engineers to jump quickly into the system and start building features and new pages. We decided to use one repository, but with a structure that makes it easy in the future to separate the pages into several repositories. If we dedicate a team per page in the future, separating the repository should not be a blocker, and the dependencies should be clear and easy to extract.

The structure we agreed on was to use a separate Vue app per page. While a SPA provides a smoother experience, we decided that it couples things too much that scalability becomes a concern. Each page built as a separate app meant that they could be bundled separately and share only common components while caching node libraries.

Vue.js and Node stack2.png
Pages in the app

Each individual page holds a single-page Vue file as well as an scss file and utilizing a CLI command that bootstraps a new page for us, as well as adding it to Webpack entry points, makes adding a new page and getting right to development a matter of minutes. Not to mention that having the same structure across the app makes it easy for newcomers to understand and work with as they jump between pages and compare older structures with what they are building.

The decision not to use a server-side rendering approach for this project was based on complexity vs. benefits gained. As our supplier administration is intended for B2B, we don't need to pay the same attention to SEO as we do on the customer website. Performance is still a significant factor for us. Still, considering the complexity brought about by server-side rendering when it comes to the development cycle and tooling, we opted not to use it for this project until it was absolutely needed.

You might also be interested in: Improving our email template development using Vue

Robust

We do not have dedicated QA teams at GetYourGuide, and this is for the best. Every engineer is responsible for the code they write and the features they release. It falls on us to add tests, monitors, alerts and to react properly to incidents. For our new system, we decided that TypeScript would help us develop a robust system that warns us about what could go wrong before it goes wrong.

Coupled with a strong static code analysis using ESLint, we are able to notice mistakes in the code before it’s shipped. As we run the analysis on every commit to any branch, we do not allow code that does not pass our analysis into our repository, even on feature branches.

Vue.js and Node stack5.png
Code using ESLint
Vue.js and Node stack 3.png
Code using ESLint 2

The other robustness variable that we wanted to get right was testing. We believe in meaningful tests that ensure any future change in the code is safe. As a rule, we started enforcing a 30% minimum unit test coverage for every pull-request (now we increased it to 70%). It also became part of our pull-request culture to detect parts of the code that could use more tests, or tests that don’t add value and should be improved or removed.

Vue.js and Node stack.png
Codecov report

In addition to unit tests, we add end-to-end tests for complete pages. They run on every deployment to production (while Unit tests run on every pull-request) and can terminate the deployment in the case of failure.

Performant

While we opted not to use server-side rendering for the new system on the side of simplicity, performance was still a key factor for us. We wanted to encourage users to use the administration on mobile phones to accept bookings or check communications with customers. To achieve that, we needed to make sure that both the UX and the page's performance were satisfactory.

I admit that this is an area that still has a long way to go. We laid the groundwork for bundle sizes, caching vendor files, and decreasing the number of requests to the server as much as possible. Our API still lives in the monolith, however, our first meaningful paint is still blocked by authorization calls to the API and initial data fetching. We expect that migrating our API to Java services and using an aggregation layer on Koa would improve our performance scores by a lot.

All migrated pages were built mobile-first with focus on Mobile UX.
All migrated pages were built mobile-first with focus on Mobile UX

Migration strategy

After we released the new onboarding flow, we decided to follow through with the migration while simultaneously adding features and supporting company strategies using our new frontend stack. The decision on which pages to move next was entirely data-driven. We used Google Analytics to see which pages were being used the most, which offer clear and beneficial improvements for our users. We followed that list.

The new activity on-boarding flow.
The new activity on-boarding flow

By building new pages using the new system and redirecting users to them, we had two systems running at the same time during the migration process.

Our strategy for migrating pages varied from moving a page as they were, rewritten in the new stack and using our new components, or moving a page after overhauling it while enriching the features and the overall UX of the page. Pages that were moved as they were are currently planned for a redesign this year.

The new home page, an example of a completely overhauled page.
The new home page, an example of a completely overhauled page

During that time, we also managed to release completely new pages. Here the new stack showed its strength; features that would have required weeks to build in the monolith were built and released in one week, well tested, and with a much higher level of confidence than when working with the old system. An example is a new calendar page that displays the supplier’s availabilities in one handy view.

The calendar page, an example of a new page built while migrating.
The calendar page, an example of a new page built while migrating

Goodbye, monolith!

Before the end of 2020, we managed to migrate the last page from the old monolith into our new frontend stack (our 404 page). This gave us confidence and freedom in deciding on our 2021 goals. We now have a system that, while not perfect, is easier to work with, robust, and is constantly improving.

It is much easier for new team members or members from other teams to understand our structure and quickly contribute to our codebase. And having solid linters, test coverage, and strong Pull-request culture, we are a lot more flexible in releasing features, confident that it will deliver the value intended to our users.

We still have many challenges ahead of us, moving the API out of the monolith, creating an aggregation layer on the Node side, and improving our client-side performance being the most immediate ones.

Measuring success

We strongly believe in data-driven decision-making at GetYourGuide. We rely on qualitative and quantitative user research, A/B testing, and surveys to understand our users and develop a plan of features and requirements. Our migration project wasn't any different. Before the project started, we conducted surveys to gather feedback on our Supplier Administration in its old state. The surveys were focused on the activity onboarding and gathered information on most requested features and difficulties in using the Administration in general. This established a baseline of the user experience we wanted to improve.

We conducted the same survey after the release of the activity onboarding flow. While we did not decrease the complexity of certain parts of the flow, we did improve the overall user experience by 19%, according to our user's survey results (based on responses from over 190 users.

Conclusion

While it seems like a daunting task to move an entire well-established application to a new stack, tackling the migration in pieces — while also adding features and improving the functionality of migrated pages — was the right way to go.

We didn't abandon company initiatives during the migration but rather contributed learnings from the migration process back into new features and vice versa. Simultaneously, we were continuously improving our system's structure and tooling to make the development experience easy and approachable.  

Building a robust application is more about providing great tooling, a simple structure, and continuous support to both new and experienced engineers than it is about setting rigid rules and coming up with the most complex structure right out of the gate. And while each new application is set out with some goals in its creators' minds, iterative and prioritized steps do pay off if you're heading in the right direction.

Other articles from this series
No items found.

Featured roles

Marketing Executive
Berlin
Full-time / Permanent
Marketing Executive
Berlin
Full-time / Permanent
Marketing Executive
Berlin
Full-time / Permanent

Join the journey.

Our 800+ strong team is changing the way millions experience the world, and you can help.

Keep up to date with the latest news

Oops! Something went wrong while submitting the form.