Companies at a scale like Spotify’s, with half a million lines of code and forty engineers, cannot afford to write spaghetti code that barely works. In this MBLTDev15 talk, Hector Zarate of Spotify goes in-depth about the internal changes that Spotify made to extract common layers of code from isolated chunks & create a visually consistent, light, and back-end-driven iOS app. Learn how these architectural changes enabled Spotify’s successful and impressive redesign, and will simplify innovation in the future.
Hi everyone! My name is Hector Zarate, and I am an iOS developer at Spotify. I work as a feature developer. This means that I work very close to the user, and I’m concerned with design, accessibility, and usability of the application.
Spotify Scale, by the Numbers (0:29)
Before we, I just want to share some numbers of the company. So first some numbers on Spotify. We are the leading music streaming service all around the world. We have around 75 million active users, 20 million subscribers. We have a catalogue of at least 30 million songs, and we are available in 58 markets.
Now some numbers on our iOS client so you have an idea of what we deal with everyday. We have 40 monthly contributors across two different timezones, New York and Stockholm, and across three offices, Stockholm, Gothenburg, and New York. Our codebase is roughly half a million lines of code, and we support millions of users every day.
When Code Isolation Goes Wrong (1:40)
Today we will discuss how we transitioned from an application that was visually inconsistent, thick, and client-based to a client that is consistent, light, and back-end driven. In other words, consistent, thin, and dumb. This transformation will enable the development of next iterations of our product. This is a story that perhaps is common to many companies, but I think in our case it’s exciting because of our particular organization. We have to deal with a scale of 80 million users. As such, we also have many engineers working to make this product.
We also have to deal with lots of innovation. We are the leading product in the market, but to keep that, we really need to innovate every day. Lastly, our organization is modular. We have isolated features like radio, or artist, or the player, and they are all teams that are autonomous with their backend engineers, iOS, Android, Q&A tests, and more. For iOS, they’re completely autonomous. They can do anything by themselves, and for iOS, this means that each one of these aspects of the product is a project inside an Xcode workspace with a public API, and it’s defined by protocols.
This is really cool because if you work in the album section, for example, you can really focus into it, tinker your album feature, and you really don’t care what’s happening in the ads section because of this modularity. The entire app is highly modular and independent, and that’s a good thing.
The downside of this is that we are creating silos of knowledge between the engineers and consequently silos of implementation.t Through time, these silos start to grow more and more apart from each other, and we get to a state where standardization is a very big challenge. It was natural that our application became visually inconsistent as each feature was maintained in isolation.
G.L.U.E. - Internal Secret of Consistency (5:30)
What we are probably missing is some kind of glue that binds them together, so that’s what we developed. This glue that we call Global Language for a Unified Experience is a set of metrics, colors, and fonts that are combined together to create components like buttons or titles, headers, whatever, or even things that are even more complex like our cards that represent playlists.
On the implementation side, it’s just a framework that sits on top of UIKit, and that all our features have access to it and use it. Instead of using UIKit directly, we use all these subclasses and factories, and then we can make changes quickly, like a color, highlight, or font tweak across the app.
This gives our developers this joy building blocks to develop the features that you need. When GLUE was finished, our app looked very consistent; now we’re just missing thin and dumb.
Ceramic - Internal Secret of Thinness (7:13)
One of my first projects at Spotify was attempting to thin the app. We were handling the Browse page in genres, and my team had this idea of make like really awesome genre pages, and they wanted to showcase not only playlists like we usually will do, but also artists, singles, playlists, albums, and more. They wanted to be very specific for a genre. They want it to be different at different points in time, and it was just really dynamic. Sometimes you will see a playlist like here in a grid, sometimes a table, or a scrolling carousel.
The point here is that it’s very dynamic, and the content is just different types, not just one kind of operating a specific model. This team, they came with a very, very elegant model of describing this, so they figured this out. They have a space that contains blocks that, in turn, contain items, and while they have some basic properties like an item has a title, subtitle, a block has a title as well, and the space also has a title, and there is one key property here. That is the render type for the block.
This render type dictates the layout of the page and the presentation of the information that is stored in the models in each of our screens and sub-screens. We extracted this idea so it could be used for almost every component of the app, based on a cool name called Ceramic to compose these blocks.
To implement Ceramic, I defined these three protocols that you conform to. You have a space protocol, block protocol, and item protocol, and I really don’t care about your data if it’s offline or online. You just conform to them, and the framework renders this data. If we deal with very particular cases like a page with tracks or a page with something that I didn’t think about, then we use composition of protocols. We have item with metadata or item with icon, and we scale this complexity with protocols.
Backend View Model - Dumb Client (13:04)
We are still not done with simplifying our app since logic like sorting or translations still happens on the client side. Nevertheless, a team that was using Ceramic, the search team, realized that we have this really good frameworks that simplifies the view, the view controller, and the model, but the view model is still very different between each feature. They wanted to simplify this or make it standard across all these features, and they had a very clever idea.
They sent the view model to the backend, and they created a definition of JSON and some JSON engine that parses and interprets this JSON specification, and they put that on top of the Ceramic framework, which is on top of GLUE, which is on top of UIKit. Now these features start using these hubs, and now we got a client that really doesn’t do anything besides receiving data and maybe information of how to render this data, and now it’s a pretty dumb client.
Thanks to the back-end view model architecture, we can integrate content and test hypotheses, all without going through the App Store or changing any part of our client. This is all just a response from the backend. We have some existing block rendered types, but if we want something that looks different, that behaves differently, we just implement that part and shape it.
It is a very narrow sweet spot between flexibility and the rigidness of the framework. This approach empowers us to create tailer, personalized experiences in the next generations of Spotify, where before we had a client that will give the same to everybody.
Abstraction Downsides (22:43)
What are the risks of this? Well, the major risk is that you have a single point of failure, so you need good coverage of unit testing, automated tests, whatever you can use to reduce the risk of failing. At the same time, it’s used across the whole application, so any kind of failure will be noticed quickly, so that’s a good thing.
The second risk, which I think is even more important, is that you end up building your own cage from the inside. You have to learn to know when your framework is not good enough for the task, and at some point in our iOS application this framework is not going to be enough for what we want to do. You have to learn to recognize when will that happen.
Composition of Building Blocks (23:58)
I just want to end this with one observation about how these frameworks interact with each other and stack on top of each other. They remind me a lot of how mechanical machines work. You will start with something very simple like a wheel or a screw or a UILabel, and then you combine them, and then you get a more complex machine, and then if you keep combining them, then you get an even more complex machine that gives you more mechanical advantage. This machine is useful to multiply efforts and move you forward fast, and this is the kind of things that you want inside a tech organization.
Common Pitfalls & Advice (24:30)
Since we develop lots of internal frameworks in Spotify, I’ll discuss some common pitfalls that we’ve encountered and some good aspects of framework design.
- Keep it single purpose. Do one thing, but do it right. If it starts doing too many things, then you start introducing too many moving parts, and it’s gonna be just difficult to use. Just keep in simple.
- Have a vision – a roadmap of what you want to do with your framework, where it’s going to go.
- Share the toy. That’s important. It’s about preserving quality through some ownership and keeping your toy but also sharing it with other developers and allowing them to contribute and fail. I think that’s important, and so that all play together with your shiny toy to improve it.
- Have some marketing and customer support; give the framework a good name and write great documentation. Maybe consider doing workshops inside your company or evangelization efforts. This works both for an open source project or an internal framework.
- Finally, these kind of results are the results of lots of people working together towards the same goal, so share that success. This is not just my work, but this is the work of lots of awesome engineers, and we just stack that effort and build awesome things like this.
Q: Is this code that your presented and discussed production code?
Hector: Yes, these are all frameworks powering Spotify at this moment.
Q: What were some of the key difficulties you had in implementing these frameworks in the app?
Hector: The biggest challenge in creating this framework was not so much technical as it was organizational. On the technical side, it’s not much more than a vertical collection view with a relatively simple layout that just renders based on the input. However, on the organizational side, I had to convince other engineers to use my framwork despite their code “working,” so it took effort to make it happen.
Q: We are working on the same type of view-model on the back-end in our e-Commerce app. Since JSON isn’t helpful for marketing or content people, how do you allow them to configure pages on their own?
Hector: We have some content management systems that the editors use that are pretty simple, like small WordPresses. Those get exported into space, but they still require some massaging from the engineering team to work, so a lot of manual work is involved in this process.
Q: Is the GLUE framework open sourced?
Hector: No, it is an internal framework; it’s merely a thin layer on top of UIKit that is very specific to Spotify in the it stores our specific metrics like our green and black colors as well as fonts, and will likely not be valuable to other apps if it became open source.