Applying the Facade Pattern on Spotify for Artists

February 7, 2024 Published by Rich Soni (Senior Fullstack Engineer)

Introduction

At Spotify, we’re dedicated to delivering a unified experience to our customers — which can sometimes be at odds with the vast, autonomous structure of our engineering organization. To prevent Conway’s Law from becoming a reality, we have to be vigilant, ensuring our diverse, geographically dispersed teams don’t unintentionally create fragmented user experiences.

So how do we reconcile these seemingly opposing notions? From a visual perspective, our design system, Encore, has embraced a “local system” approach, which enables individual systems (Creator, Ads, Consumer, etc.) to build on a shared foundation. But Encore also affords them the flexibility to offer a customized experience that speaks to each of their local customer segments.

From a support perspective, we recently employed an Inverse Conway Maneuver, creating a team to unify the support experience across the local segments. This team built an internal support platform called Turnkey, which took the approach opposite from Encore. This platform generalized the customer support tooling, which removed the burden of implementing and supporting it for each local segment.

Encore’s “local system” approach.
Turnkey’s Inverse Conway Maneuver.

During the migration of the Creator Support pages to Turnkey, we faced an unexpected challenge caused by the differences in these two approaches to Conway’s Law. Before migration, our support pages were collocated with the Spotify for Artists home page. This included our MastheadHeader and MastheadFooter components, which are key to unifying our user’s experience within Spotify for Artists. We wanted these components to continue to be the same from within the Turnkey system, but we also assumed that all the other “local segments” would want the same for their users.

To solve this, we leveraged the facade pattern, which “provides a single, simplified interface to the more general facilities of a subsystem,” and we created our own iteration, S4X-Masthead, to maintain parity between our Masthead components of these two systems.

S4X-Masthead

The S4X-Masthead exports three React components: MastheadHeader, MastheadFooter, and MastheadProvider. The goal of these components is to prevent duplication and drifting implementation between the client applications. By centralizing these elements, we can maintain consistency within the user’s experience, like fixing bugs or making design changes in one place, instead of cascading that change to all subsurfaces of Spotify for Artists.

The MastheadHeader and MastheadFooter are UI components that collectively afford various navigational and utilitarian actions presented within every Spotify for Artists surface. These include elements like language selection, login/logout, links to different areas of the site, contact information, and legal disclaimers. Like the data provided by the MastheadProvider, these surfaces are, ideally, not different from each other. For instance, if the URL for a social media account changes, we can share the MastheadFooter component between applications and proactively prevent broken links.

The MastheadHeader component of the S4X-Masthead.
The MastheadHeader component of the S4X-Masthead.

To guarantee consistency among the clients, the data is dynamically loaded from a CMS at runtime. If, instead, we hardcoded this data, there could still be a drift in experience due to one client not updating its version to get the new experience.

The MastheadProvider is used to expose some key contexts to each application, including the user session and localization preferences. This data is derived from actions taken within the MastheadHeader and MastheadFooter components but can also be used from within the application pages. Maintaining integrations requires correspondences with the domain-specific teams that provide these integrations and are the places that are most likely to cause bugs in the application if the implementation drifts among clients. For example, updates to the authentication integration in one client could break the integration in others. By providing this to the clients, we ensure that they are all using the same version of the integration library.

Leveraging the facade pattern

S4X Masthead architecture.
Class Diagram for Facade Design Pattern” by Vanderjoe.  Used under CC BY-SA 4.0, via Wikimedia Commons

Part of the beauty of using something well-established, like the facade pattern, is that it makes communication crystal clear. There’s already a body of material to reference both in implementation and documentation. The friction for debating details is much higher.

The facade pattern, as described by its inventors, “provides a single, simplified interface to the more general facilities of a subsystem.” They say it’s typically used in three cases:

  1. You want to provide a simple interface to a complex subsystem.
  2. There are many dependencies between clients and implementation classes of an abstraction.
  3. You want to layer your subsystems.

When creating a facade, the focus needs to be on the clean interface — integration with a facade should be trivial. This is important when building systems that cross team boundaries because the communication overhead of coordinating contract changes becomes exponentially more expensive as the number of consumers grows. While we only have two consumers for our system, they’re very far from each other in the organization hierarchy, which drives the cost higher. This simplicity afforded by the facade is integral to upholding a consistent user experience.

1. Provide a simple interface to a complex subsystem.

Reduced cost of maintenance

With a facade like S4X-Masthead, the only changes a client system has to maintain are version updates. Since the content is served dynamically at runtime via our CMS, this is limited only to structural changes to the underlying component or its design. Dynamically delivered content includes translated copy, menu content, and image assets.

Reduced risk of mistakes

Simple designs are easier to understand, and understanding prevents mistakes. Having a single integration point through abstraction, using the standard Spotify web library stack, and implementing a well-known design pattern (the facade) simplifies the system. This simplification lowers the barrier for understanding, thus reducing the risk of making a mistake.

2. There are many dependencies among clients and implementation classes of an abstraction.

The S4X-Masthead reduces the number of dependencies managed by the client. Instead of directly integrating with a third-party translation service or having teams manually synchronize UI and copy changes to the masthead, they are delivered as a single dependency to the client.

3. Layer your subsystems.

The S4X-Masthead integrates with the CMS for the component. The CMS handles translations through another third-party service. If the implementation details change in the future, S4X-Masthead can make the changes and potentially not require the downstream clients to even know.

Future considerations

While it was a move in the right direction, there’s still more work on the table for the project’s future. To begin with, our S4X-Masthead is the second-most shared Masthead project at Spotify. We followed in the footsteps of the consumer application, which also has a Masthead package. While there are some major differences in the scope of these projects, there’s a great deal of work to be done to combine ideas and simplify even further.

Note: Applicability reasons taken from Design Patterns: Elements of Reusable Object-Oriented Software (1994). Read about the facade pattern for free at http://w3sdesign.com/GoF_Design_Patterns_Reference0100.pdf.