Leveraging configurable components to scale LinkedIn's Profile experience
April 5, 2022
Background and motivation
The Profile lies at the center of LinkedIn’s ecosystem and is the primary tool members use to showcase their professional identity. To meet the growing representational needs of our members, we had to acknowledge some of the challenges that come with building at scale:
Customizations based on member intents can be complex, resulting in a one-size fits all Profile.
Additions of new content types on Profile are also resource intensive.
Experiences diverge platform to platform, such as from mobile to desktop, ranging from copy texts to ordering of the cards themselves. At times, this can result in an inconsistent platform UI.
To help our teams build and deliver new features that allow our members to best represent themselves on their Profiles faster and more efficiently, we rebuilt Profile as a platform, leveraging modular, dynamic components that scale, to represent diverse backgrounds and multiple intents, while minimizing engineering friction and overhead. These API driven “component” building blocks, when pieced together, represent the full Profile.
On Profile, we display various types of content to our members – experiences, education, skills, etc. With our legacy architecture, most have their own API to return the necessary data to display the UI and each API is built around the specific data it is responsible for.
Legacy Profile data flow and architecture
With this architecture, the core challenge is having each client implement business logic to fire relevant API requests and transform the data-driven responses for their view layer. In this model, clients own much of the business logic for what Profile cards to display, how to display them, and what order the cards should be placed in. Overall this leads to slower release cycles for mobile clients as there is more engineering effort spent building new features and maintaining existing ones, and inconsistent product experiences due to different business logic on each client.
In order to iterate quickly and keep client experiences consistent, we needed to improve this architecture to standardize our logic and views across the clients and shift the business logic to the API layer. Once we can do that, we immediately are able to realize many benefits that come from a centralized, single source of truth logic layer. At its core, this is what this re-architecture achieves.
As mentioned above, we have been traditionally designing our Profile flows centered around the data we eventually want to render. Here, we started to explore how our flows would be structured if we centered APIs around a consistent set of views to render.
Standardizing UI components
To build a view-centric architecture, the first step was to standardize the views that we want to use to build Profile. Ultimately, we worked with our Product and Design teams to define a standardized set of composable components. By defining these platform-compatible (iOS, Android, and Web) UI components, we make sure that the overall user experience we ship to end customers is consistent. Below are a few examples of header, prompt, and text components. The header component has seven attributes associated with it that are rendered exactly in the way designed in the mocks below. Similarly a prompt component has five attributes and a text component has two attributes. All components come with a small set of optional attributes, giving us some flexibility to configure a component to best fit specific features.
For example, in a header component, only the “Title” would be required, while the rest of the attributes are optional depending on the use case. We can see three subtle variations of the header component displayed on the Profile above, where “audience”, “primary action”, and “secondary action” are all optional.
These components stitched together can create a card that you may see on the Profile. Below is a very simple example, where we can use a header and text component to create the “About” card.
Different components to create “About” card
Once a comprehensive set of components are designed, we have all of the reusable building blocks necessary to create the full Profile page. This helps us cut costs by 4x to build experiences that leverage existing UI components.
Defining our API schemas and endpoints
With our new strategy of creating view-based models, once we had designs for each of our components, the Rest.li schemas we defined came naturally. By leveraging unions, we are able to define a component schema, where each alias of the union represents a certain type of component we had designed with our product/design partners. A “card” on the Profile would simply be a wrapper around an array of these components.
Using this structure, we were able to simplify our client call patterns and build an architecture that, given a profile identifier, returns an ordered list of cards for that member to render.
Comparing this back to our legacy architecture, we now have a much more simplified client flow, moving most of our core complex client business logic onto the API. Ultimately, this reduced lines of code on clients by 67%.
New simplified Profile data flow and architecture
Complex UI layouts
Many cards on Profile today have somewhat complex layouts and are not necessarily just a stacked layout of components on top of another. A normal stack of components would generally look something like this, with components simply sitting on top of each other:
Basic stacked component layouts
We have other use cases, however, where some parent component contains another set of sub-components laid out in a particular way. For example, a tab structured component is a component with tab labels and another list of components nested within. An entity component can contain some sub-components as well, which is a list of components that have an indented UI effect.
Complex nested component layouts
The schemas we defined for these component types contain fields that point directly back to the main “component” model we described above, creating a recursively designed model.
With this structure, for even more complex scenarios which have multiple layers of nesting, we have the capability to recurse as far down as we need. For example, in the following diagram, we have entity and list components nested inside each other multiple times to create this UI view hierarchy.
Complex experience card example
With all this flexibility built into the architecture, we have gained an additional 20% of product engineering bandwidth, translating into roughly four more engineers per quarter to focus on feature development for our members.
Unifying detail screens
When a member has too many profile entities to display on the main Profile view, we allow members to navigate to a detail screen to show the full list of entities. In the old architecture, each of these detail screens had their own custom implementation that managed the data fetching, business logic, and view layer.
In the new architecture, we have unified all of our detail screen experience to be centered around components as well. Similar to the main Profile view, we designed a single API that returns the appropriate list of components based on the section type passed in. As seen in the following diagram, all of these detail screens are just a list of components, which as described earlier, are simply a union of various different component types.
Detail screen views
Moving to this model drastically simplifies our client side implementation and consolidates 40+ separate view implementations into a single detail screen framework.
New onboarding case study - Career Breaks
While taking a career break is not a new concept, the pandemic has brought the topic to the forefront, with many taking time away from work: 62% of people globally have taken a career break. What’s more, the sentiment towards taking career breaks is changing for the better.
According to a recent global survey:
62% of people globally and 64% of women have taken a career break
68% of women want more ways to positively represent their career breaks.
52% of hiring managers believe candidates should proactively bring up their career break during the interview and highlight what they learned during that time.
46% of hiring managers believe candidates with career breaks are an untapped talent pool and 51% say they’re more likely to contact an applicant that provided context.
Members on LinkedIn are also currently finding workarounds within the platform to explain breaks in employment to their network by adding unstandardized positions, such as caregiving.
We’ve been listening to our members and know that they want more ways to reflect career breaks on their profiles. So we introduced a new way for members to represent a career break in the Experience section of their Profile, with options like caregiving and health and well-being. In giving members a recognized, standardized way to proudly display career breaks on their profile, we’re letting the world know that taking a career break is professional.
Career breaks UI within experience card
This was one of the first new features we introduced after launching this new framework and is a great example of how our members are benefitting from building out new Profile view experiences.
In the old architecture, our API definitions needed to be updated to incorporate this concept of a “career break” explicitly and send back all the appropriate data that corresponded to it. Each client then needed to update their implementation business logic to translate a “CareerBreak” into the view layer.
With our new component architecture, leveraging existing components we have already built support for, the work is significantly cheaper. Without career breaks, the API would return a list of components that would look something like:
To support career breaks, the API implementation simply needed to return another EntityComponent. When formatted with the right images/texts and without any changes on client, the members will see the career break feature.
|Old architecture||New architecture|
|iOS||3 weeks||0 weeks|
|Android||3 weeks||0 weeks|
|Web||3 weeks||0 weeks|
|API||4 weeks – 2 weeks new API definition + 2 weeks implementation||3 weeks implementation|
|Total||13 weeks||3 weeks|
With our previous data model driven approach, building this would have taken 13+ weeks of engineering resources. In addition to faster iteration on development, we have observed a lower amount of client related bugs compared to building a similar feature on the old Profile. By reusing the existing UI components and transformation logic that are well tested, we lower the risk of introducing issues during rebuilding the client pipeline from scratch each time when we build a new feature.
Our hope is that this re-architecture will ultimately help deliver greater value to our members. With the re-architecture, we’ve been able to reduce lines of code on clients by 67%, translating to lower maintenance costs and improved experimentation velocity. With an additional 20% product engineering bandwidth we get roughly four more engineers per quarter to focus on feature development for our members.
Building features using standardized UI components are four times cheaper to build, making it easy to run experiments that previously required client-side changes (e.g. reordering of sections, copy changes, etc.). This exponentially improved our experimentation velocity and helped us make more data-driven decisions quicker. With the new standardized components, we now have streamlined monitoring, alerting, and tracking capabilities, translating to faster site-up triaging.
The re-architecture enabled other teams to build their own experiences on Profile, with a consistent look and feel for our members and allowed us to service twice as many partner requests than what was previously possible.
However, it’s important to note that there are some tradeoffs that come with this new architecture. Reusable components provide great benefits to lower client friction to render UI and align on styles. Moreover, one-off scenarios are expensive to support, and oftentimes, lead to the creation of new components. Such one-off custom solutions are ~40% faster to build on the legacy data model driven stack, where usually only minimal model changes are required to support these small one-off cases compared to full new components on the new stack.
Some of the steps we took at the start of the project were critical to its success. It was important to do our due diligence early to understand all the pros and cons of the new architecture. Gathering opinions and feedback from our members and our teams helped guide our decision making and ensure value.
Another critical aspect was to ensure that we were working with product and design partners to ensure that all parties understand any limitations within the system, and are speaking the same language, i.e. a “component” refers to the same concept for an engineer, a product manager, and a designer.
With the introduction of several new technologies and flows, it was imperative to performance test our APIs early and often. Even with this, we ran into several issues later in the process only when we had end-to-end flows wired up. Allocating enough time for performance testing and evaluation throughout the lifecycle of the project will greatly help derisk deliverable dates.
Lastly, ramping large scale changes can be extremely challenging without thorough tracking in place. Clear guardrail metrics should be defined to determine which metrics require further investigation. Data science teams should be involved before the ramp starts to help come up with a plan for tracking and monitoring all essential metrics.
We spent the better part of the last couple years designing and building out this new Profile framework. Now, we are excited to move forward and explore where we can take the Profile moving forward. Some key highlights include:
Working with more partner teams to onboard different content types onto the Profile wherever relevant (such as our career breaks feature).
Build a more dynamic Profile viewing experience based on our both viewer and viewee intents.
Continue to work with our technology partner teams to improve performance, reliability, and monitoring within both Profile and the technology infrastructure stack.
Expanding functionality of our components to build more leverage across both other pages within the flagship application and other LinkedIn ecosystem of apps.
We are very excited with what the future of Profile holds with this new framework and hope to continue to provide more value to our members at an increased velocity moving forward!
It truly took a village to bring this vision to reality - over 140 people across many different teams contributed to this effort! Thanks to everyone involved for the hard work and support.
Special thanks to Umair Saeed, Dong Joon Kim, Rick Ramirez, Kun Ma, Jacob Cui, Xin Liu, Zach Moore, Xuejun Zhuo, and others for their help reviewing this post.