DEV Community


The Five Year Journey to SPA

merri profile image Vesa Piittinen ・9 min read is the leading e-commerce site in Finland. The omni-channel retail company used to focus mostly in consumer electronics but has expanded to various other product categories in recent years. Steady growth has continued since the company was founded in 1992.

I joined the ranks in 2013 as a front-end developer. At that time the company was adopting agile development and was leaving behind the dark old days when developers worked more as individuals who received feature requests and bug reports directly from the management. The old culture leaned a lot on intuition and doing the most with the least - this works fine when a company is small enough, but isn't great once custom software has been growing this way for over ten years! A clear transition had begun to take place as more developers were hired to take a better control of the software.

The name of the company, Verkkokauppa, is quite straightforward as it means e-commerce. In contrast to this it was a bit bizarre that there was no team or person fully dedicated to the development of the "web", which is what the customer facing e-commerce site is called in-house. In June 2013 the Web team was finally formed and took ownership of the customer facing site.

The Legacy

The classical web, as we call the now out-of-production site, was based on PHP and was very much like most sites made before 2013: a fixed layout targeting desktop and laptop computers, HTML rendered server side with a few jQuery snippets providing features like product picture browsing on client side. But there were no real Web 2.0 features like Ajax: adding products to cart led to a separate HTML page. In that sense the site was very old-fashioned, technologically five years behind the trends.

There were other major issues with the classical web: it was plagued with business logic all over the place, including the very last views right before outputting final HTML to customer. This of course was the result of the old way of doing things: there was no time to take good care of abstractions.

It was clear for the team that this could not continue. We took some steps to improve the situation: one of the things was for to the team to build resistance against outside feature requests. This allowed time to consider the abstractions so we could start working on APIs, giving the ability to move business logic away from the view layer.

In the early months the team did a lot of improvements: one of the first was Ajax cart, which we made using AngularJS to get a bit of experience on it. We also implemented full page cache, optimized JavaScript, introduced HTML5, and fixed SEO issues. A lot of the kind of work that couldn't be done before.

Despite all those issues, even before the Web team fixed them, the site was the best you could find in Finland at the time. There is one fact however: you can't remain the best by keeping your current standards, you must think how to be the best in the future.

From Minimal Effort to Mentality of Quality

As a team we started to think about what to do with the future of the site. To help with our focus from business side we got one clear wish: we wanted to be strong in mobile. In 2013 mobile wasn't a big thing in Finland, yet. However, we had a strong assumption that it would be important as the signs elsewhere in the world pointed towards a trend of growing mobile.

There were many possible ways to go with the mobile: we could've made an independent site just for the phones. The good part is that you could do that relatively quickly. The bad thing is maintenance: you'd have to keep up two different sites and we really didn't have the hands to do that, and couldn't hope to grow fast enough for it to be plausible.

But there was news of new techs around early 2014: Node.js and React. These techs promised a possibility of using single language, JavaScript, to write our server and client-side code and re-use it in both contexts. In addition, React provided JSX so we could "write HTML in JavaScript". Not having a lot of coders this sounded a good thing: we could focus more in getting things done and spend a bit less time trying to make a mismatch of languages to agree with technological challenges.

There was also the idea of responsive: to create a mobile first site that would adjust to each device. None of us had done that before. With all these variables one could think it would be too risky to adopt so many new things.

And what do you know! We decided to build an entirely new site, based on Node.js and React. The work began on our checkout process, making it technologically possible to create an independent app for it. In spring 2014 a huge refactoring began. In summer I wrote a POC using React working with a very early version of checkout API. And as things tend to happen... the POC became the final product.

Success with Failure

A good thing about a checkout process is that it doesn't need to be indexed by search engines. This meant we could just put a HTML page somewhere and add in the JavaScript. It was our first true SPA.

However, it was clear we didn't have enough developers to put much thought into development of the new Node.js based app. And business wanted to have a site for cell phones by the end of 2014. Thus, some external help was recruited to get a React-based Node.js app running as an MVP.

The good thing: we did get the site running.

The bad thing: the team didn't get along with the external help, so they were released soon after the site went live.

Communication hadn't worked: the Node app was written in CoffeeScript and a few other technology choices we never asked for. This led into stagnation of the project for many months as nobody had time to learn CoffeeScript while the development of the checkout app was also ongoing.

At this point we had two checkout processes: the one for mobile, and the old one that existed in the inherited classical web. In first half of 2015 we worked hard to add all required features to the new checkout app, with responsive design, so that we could replace the old checkout for all users.

In June the big day happened: we gradually switched everyone over to the new checkout. And we got a pleasant surprise: conversion went up! We had done a great job with our new checkout app despite having some difficulties with React. At that time the documentation and conventions were still shaping, so we did many mistakes. But the app itself has been a great success!


Story with the future responsive site wasn't as great. No considerations had been made on architectural level to allow implementing SPA in addition to being served as an universal app. This combination is hard! No work had been done to allow for it and there weren't existing great solutions for routing. Thus, we had to ignore SPA for a long time despite having a desire to eventually implement it.

After checkout was out and I had my summer vacation, I returned to work with one goal: to remove CoffeeScript. There were some comments against it, but I did most of the refactor regardless. It was awful, lasted for months, and things didn't always go smoothly, but by the end of the year we said goodbye to CoffeeScript. At that time, we also introduced Babel and finally got JSX to the new site as well.

Refactoring would've been much easier if we had tests, but as usual, we didn't have resources to put them up properly, and external help hadn't put effort into it either. Tests would've saved from a lot! One of the typical bugs in the CoffeeScript source was unexpected variable re-use in a deeper scope. You can't declare variable in CS, so it is easy to think you have two or more variables in various scopes when you really have only one.

The great news is that the refactor was worth it: development speed picked up after the code was familiar JavaScript with some fresh ES6 additions!

The End of Classical Web

In November 2016 we released the new responsive site to all users. But we only heard that this will happen about two-three months before release! Yeah, that is quite tight considering at the beginning of the year most of the site was still mobile only, and a lot of important features were missing. We again got external help, but this time around it was made sure we really got along.

One of the major developments in 2016 was Redux. We put it in use in our checkout app and had some dramatic performance improvements. The old code passed far too many props to components, while with Redux this was no longer required. We hadn't liked Flux so we had relied in what little state management tools React provided - and we didn't know about the context API until much later! There weren’t HOC or render prop patterns.

The trend of updating to new tools and constant refactoring continued as we also picked up React Router. One could think time spent to refactoring was taken from new features, but we gained it back as things got simply designed better and were easier to use.

But the schedule! So many things could've gone wrong when we shipped the new web to all users and said goodbye to the classical web. Everything went business as usual, but it was scary because in 2016 Black Friday started to gain popularity in Finland. Despite all the dangers the new site was a success like the checkout app before.

The Calm After the Storm

As usual after a big launch, we really had to pay the price of feature rich development and completion of a goal. In first half of 2017 there was a lot of focus in fixing issues. Some people quit, others swapped teams within the company, and it took a bit of time until Web team got its numbers back.

Due to this not a lot happened to improve the progress to SPA... until release of React Router 4 which was a big one! We refactored to it in October, and it was quickly followed by React 16 in November. We now had some of the techs that allowed for SPA to be done, but then we hit a new wall that slowed things down: GDPR. A lot of things had to be considered and get done by May 2018.

We did some continual work to improve performance. In 2017 our Black Friday hadn't gone as well as we wanted and thus our yearly focus had shifted to ensuring performance to make sure people can buy from us, even if a lot of them visited the site at once. This finally started to make it obvious that we should spend time on SPA. After the summer holiday season in 2018 we finally had the slot for completing the dream to enable SPA on the entire site.

Universal Single Page App

Why is SPA so great? At this point we already had a great universal JavaScript app and we had optimized React boot times as much as we could. And... it wasn't enough.

When you go from HTML page to another in the traditional way you lose the client context entirely. Everything is unloaded and then loaded again, and then React needs to hydrate, followed by all the necessary business logic... it is a lot.

SPA skips most of this waste: you instead boot the app once and only get what you need via API calls instead of asking for an HTML page. The performance improvement is most noticeable in limited devices like cell phones: you can make the experience snappy and fast even on a phone when you take away the unnecessary work.

At the end of 2018 we reached the goal: all pages could finally be loaded as SPA. And it has been good: despite increased marketing efforts, which usually bring more people who don't buy thus reducing conversion, we haven't seen a reduction. Conversion has instead been the same, or even better.

It took about five years, but we now have quite a dream come true e-commerce site on our hands. It does many hard things and manages to do them right. There is of course still room for further improvement, but the most important thing is that we've not fallen behind the competition, which have vastly improved their sites within the past two or three years.

But their work is not enough!

Unlike in 2013 when the Web team began its work, we are no longer five years behind the trends in tech. A lot of what we have is the cutting edge. We've done a lot of work to reach this point, and while we still have things to do... we are the best in Finland.


Editor guide