There's a lot of great literature out there on why you should build a technical platform, and what is a platform, but I haven't found a resource which illustrates specific situations where you might want to build one. With that, I started thinking about patterns that could help spot the need for a platform and what to do about it when you find yourself in this situation as an engineering leader.
I plan to write a few articles about the different patterns I've seen in the past. If you think of any other examples, please reach out and I will write about it and credit you as a contributor.
§What is a platform?
For those less familiar with technical platforms, I'll be using the following overly simplified terminology and set of principles that might help understand the basics. If you'd like to go deeper on the subject, the articles in the introduction will give you more depth on the subject.
- Application team is a team that leverages the technical platform for a specific use-case, e.g. a team building recurring billing through a payments platform;
- Platform team is the team that operates and maintains the technical platform leveraged by application teams, e.g., the payments platform team;
- Capability is a piece of software that provides the business and a user the ability to do something, e.g., "charging a credit card" is a capability of the payments platform, and so is "refunding a card transaction".
- A platform is self-serve for most use-cases. Not only from a tech standpoint – meaning excellent documentation, developer experience, etc. – but also from a people and process standpoint. Jade Rubick's self-service coordination model article illustrates in detail what I mean.
- A platform is extensible for use-cases it doesn't support. Application teams can leverage the platform as building blocks rather than a black box to build and support their own needs. For instance, extending a payments platform to support recurring billing by an application team might be easy if it has a "store cards" capability and supports "charging a credit card".
- A platform operates similarly to a third-party to the use-cases. All complexity on maintaining the platform's domain is abstracted from the application team. Abuse prevention, security, compliance and 3rd-party vendors are good examples of the complexity a platform should abstract away.
The following quote I took from this article written by Evan Bottcher on Martin Fowler's blog illustrates the concept very well:
"A digital platform is a foundation of self-service APIs, tools, services, knowledge and support which are arranged as a compelling internal product. Autonomous delivery teams can make use of the platform to deliver product features at a higher pace, with reduced coordination."
With this quick primer on technical platforms, here's a fictitious story that talks about a common pattern to build platform teams: "consolidation".
§A story & the problem
Acme corp started its business by serving only business customers. Besides building a great product, they also had a software engineering team whose charter was onboarding new businesses. Besides designing the experience, the business onboarding team developed some basic functionality for:
- Authenticity checks through a tax ID to ensure the businesses onboarded are legally registered;
- Compliance checks for preventing money laundering, for compliance, security and quality reasons;
- Contact information verification to ensure any onboarded business could be contacted for any reason;
- And, as part of the onboarding flow, a credit card was required, which would get charged after the product trial ended.
Product-market fit came very fast for Acme, given their innovative product. Consequently, their ambitions broadened, and Acme's leadership announced a new strategy to support consumers without a legal business, with a different set of features. To do so, they staffed another team to build consumer onboarding. With the rising pressure from investors to hit targets, it made sense for the consumer onboarding team to develop their own set of systems. At this stage, to prevent fake accounts, it was as simple as just sending an email to confirm the consumer's email address.
Over a few months, the consumer side of the business also grew considerably. Acme saw another opportunity to charge a subset of consumers for a specific tier of their business product. The consumer onboarding team quickly implemented the feature, which was an excellent win. Nonetheless, a few months after the launch, some issues came to light:
- Trials between the consumer and business profiles were inconsistent, and managing different lengths of cycles created a lot of overhead for the finance team;
- Given consumer and business onboarding used different payment vendors, the same credit card that would work in a business account wouldn't work in a consumer account;
- As both products were built independently, language to refer to the domain varied across consumer & business, and sometimes was even conflicting;
- As Acme expanded to new markets, both consumer & business teams had to add new payment types, new compliance checks, and support for new currencies.
Usually, there are a few symptoms that precede the need to apply the consolidation pattern:
- Fragmented technology for a capability. Especially when you're experimenting with a new product, over-indexing in cohesion is usually a bad idea, as you barely know if the product will ever be successful. In the anecdote above, when the engineering leadership team staffed the consumer onboarding team, taking a payment was off the scope, so it probably was the right decision to build a new set of systems. Although as the scope increased, the company ended up with duplicated systems for many capabilities such as "taking a payment", "running compliance checks", "managing trials".
- Duplication of work or similar indirect dependencies. In the anecdote, when expanding to new markets, both consumer and business onboarding teams would depend on a "user management team" to add a "country" field to the user model to select which currency to use when making a payment. We can abstract this as more than one team having to do very similar implementation or sometimes the same work, or two teams having indirect dependencies for the same reasons to the same parties.
- Broken language across the business. In the example above, referring to "product trial" or "compliance checks" is very ambiguous, as you may be referring to very different things depending on who you talk with. For folks familiar with the Domain-Driven Design book, the Ubiquitous Language chapter comes to mind here.
§A solution to the problem
One example of a path forward for teams in such a situation is using the "application/platform" model and splitting up responsibility into three areas:
- Consumer onboarding, which focuses on the experience of the consumer onboarding and anything specific to the consumer side;
- Business onboarding, which focuses on the business experience and its specifics;
- Onboarding platform, which consolidates the capabilities used by both onboarding teams into a platform. Good examples of capabilities in this platform team might be "taking payments", "managing trials", "running compliance checks", which can be configured or extended to different use-cases;
And here's a breakdown of a step-by-step to test the change and see if it makes sense for your case:
- Set up a virtual team with representation from both teams. This group of people will be accountable for putting together an action plan and test the hypothesis. Besides working on a shared roadmap, I recommend looking into SLAs per use-case, level of extensibility needed per team, and prioritising future cases in the new platform with input from both teams. You might find that maybe you can live with duplication for a while longer, or even conclude that a platform is not the right fit;
- Carve out capacity to consolidate capabilities. If that proves to be the path forward, rather than going with a big-bang migration, or rewriting everything from the ground up, pull one capability at a time from former systems into the new platform. A way to prioritise is pick the use-cases that are the largest pain points for both teams and the business first, or the largest bottlenecks for the business first;
- Eventually staff a new team. Preferably with some degree of resourcing from existing teams, and move to the application/platform model.
And to wrap up, here's how doing this solves the symptoms aforementioned:
- Fragmented technology is no longer an issue, as, by design, the shared capabilities are in a single team;
- Ideally, most of the work should sit with the platform team when adding a new payment type, complying with a new policy, or adding a new trial type;
- The new organisational boundary in the platform team can be a forcing function for language correction, even though there will be a need for conscious effort from the platform team.
Special thanks to David Golden for his feedback on a previous version of this article.