2016 has been a very busy year at Trainline as we have been growing at a rapid pace. This means our tech team has had to work hard to scale effectively and cope with the sheer demand.
New product teams have been springing up all through the year, while older teams have grown and been split into sub-teams to maintain the essential agility of small teams. With such growth, we have needed to ensure our processes were in good shape to manage the increased complexity that this brings.
Here are a few fascinating stats which tell a short story of the year at Trainline … Continue reading
Hacktrain is a three day hackathon on a train. Around 80 software developers, designers and entrepreneurs from across the world gather together to imagine a better travel experience for the rails. The best ideas win a trip to Hong Kong and an assortment of light sabers, drones and other suitably geeky toys. Continue reading
About our App
The Trainline app is a ticket-reseller market leader with more than a million active users. So you can imagine that the quality of our app is one of the main things we care about. The ability to spot issues quickly and capture crashes is critical for the apps of this scale and complexity. And as we are always developing something new and updating the application continuously, we must make sure that we have a fast and robust way of making sure that we do not break anything on the way.
As with any responsible team, of course, we write unit tests for business logic, and we also have integration tests for some big system components. But we have started to get a sense that we are missing something and this something is quite big piece of the puzzle in order to get the right level of confidence about the quality and stability of our application as the team makes code changes from release to release. So we started thinking about this. What is missing? Logic is tested and covered. Even complex class interactions are covered, but what is missing?
Of course, one of the most crucial parts of the application to test is the UI! The most prominent piece of the application that people are guaranteed to come into contact with in their daily use of the app. If something breaks the UI, if something breaks in screen interactions, it will inevitably lead to a very obvious bad user experience and we definitely don’t want to upset the users of our app at all!
To address this issue correctly, we first identified any obstacles that we might face while working with a UI test automation suite: Continue reading
Our team supports nine applications out of the same code base (achieved by a combination of configuration, feature toggles and CSS magic). This code base has been evolving continuously over the last five years and we do at least one release every week and often more than that. Given this scenario, you can imagine how vital a role that unit tests play.
We depend a lot on our unit tests (among other things, of course) to ensure that releases go smoothly and that, when we add that shiny new feature that enables the customer to change her seat, it does not break the feature that lets her get the ticket on her mobile! To achieve this, our team adheres strictly to TDD and we have over 10,000 unit test cases that are run every time a commit is pushed to github and this number keeps on growing with every new feature development that we do.
How could we run our unit tests faster?
OK, so we have great unit-test coverage. However, the side effect of this is that it usually took more than 5 minutes to run the unit tests. Now that is not a very big number by itself but it does become an irritant when we run tests on our developer boxes multiple times a day before we push our commits to git. On a given day, a developer could have spent 15-30 minutes waiting for the tests to run and the build to finish. So how could we spped up this process?
It turns out that NUnit-3 test engine has the ability to run tests in parallel. We hoped that it would reduce our test execution time. In addition, we looked at how Rake Multitask could help us reduce our overall build times. Read on to see what happened…
Whenever I reach a milestone or finish something, I pause and reflect on the journey and what I have learnt. I’m going to talk about our journey of migrating one of our systems from MSMQ to SQS.
When we started, we had a system that looked like this:
We wouldn’t dream of running an A/B or Multivariate test without a solid hypothesis in place. These little statements are the tiny hearts that power an idea through to completion.
But what is it about this statement that makes it so invaluable? And how specifically has it helped us? I’m hoping this article will give you an answer to these questions, as well as convince you to use them in your testing program (if you’re not already doing so, that is).
Best of all, I’ll be using a real example as a case study! Continue reading
With functional tests being an integral part of a webapp workflow, we should always try to find ways to make them run smoother and make our lives easier.
I’ve been working with Selenium Webdriver/WebdriverIO for years now, but I have always thought: “Wouldn’t it be great not to need a Selenium server running before starting my tests?”
This may seem like a minor problem, but it means having another tab open in my terminal, starting/stopping that process, and it all gets far more difficult when you try to automate it in a CI environment. In addition to that, you need Java installed to run the Selenium server (or you can use the selenium-standalone npm package, which removes the dependency from Java but still needs to be started/stopped). Continue reading
At Trainline we use AWS Lambda  in conjunction with API Gateway  for some of our microservices. Different teams use different languages, but in the Data Engineering team we use Clojure  – which is a JVM based functional programming language. Here we share some of the experiences we’ve had developing and deploying REST based APIs using JVM based Lambdas.
Although we normally use Clojure, in this blog post we will present a Java based example (for the benefit of a wider audience). However, we expect that the same results would apply to all JVM based languages (Clojure, Scala, Groovy, etc.) Continue reading
(click here for the English version)
En janvier, nous avons appris que la SNCF souhaitait mettre à jour son système tarifaire, c’est-à-dire l’ensemble des règles qui déterminent le prix d’un billet. Elle laissait tomber les prix des périodes d’affluence des TGV, elle diminuait les changements de prix brusques, elle offrait tant de cadeaux aux porteurs de cartes de réduction que ça sentait bon Noël.
Mais ces nobles objectifs s’accompagnent de grands défis. Tout comme une princesse doit combattre un dragon pour délivrer son prince charmant, la SNCF devrait combattre son système tarifaire actuel pour en extraire une perle de ses cendres. Le sang de ce combat ne pouvait éviter de couler sur leurs partenaires : les guichetiers, les agences de voyage, les GDS, et nous.
Les systèmes tarifaires n’ont qu’à bien se tenir !
(cliquez ici pour la version française)
Back in January, here at Trainline Europe, we learnt that SNCF, the main French railway company, wanted to update their fare system — that is, the set of rules which determine their ticket prices. The plan was to scrap congestion pricing on TGVs (France’s high-speed trains), reduce sudden price increases, introduce so many offers to discount card owners that it would feel like Christmas!
However, those goals were not without challenges. Just as a princess must defeat a dragon to free her Prince Charming, SNCF had to fight the complexity of its current fare system to extract a pearl from its ashes. The blood from this fight had to drip onto their partners: counter agents, travel agencies, GDSes … and yours truly.
Fighting fare systems requires extensive equipment.