Trainline replatforming: our front-end journey

Trainline Team
Trainline’s Blog
Published in
6 min readJan 13, 2017
screen-shot-2016-12-16-at-12-47-28

We recently started working on rebuilding the desktop version of the Trainline website. It is a big deal for the front-end engineering team because we have to make sure every choice is justified so that the user experience is never compromised. I am writing this blog post to explain how we went about selecting our front-end tech stack and why we made these choices.

How we approached it

First, it seemed obvious for us to use the following JavaScript dependencies as a base for our front-end stack:

  • React
  • React-router
  • Redux
  • Webpack

Things became more complicated when we had to discuss the following topics:

  • Which library to manage side-effects: Redux-saga, Redux-observable or Redux-thunk ?
  • Is static typing valuable for front-end development and, if so, should we use Flow or TypeScript?
  • Which library should we use for styling in React: CSS-modules with PostCSS or Aphrodite?
  • Is server-side rendering valuable for performance and SEO?
  • Should we keep our control components (buttons, drop-downs …) in a separate git repository?

This is a lot to bring to the table and we spent a lot of time deliberating. Due to the number of users of our website, every choice has to be carefully considered. For example, we had to make sure that every library we selected is well maintained and fits well with the other ones.

For that, we did some spikes (short, focused investigations) on each of the above points. It would take too long to discuss each one in detail, but here, I will cover the two most controversial.

Static typing in JavaScript — a long debate

scream

Today, there are two main technologies which bring static typing to Javascript:

  • TypeScript (maintained by Microsoft)
  • Flow (maintained by Facebook)

Both provide some common basics feature of static typings but are actually quite different in their implementation. To us Typescript seemed to be the most adapted and, to be honest, we didn’t focus too much on Flow, mainly because the team was already used to TypeScript. As opposed to Flow, Typescript is a compiler, and we are using it as a replacement for Babel to compile to ES5 which also simplifies our stack.

Now the main debate in the team was why we should be using static typings with TypeScript. We had a look at multiple articles to help us out here, such as:

Each of these covers a lot of valuable opinions, but I will try to summarise the team opinion on this. I personally think that the most important point is that TypeScript helps us to catch some static type related bugs. This is even more so since TypeScript 2.0 came out with the strictNullChecks compiler option.

Next, having static types helps us to understand the shape of the data at any time. By just looking at a TypeScript interface, we already know what is at our disposal. We don’t need to look at the API documentation, everything is there in the same codebase. This way, we only focus on the IDE and we spend less time in the browser trying to debug using console.log or break points. To make sure that we benefitted from this, we decided to be strict and force everyone to define an accurate type by enabling noImplicitAny flag.

Another nice point that TypeScript provides, which is not always shown, is that it gives a proper “auto-completion” and “jump to definition” and this is very valuable as well. Now that I am used to the syntax, my productivity has increased a lot by just jumping between files, so I don’t spend time hunting around the files trying to search for any information.

That being said, one downside of TypeScript is that we rely on the community for the type definition files. If a library doesn’t have a type definition file you either have to write it yourself or you have to use it without typings. To me this is not a big deal and shouldn’t be a big worry, as the community around TypeScript is big enough that all the most-used libraries already have their type definition files. If the library you are using doesn’t have any, you should think twice about using it.

Styling in react, inline-style with Aphrodite vs CSS modules

And now the second most controversial topic our team had to face. We were quite literally divided in two around this one. In the end, we decided to go with Aphrodite and here is why:

  • It is easier to apply dynamic styles with inline styles rather than applying a css class as a string depending on some logic
  • Aphrodite provides real CSS pseudo-selectors (`:hover`, `:focus` etc.) that inline styles alone do not cover
  • Because CSS involves cascading styles, the rules are not scoped to a component and this can lead to some unexpected styling issues.
  • Aphrodite is compatible with server-side rendering
  • When using Aphrodite with server side rendering you can extract the CSS styles into a separate file so that the browser can cache it.
  • Aphrodite provides granular font importing. If the styles in your page don’t reference a font defined by Aphrodite, it does not get inserted (although Chrome already behaves this way).

These arguments were sufficient for us to choose Aphrodite as a styling library over css-module, but there are plenty of other elegant solutions worth trying if Aphrodite doesn’t fit your needs. At the moment I would suggest having a look at Glamor and the new shiny Styled components which is, I think, the most “React way” to tackle the subject.

PS: If you want to have a look at Styled components, at Trainline we have used it for the website of our Reactivate meet up.

The challenges coming up

pqytbp7ek1dqs

Once we had tested everything we wrote a boilerplate containing the full software stack. We now have around 20 developers working full-time on the desktop site using Typescript and Aphrodite and haven’t found any limitations so far.

Although it may take a bit of time for new joiners to get up to speed on all these technologies, I think it is good for the business in the long term. Enforcing some guidelines with these tools helps to reduce the impact that technical debt could have on the project.

We now have to make sure we share the knowledge with each other in an effective and efficient way and this is the upcoming challenge for the team. Sharing knowledge well is particularly important around Typescript and RxJs as these two technologies are quite disruptive.

If you liked this blog post, or if you are interested about the tools we are using, please come along to our next React meetup and join our Reactivate meetup group!

About the author

Alexandre Rieux is a front-end developer mainly working with React, sometimes playing with Swift, or learning Haskell and Elm (FP enthusiast). He is co-organiser of reactivate.london

--

--