Evolving the LinkedIn Business Platform

March 27, 2023

At LinkedIn, one of our most important goals is to offer a top-notch experience for all of our customers. Purchasing is a big part of that customer experience, and it is not as straightforward as many people would think. It can be complex and difficult to navigate, which makes the LinkedIn Business Platform such an important tool for delivering high-quality experiences to LinkedIn sales representatives (our internal consumers) and also customers of our products and services.

The LinkedIn Business Platform (LBP) is the platform that powers monetization at LinkedIn. Across all of our lines of business, products and services are quoted, priced, discounted, taxed, sold, provisioned, and renewed using LBP systems. It’s the LBP that brings together the logic  (code, rules, workflows, and algorithms) needed to achieve various business actions for our LinkedIn sales representatives and customers over the entire purchase lifecycle and beyond.

In this blog, we’ll provide a high-level overview of the platform and its evolution over time. In future posts, we’ll explain in detail some of the key components that power the LBP.

Understanding the business complexity

LBP is our new generation of this platform that enables multi-dimensional business growth while balancing overall system complexity and demands for strong business features. 

Being multi-dimensional is important because there are various aspects that must be considered throughout the purchase flow. Some of these dimensions are: 

  • Customer type: Individual or enterprise customer, profit/non-profit, government, etc.

  • Sales channel: Online self-served purchase or sales-representative assisted deals

  • Platform: iOS, Android, Web, etc.

  • Geographic region: Currency, tax, country-specific regulations, and regional payment methods

  • Product line: LinkedIn Marketing Solutions, LinkedIn Talent Solutions, LinkedIn Sales Solutions, etc.

  • Discount: Various automatic or discretionary discounts

  • Offers: Incentive a customer might use if offered and eligible (i.e. a free trial)

  • Product type: Subscription, consumable, or usage-based products

  • Contract type: Time bound (fixed start and end date), evergreen (active until canceled), etc.

  • Billing method: Pay upfront, pay on specified billing frequency, pay-on-delivery, etc.

  • Payment type: Credit card, PayPal, invoice, etc.

Dimensions are constantly added and all of these dimensions bring complexity to the platform. They create different variations of purchase flows or entirely change the experience and contract lifecycle. Imagine frequent requirements such as, “we need to enable automatic discount A for products B, C, D or entire product line E, when sold on platform F through sales channel G. This only applies to geographic region H when customer types are I or J.” 

To help our team manage this complexity, we’ve evolved LBP significantly to adjust for changing requirements, growing business needs, and shifting industry standards.

The evolution of our platform

Today, LBP consists of many business domain-driven services built with a loosely coupled architecture that uses configuration and a rules-based approach. This enables agility in new feature development as well as continuous integration and maintainability. But it wasn’t always this way.

In its earlier version, LBP was built on top of very few services that had all logic stored in a single codebase. The biggest of them was a huge monolith service called the Order Management System (OMS) and had logic for Pricing, Offers, Quoting, Ordering, Contracts, Renewals, Billing, Payments, Provisioning, and many more functional blocks in the purchase lifecycle as shown on Figure 1.

  • Graphic of our Order Management System (OMS)

Figure 1: Order Management System (OMS)

Over time, with the addition of new features, flows, products, and services, this monolith grew into large deployable services that were hard to develop and maintain. Many of the functional blocks of the monolith were tightly coupled with each other, making it difficult to reason about the code and sustain a healthy pace of development.

The turning point: modeling field flows

Recognizing the challenges, we started building a brand new experience, “field” flows, to streamline a whole new segment of enterprise customers making purchases at LinkedIn. Field flows are scenarios in which sales representatives are involved in the purchase process and assist a customer with the initial purchase of LinkedIn products. Representatives are also involved throughout the entire contract lifecycle, such as handling cancellations, add-on purchases, contract amendments, and much more. The difference in experience can be commonly compared to an online flow where individual members make purchases online via a self-service experience.

This re-imagining of field flows was a multi-year journey. The initial vision was to re-use the same OMS monolith service to enhance existing logic and implement new features to support new flows. The plan also included building foundational pieces that would power future flows that would be based on the new “field” tech stack.

While this project moved rapidly, we faced challenges with the OMS monolith service, such as:

  1. No domain boundaries: No dedicated engineering or product owner was assigned to a functional block or domain. Engineers worked on various features so they didn’t have expertise in a particular domain area or clear understanding of its role and boundaries.

  2. Regressions: New changes were frequently breaking existing and recently added logic.

  3. Reduced developer productivity: New feature development was taking much longer than planned. Many project milestones and releases had to be delayed.

  4. Low leverage of existing logic: In many blocks, it was nearly impossible to make changes in OMS or generalize logic without major refactoring.

Soon enough it became obvious that implementing new “field” flows (like many other big initiatives) couldn’t be done on a monolith OMS. Additionally, teams realized the difficulty in scaling our business further with this architecture. The alternative was to design and build a new microservice architecture, extracting or re-implementing parts of the logic from the OMS monolith and implementing all remaining pieces from scratch.

This offered a chance to design a new commerce platform, applying previous learning and accounting for future growth. This alternative was deeply challenging and meant a complete change of plans and trajectory for this project. Teams needed to implement many more foundational blocks than planned, re-prioritize and re-sequence tasks, and re-format execution tracks. 

Course correcting is never easy. As with many business-critical projects, our teams had invested in implementation plans, started executing on project tasks, and communicated intended milestones broadly. However, we had confidence in the benefits we could achieve with the change in direction, and we pivoted towards the rewrite.

A domain-driven architecture

Our initial idea for rearchitecting the OMS monolith service involved extracting blocks of common functionality for a specific business area into separate smaller deployable services as shown on Figure 2.

As we developed that approach further, we established key guidelines for domain-driven services:

  • Each domain houses the core entities and the business logic associated with the domain.

  • Each domain service is a single source of truth for its entities.

  • Domains are completely independent and interact using established events, models, and APIs.

  • Each domain has a clear engineering and product ownership.

  • Omnichannel logic is applied. Each domain handles all its logic for any flows like individual or enterprise, online or offline, and platforms (iOS, Android, Web).

  • Image of Initial concept of separate domain-driven services

Figure 2: Initial concept of separate domain-driven services

Once this vision was adopted, the next step was to redesign the platform, identify the initial domains to be created, and establish a code migration plan. It became clear that this would be an involved process but necessary for implementing a new “field” tech stack and supporting the long-term success of the platform.

The high-level transition plan included several steps:

  1. Create new domain deployable services and extract each domain’s logic into its own service.

  2. Define public models/APIs for each domain.

  3. Start using new domain services in the all new logic.

  4. Deprecate corresponding domain logic in the monolith service.

  5. Freeze and gradually phase out domain logic in the OMS monolith service.

  6. Ultimately decommission the entire monolith service.

This process took time, with adjustments throughout to ensure a calculated and successful progression toward our target. During the migration process from big monolithic services to smaller domain-driven services, we faced a few challenges. 

First, we couldn't simply stop using the existing OMS service, as it was serving all production traffic at the time. This task was like replacing all the parts of an airplane while it is flying so a measured approach was essential. 

Second, this migration was not just a lift and shift. Verbatim code migration was not an option since previous models and APIs were violating our new guidelines, so we had to rethink and redesign many of them. 

Lastly, the business logic had to be re-written for most domains in order to support the new vision of domains and to re-implement many business operations as workflows.

Results

Once the first several domain services were created, the domain-driven architecture and the transition from monolithic services proved to be successful. New feature development and deployment cycles improved tremendously. Where before preparation and complete deployment of OMS could take days, we are now experiencing cases where deployment of a single domain service could be done independently and take 1-2 hours or less. Overall, time to market has improved significantly for new projects and features, and we’ve avoided a single point of failure by ensuring the entire system no longer relies on a single service or a team.

This new vision of a domain-driven LBP reshaped the entire organization and changed the way we work daily, plan our milestones, and execute. With this reorganization, teams were formed by domain, with each domain planning its own set of features, formalizing key principles, and shaping their domain’s vision and role to support the overall LBP ecosystem. Teams started to think about clear domain separation and boundaries, making sure not to create tight coupling with other domains.

Over the past two to three years, teams have completed a number of major initiatives cleanly, following domain consistency and without changes in OMS monolith. These initiatives included: plenty of “field” projects to support our enterprise customer segment and brand new LBP domains like Ordering, Billing, Contracts, Rules-based Pricing, Enterprise/Field Sales Migration, Field & Online Purchase Flows Unification (Self-Serve Purchases), and many others.

Currently, all field and enterprise flows use new domain services and no longer rely on the OMS monolith. As for the OMS, we’re currently code freezing and gradually phasing it out. Eventually, the goal is to move over remaining online flows and fully decommission the OMS.

Purchase flow example

To understand the benefit that moving toward a domain-driven architecture for LBP can have on our customers, let’s consider a simplified purchase flow at LinkedIn. A customer chooses a product or a service to buy, sees the price, applicable offers, and tax. Then, they navigate to the checkout page and pay to complete the purchase. Just a few clicks, simple enough! 

To support the smooth and simple experience provided to our customers, the generalized purchase flow in LBP, as illustrated on Figure 3, includes showing eligible products, generating a proposal and quote, pricing and taxes, displaying checkout, and creating an order. Once an order is paid and placed, a contract is created that needs to be billed and provisioned according to the agreed terms and conditions. In many cases, a contract will automatically be renewed until canceled by the customer.

  • Graphic of the Generalized purchase flow in LBP

Figure 3: Generalized purchase flow in LBP

Conclusion

LBP has come a long way, but it is still in the early phases of its evolution with rapid business growth. Looking back at the direction we took, it is now clear that the project to implement new “field” flows, and many other major initiatives, could not be possible without evolving the domain-driven platform.

Kudos

Evolution of LBP would not have been possible without the dedication and hard work of the LBP Team and its partners, talented people and leaders. A huge thanks to the entire LBP Organization.

Additionally big thanks for helping with this blog post to LBP Team and especially to  Siddharth Agarwal, Roman Inozemtsev, Jacob Creed, Venki Balakrishnan, Calvin Lei, Jenie Gao, Stuti Sanketh, Sachin Kakkar, Benito Leyva, and Greg Earl.

 

Topics