In this part, we will talk about the key characteristics of well-factored service architecture. We will provide high-level guidance on factoring services into business-truthful (refer to Part One for details), composable abstractions.
When talking about factoring services, we classify services into three different types.
Client experience services are responsible for providing the best experience tailored to a specific channel or client
Business capability services are typically end-user facing and deliver tangible value to the end user
Foundational capabilities rarely deliver tangible value to end users individually but their main purpose is to enable higher-order business capabilities
Let’s take an example. Find-in-Store enables customers to find a product in a store. This is an example of value being delivered to the end customer by a retail company. If we were to model services to support the Find-in-Store capability, you would have foundational capabilities such as Catalog, Inventory, and Store. The Catalog service provides capabilities like product search, the Inventory provides product availability and the Store provides store locator logic. If Find-in-Store is modeled as a business capability, it would use the Catalog service to find the product in the catalog, the Store service to locate the stores closest to the customer and then use the Inventory service to get the available inventory for that product in those stores. It essentially brings together the foundational capabilities to create tangible value for the customer.
Service composability—the value of classifying services
The reason we classify services, especially the foundational and business capabilities, is because to survive in a competitive market, new ways of delivering customer value must be created quickly. And to do so, foundational capabilities need to be built and maintained independent of existing business capabilities. By doing so, foundational capabilities can be composed easily to create new business offerings quickly.
For example, Product Recommendations as a business capability will be delivered on top of the same foundational capabilities like Catalog, Inventory, and Order. If the foundational capabilities were mangled with the Find-in-Store logic, they reduce the flexibility of those services and make it harder to quickly build new business capabilities, such as Product Recommendations.
Also, foundational capabilities need to evolve independently of the business capabilities that use them and vice versa. In the above example, the product search in Catalog service needs to evolve independently of the Find-in-Store capability, say, for example, to support a new product category.
One of the reasons why omnichannel capabilities have been so hard to deliver is because the foundational capabilities, such as Inventory, were not factored out as independent services. They were embedded deep in the eCommerce engine as opposed to being an independent building block used to build omnichannel capabilities like Find-in-Store.
Figure 1: New capabilities like Product Recommendations and Checkout on top of well-factored foundational capabilities
Guiding principles and anti-patterns for factoring services
Here are some guiding principles and some of the anti-patterns we have seen when building these type of services.
Foundational capability services
Core capabilities in the organization have the corresponding foundational capability. Core assets like Catalog, Store, Inventory, and Order should have the foundational capability to encapsulate the business logic and data around them. The foundational capabilities should serve as a system of record for these assets, providing data and logic consistency across various business capabilities. The inventory availability for a particular product should be the same, regardless of the business capability accessing it, whether that’s Product Recommendations or Find-in-Store. It’s important to invest in designing these services well and applying engineering rigor because they represent the fundamental building blocks of the business.
Foundational capability services need to support a wide variety of business capabilities. Foundational capabilities should be coarse-grained to best support a wide variety of business capabilities. They need to be free of business capability logic to enable spinning up of new business capabilities quickly. It’s also important to pay close attention to Service Level Objectives (SLOs) like latency and throughput to avoid one rogue business capability ruining the experience for the others.
Foundational capability act as a domain facade to legacy systems. In some cases, the system of record for a core asset is spread across various legacy systems. Here, the foundational capability is essentially a domain facade exposing a technology neutral, domain-centric interface for the asset to the rest of the organization. This helps to avoid leaking of the domain as well as technology complexity from the legacy systems such as legacy IDs, legacy names, legacy modes of processing data like file transfer into the rest of the organization.
Foundation capability logic is splintered across the organization. We’ve seen some of the foundational capabilities built to support one-off business scenarios without a cohesive vision. This results in duplication or splintering of the foundational capability in different business capabilities or legacy systems. Foundational capability services provide a natural home to host the logic and the complexity surrounding it in a single place so that it’s not repeated or implemented differently across the organization. For example, it’s important to have a single inventory service for the entire organization as opposed to having separate systems for the supply chain, eCommerce, and store divisions.
Anemic services. When building foundational services, it’s important that foundational services don’t become ‘anemic’ or CRUD. Foundational services aren’t just about the data that belongs to the asset, but also the logic surrounding the data. For example, inventory service contains not only the inventory data but logic to handle back-orders, store inventory reliability issues and supply chain optimization.
Over-speculative services. Foundational services need to support today's business capabilities and future ones. But, care should be taken to ensure they’re not overly speculative. Foundational services need to be built with the philosophy of ‘think long term, act short term’. Foundational services should still be driven primarily by today's business capabilities but flex easily, at least conceptually, to satisfy future needs.
Single model for the entire organization. Having foundational capabilities doesn’t mean having a single model shared by all the groups in the organization. Foundational capabilities encapsulate core data and logic for the capability. It doesn’t mean all the data surrounding a capability has to live in the capability. For example, the core data for a product like name, description and product search logic would sit in the catalog service. But the logic and data corresponding to its sales strategy—whether it gets sold as part of the store channel or the online channel—needs to be part of the commerce domain. Similarly, the distribution strategy—where a product gets stocked—should be part of the fulfillment domain.
Business capability services
Business capability services model business processes and own the business logic around those. As an example, Reserve-in-Store as a business capability enables a customer to reserve a product in a store. This business capability manages the entire workflow all the way from customer reserving the product online in a store, store associate being notified of it on their handheld device, store associate finding it on the shop floor, letting the customer know it is reserved for them, and ultimately the customer coming to the store to try it out or in the best case scenario buying the product. The business capability also has to manage all the failure scenarios such as store associate not finding the item or the customer not showing up. All the changes to the workflow and related user experience need to be managed carefully in one place for a delightful customer experience.
Business capabilities provide a seamless customer experience across all channels. The customer should be able to access the same Reserve-in-Store experience regardless of the channel they come from. The experience should also be seamless across channels. If the customer makes a reservation using a desktop application, they should be able to get notifications and check the status of the reservation on their mobile app which is the responsibility of the business capability service.
Business capability services are composable so as to enable sophisticated business offerings. Having a Find-in-Store capability makes it easier to build the Reserve-in-Store capability on top of it since the customer has to find an item in a store before they reserve it. The Find-in-Store capability hides the complexity of finding an item in a store, dealing with the vagaries of Inventory and Store services and frees the team building Reserve-in-Store to do other value add activities.
Experimentation is a first class concern of the business capability services. Typically, we’ve seen experimentation being used a lot for trying out new customer interactions—like page layout—which happen in the client experience services. But deep meaningful experimentation can only be done by re-imagining the workflows in the business capabilities. For example, the customer has used the Reserve-in-Store capability to reserve a product in a store. The business might want to experiment with certain promotions around matching items or specials going on at the store. If the customer reservation expires because of a no-show, they could be enticed to visit the store by offering discounted pricing. Business capabilities provide a natural home for these hosting these experiments and enabling innovation by managing the end-to-end user experience.
Missing abstraction for business capabilities. Too often we’ve seen business capability logic leak either into foundational services or get coupled with the presentation logic. When business capabilities span interactions across multiple foundational services, it is highly recommended to encapsulate its behavior in an independently evolvable service. We’ve seen complex checkout logic related to product recommendations, pricing, fraud detection, payment, product delivery being coupled to presentation logic. More importantly, it’s repeated across channel services, which causes inconsistent user experience. It’s best to have a common Checkout business capability to encapsulate the complexity of the process itself and then a client experience service for each channel to optimize the experience for the channel.
Client experience services
A special note on client experience services and their relationship to Backend for Frontend (BFF) pattern. We think BFFs fall into the client experience services category, as long as they contain pure presentation logic for the client and no business logic. We believe the phrase ‘client experience’ does a better job of explaining what we mean which is tailoring the business capability to best suit the needs of the client.
The client experience service supports the mode of expression that’s best suited to the client. Their primary responsibility is to deliver the best possible experience for the client. These services need to account for things like text or graphical nature of communication, the screen real estate, the network bandwidth available and client specific protocols. For instance, a voice-activated device gathers context in a different way than a small-screen mobile one. The back and forth of a voice conversation would be considered normal. But the same interaction would be onerous with a mobile device on the go, where you need quick access to the information you need.
Business/domain logic should not be present in these type of services. As an example, the checkout flow is modeled as a business capability with client experience services for the mobile and web channels. The business decides to offer a discount to customers using the mobile app for checkout. The discount percentage should live in the client experience service for mobile, but the actual discount calculation logic should live in the checkout business capability service. This means the discount logic is consistent across channels while providing the channels the freedom to choose their discount percentages.
Client experience services are optional. If the client needs aren’t vastly different than what the business capability offers, then you might not need an additional hop between the client and the business capability as long as it satisfies the performance, security and network topology requirements.
Correctness versus speed to market tradeoff
When building client experience service, correctness should be traded off for speed-to-market whereas when building foundational service, speed-to-market should be traded off for correctness. When building a SavingsAccount foundational capability, it’s extremely important to show the right balance and hence correctness is very important. On the other hand, launching a new experience for the Apple Watch to meet an aggressive marketing deadline, might mean quick turnaround time on building client experience services. In the case of the business capability, we recommend you consider speed-to-market as more important than correctness as business capability services are instrumental in enabling innovative experiences to customers quickly.
Figure 2: Correctness versus speed to market tradeoff
You might not get the service classification right the first time around
It’s likely you’ll experience some teething pain coming up with the right service classification. You’ll have to refactor your logic across the different service types as your understanding of the business evolves. We’ve seen from experience, the logic that is duplicated across multiple business capabilities either gets refactored into its own business capability or in a foundational service that’s best suited to hold the logic. Having a strong suite of end-to-end tests that span all the services involved can help make sure that the refactoring is successful. This has to be supplemented by light-weight governance which involves as much of education as supervision.
To be able to create business offerings quickly, it’s important to have business-truthful foundational and business capabilities that can be composed easily. Foundational capabilities represent core assets in the organization whereas business capabilities provide tangible value to end customers. The client experience services are responsible for providing the best possible experience to the client.
In Part Three, we’ll provide guidelines on defining service boundaries—whether it’s decomposing an existing monolith or building a brand new set of services.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.