If you’re Picasso, don’t A/B test, but for the rest of us it’s humbling to evaluate our ideas…
Posted on by Richard Greene
Atomic design is a pattern pioneered by Brad Frost that advocates building up the visual elements of a webpage from small components that combine to make ever more useful and complex forms. We at Skyscanner have also found it to be a useful analogy for how small components of code functionality can be used to build up functional, integrated web applications. Here’s our experience of using atomic-based code design.
Describing and designing code in this way makes it easier for us to abstract out and re-use shared functionality, improve testability of code and identify dependencies so that we can build the cleanest and most maintainable code possible.
Atomic Design Terminology
In the design paradigm, atoms are the smallest possible unit of functionality, molecules are simple features built up from one or more atoms and organisms are full features made up from molecules and presented to the user. These could be a button, date-picker for a return trip, or a full search control with date, location and filters, respectively. Organisms are placed into templates, which map out where they appear in relation to each other, forming specific pages. From a developer point of view, we can map this onto the underlying code that makes these function and also on to pieces of application logic that have no component directly visible to the user.
In our Squad (Inspiration and Discovery) we inherited an existing codebase and went about expanding and updating it. As we went along we realised that we wanted to try breaking down the existing functionality into separate re-usable components. Part of the motivation for this was so that it would be easier to swap in and out different versions of components when we wanted to experiment with new and improved features. Another motivation was to take areas of functionality that were very similar in different places in the codebase and creat shared, reusable components for them so that they would have a single point for maintenance and testing. That way we could avoid bugs that were found and fixed in one area cropping up again or slipping by in similar areas that hadn’t picked up the original fix.
The first step was to pull out some simple, shared functionality, like our logging and server communication code. These were our first molecules, a few very basic pieces of functionality that we would re-use again and again across the code. They were composed of no more than a few functions (atoms) and gave us single points where we could add new functionality. For the logger, this gave us an easy way to add in logging to new channels, such as adding logging for Google Analytics or Facebook where it had been lacking before. For the server communication this would later allow us to experiment with substituting in more up-to-date data from local caches, on top of data from server storage, without the consuming applications ever having to know the substitution was being made.
Win Some, Lose Some
Our next step was to move across from Browserify to Webpack. Although similar in functionality, Webpack had some additional out of the box features that were useful to us. The ability to require CSS as well as functional code was very useful, and it also came with ability to inline SVGs as part of the build process rather than serving them up separately. With this done, we now had each of our main product pages effectively running as single large organism on their own pages.
Our first effort in putting together multiple separate organisms on a single page was with one of our newer pages, the map. We introduced a new component to give people a richer way to choose their specific flight dates after choosing their location from the map, a panel that let them see the pairs of dates they could fly out and back on. The two organisms used a shared bus to communicate with each other, a molecule that we added in at the page level. This allowed the panel to update its display based on changes to the selected location, messaged out from the map via the shared bus. We were able to add in a whole new component, displaying rich data to the user, with very little disturbance to the map code. The two organisms relied on shared expectations of data at the page level, communicating via the bus, but were otherwise ignorant of each other’s existence.
Our problem came when we tried to use the new panel component in place of the existing code on of our older pages, to see if it could duplicate the success it had shown being used with the map. We quickly found that to be used successfully in the older page, it had to be customised in a number of ways that differed from how we wanted to use it on the map. It needed to be embedded in some additional UI, which we were able to do by adding another simple molecule of functionality, adding some filters and visual padding. However, we also found that we needed to alter the layout, the styling and add in some additional small pieces of functionality that weren’t necessary when using it alongside the map.
The lesson we learned from this was that although organisms were discrete from each other they were often too dependent on their context in a given page to be fully reusable. A better way of looking at them was as a collection of molecules of functionality. The existing panel was a particular configuration of molecules, and one we could use as a template for building another organism in a new context, but was unlikely something we would re-use as a whole piece.
Onwards and Upwards
Our current work is now focusing on the styles associated with our web components and on applying atomic design principles more thoroughly across our existing code. Using Webpack’s ability to require styles like other library code we can create separate SASS files for each component and then combine them as needed. Instead of a single master style file, we build up and extract our overall stylesheet for any given page from the molecules we have pulled together to build it. To avoid problems with CSS ordering and specificity we are looking at adopting CSS Modules. With Webpack we can generate unique, locally scoped class names every time we consume styles for a molecule. The small amount of duplication this may cause is more than made up for by the ease of mixing and matching of different style components for our purposes.
For our existing code we are steadily decomposing the existing page-level applications into less tightly coupled molecules. In some cases, this is only a small change to the existing classes, in others it requires pulling out a lot of the implicit knowledge they have about the state of the rest of the page and making them require or access it explicitly. For one of our search controls, for instance, this allows us to pull out certain search fields to re-use in a different and more specific selection UI when the user has begun to narrow their search for destinations on a page. We can see clearly what components needs to function so that we can re-use them easily elsewhere. We can also see what depends on them and how they are connected to the other molecules around them for when we want to try putting new or updated molecule in their current place to test out new designs.
The more we break down our code into these building blocks, the quicker it is when we drop in new UI or UX on the page, when we update our data sources and when we want to try out or discard new pieces of functionality. If we want to try out a new service, we are better placed to put together a working prototype from the molecules we already have lying around, as our applications are designed to be broken down into pieces and rebuilt as needed.
Richard Greene is a Software Engineer working in Skyscanner’s Inspiration and Discovery Squad.
Posted on by Pim Van Oerle
A few weeks ago we launched the Skyscanner Facebook Messenger bot. Designed to give simple answers to complicated travel questions inside Facebook Messenger, the bot forms part of a wider move we’re seeing towards Conversations as a channel, alongside (and overlapping with) web and app.
This post will go over some of our experiences in building the bot – how we set ourselves up, what sort of technology we used to allow us to move quickly, and how we moved from concept to production in just 42 days.
Posted on by Dani Ametller
…and other related stories
So, we got ourselves this fairly new service called ECS (early adopter alert!). ECS is a multi-layer acronym for (Elastic Compute Cloud) Container Service.
The idea is that you simply define your tasks as Docker images, you give them a cluster to run on and the ECS does the rest for you. You can just say how many of your tasks you want to run, and ECS will try to figure out where to place them, when to start and when to kill. Great.
The notion of ‘when to start and when to kill’ might sound alarm bells in your head: if so, here’s our experience of cooperative scaling on AWS ECS.
Posted on by Richard Davidson
This episode we talk about bots. Skyscanner recently released our Facebook Messenger bot and we talk about how we did this and what the future of bots may be.
Posted on by Csaba Toth
As developers of Skyscanner’s iOS app, we’re always thinking about the performance of the application. We know that even if we have a great application with a lot of features, lag can hamper the whole UX. Here are our top three tips to help address app performance.
Posted on by Filip Filipov
APIs have become the life-blood of the modern Internet; they are powerful tools that open a stream of highly valuable data upon which start-ups can create a working foundation for their new tools.
Skyscanner has committed itself to being as open as possible in providing its travel APIs to start-ups and new businesses. We want to make our data, which has taken years to build into a comprehensive and cutting-edge travel search engine, available to others as they start on their own mission to bring something new to the game.
Posted on by Tamas Karai
You might have read our previous blog post about data driven development in apps, although if you haven’t, you can find that blog post here. This post is a more detailed overview showcasing the technical details and motivations behind building our new mobile analytics framework.
Posted on by Akos Kapui
Mobile first design often refers to a principle that puts UI/UX designs for mobile devices before desktop web. However, the implications that come with this go way beyond the UI. A mobile first strategy requires a new approach to planning, development, UX – and it requires a new approach to API design as well. Although using the same RESTful APIs for all platforms would be possible, in reality it creates constraints for the mobile experience. The benefit of designing user-interfaces only for the web was a massive simplification and we (engineers) can easily get used to this level of comfort. This article is going to discuss design considerations for service APIs that enable teams to deliver a mobile first experience.
Posted on by Stephen Hailey
Skyscanner is powered by a constantly evolving collection of systems which have been implemented at different times, by different teams and using different technologies. As part of this evolution I have been exploring options for porting some of our .Net services from Windows-based servers to Linux-based Docker containers by using .Net Core. Along the way I have contributed back to the open source Compare .Net Objects project to add .Net Core support and discuss the details of what was involved below.