Introduction of View Styles at Bumble

Andrei Simvolokov
Oct 20, 2020 · 10 min read

We are the team behind Badoo and Bumble, two of the world’s largest dating and connection applications with millions of users worldwide. To deal with the challenges that arise with such different products we rely on code reusability, and by so avoiding reinventing the wheel we keep our apps stable, our UX solutions consistent and much more.

However, for something to be reusable it has to actually be designed with that in mind. So, our dev team supports specific instruments, follows specific procedures and, of course, uses specific code architecture solutions.

Let’s say, for example, that you are creating a new feature which requires a new UI component likely to be reused in other projects. How would you go about it?

Any kind of clean architecture requires that the solution be split at least in two layers:

  • A View class — for displaying data on a screen.
  • A class which is responsible for a reusable case logic and controls a View class.

This pattern is very common to every mainstream application architecture (MVP, MVVM, VIPER, etc.)

Sounds like a nice clean solution, doesn’t it? But are these solutions really able to provide reusable components which can be styled for any specific case? Let’s test them out and see how we create such components in Bumble. Ready?

What is problematic with classic MVC/MVP/MVVM implementation?

Imagine a simple tooltip which needs to appear when a particular control appears on the screen. A model layer provides a localised text to be presented. Depending on control, each tooltip should have a different color:

Let’s use the MVP pattern as an example. The presenter needs to handle one event only (the control has appeared), set the tooltip’s text, set the tooltip’s color and present the View.

The class structure will look something like this:

The tooltip’s color will differ across different cases. So, a specific Presenter is needed for each case.

We can do the opposite and create a 100% reusable Presenter. It’s not going to control the View’s color. If a View is going to set its color on its own, then a specific View class needs to be implemented for each case.

Both patterns have problems with code reusability. Each time the tooltip needs to be reused, the developer is pushed to implement a whole new View/Presenter class. Most likely the developer will create a View/Presenter subclass instead and experience all the side effects of subclassing.

The ideal solution would be to have a single View class and a single Presenter class such that they can be reused everywhere. But how do you stylify the tooltip in each specific case? Classic architecture patterns like MVP just don’t describe that. Looks like we need a third player, a special class responsible for a View’s style.

Implementing a style component

Let’s dive into typography for a while. Imagine we publish a magazine or manage a Bumble employee benefits web-page. Here is a block of text which could be put there:

Editors change the text in two ways:

  • Editing. Editing means content changing. Let’s change, for example, 5-minute daily massages to 1-hour weekly massages.
  • Formatting. Formatting means changing text’s visible attributes, so let’s change the title’s color and make the font of the most important words bold.

The same approach can be used for our reusable UI components. Firstly, we need to split a View’s API into two parts

  • Content. This is the main data which View is supposed to output no matter in which App or which part of App is used
  • Style. This is a format data and is specific for each reusable case.

When a particular View needs to be displayed with MVP pattern on a screen:

  • a View is created
  • a View applies a specific style according to a case
  • a View is assigned to a Presenter.

So, a Presenter controls a View’s content while a View’s style is controlled by the factory which created it. This architecture is pretty flexible and facilitates the implementation of reusable components and combines them together:

  • the same Views can be reused in different contexts
  • the same Presenters can be used in the same feature cases. Views can be styled for a specific case
  • the same Styles can be used for the same UI component even if a feature case is different.

Alright, now that we have the architecture design, let’s create a self-explanatory maintainable and testable style for the next component:

I suggest defining a style as a struct:

And then, implementing a View:

As you can see, the title-text and the message-text are the displayed content of this View. At the same time, a huge set of properties became a style of the View. A specific Style entity can be easily defined. For example, a general component style for the Badoo App would look like this:

So now we’re able to create a View, apply a Style and assign the View to Presenter.


The previous example features a very simple View. However, its Style is a large structure and difficult to maintain. If we continue increasing a View’s complexity we will definitely struggle with the style’s size, so let’s try and break it down into smaller pieces.

First of all, we’ll create a very abstract ViewStyle structure which can be used for all the Views.

Now, let’s create a LabelStyle to be applied on UILabel. UILabel is a subclass of UIView, so it must contain a superclass style’s data. This can be achieved through aggregation.

Finally, we have to refactor the NewsViewStyle structure. NewsView is a subclass of UIView, so it must aggregate a ViewStyle structure. Also, it contains two UILabels and must have their styles.

This code is much better! It’s shorter, more understandable and it can be easily extended. It means we are now able to reuse substyles on as many levels as we need.

Default styles’ values

What does our NewsViewStyle.badoo definition look like now?

Hmm… it’s really bulky, right? Also, half of the code is describing default values. Do we need to do it for each style? Swift allows us to provide default values for parameters, so it is good for providing them to Style’s constructor:

However, subclasses suffer a tricky negative effect. What happens when a default cornerRadius of some subclass is not equal to zero? In such case, a subclass entity cannot distinguish between a default value and explicit zero value.
UIKit provides a reset-on-nil algorithm for many components’ properties. Examples can be found in UIView.backgroundColor, UILabel.font, UILable.textColor, etc. Let’s do the same.

All the Style’s properties need to be optional and nullified by default. Applicators must apply default values for all nil properties. Besides that, a substyle of any style can be nil, so applicators must be able to apply an optional style.

This is much more compact! It is easy to read, maintain and extend.

At last! One style solution to rule them all…Or is it?

Of course, this solution is not a silver bullet. Here are at least a couple of problems we have encountered.

Occasional inability to reuse universal substyles.

In the previous example we defined a universal ViewStyle helper struct which has a backgroundColor property, but can it be used for any subclass of UIView? Take a look at this next simple View:

It’s just a circle with a border. For example, be used as an indicator in which case the style can be constructed with a substyle helper.

Also, the same View can be used as a color picker:

In this case, the View’s background color represents the View’s content. However, border color and width are still part of the style. The substyle ViewStyle helper cannot be used because it would override the background color provided by the content.

Depending on the context some properties can be a part of style/content

Let’s move on now to look at the next UI element. This is a button which is used as a dating profile badge. It shows that a user is interested in sports and does sometimes take exercise.

It has an image. Should it be a part of ButtonStyle or not? Well, it depends on the context. This part of a View can be specified by the View-level or by the model-level.

When specified by the View-level it means that this icon is always shown for this kind of button. Image is a part of the style.

If it is specified by the model, then another icon can be shown for this button at some point in time. Image is a part of the content. For example, an image can be a part of the content provided by a server. Presenter receives an image and shows it in the View.

So, in a common case image cannot be a part of ButtonStyle, but in a particular case, it can be a part of an ImagedButtonStyle.

Can we make it even better?

Yeap. The idea of Styles can be improved and extended. Here is the list of ideas which we’ve already use or going to use in the future:

  • Basic styles and styles’ components (colors, fonts, dimensions…) can be controlled by a design system for all the company’s platforms. And we have one.
  • View-components with all possible styles can be easily presented in a Gallery App for fast development.
  • Styles can be covered with Visual Regression Tests.
  • Basic styles and styles’ components (colors, fonts, dimensions…) can be stored as resources on a device and can be replaced at any time from a server-side.

Do you have any more ideas on how Styles could be used? How else would you tackle the issue of UI component reusability? Would ViewStyles work for you? Feel free to share your ideas in the comments section!

Bumble Tech

This is the Bumble tech team blog focused on technology and…

Bumble Tech

We’re the tech team behind social networking apps Bumble and Badoo. Our products help millions of people build meaningful connections around the world.

Andrei Simvolokov

Written by

iOS Developer

Bumble Tech

We’re the tech team behind social networking apps Bumble and Badoo. Our products help millions of people build meaningful connections around the world.