Composable Solution Design: What It Is and Why It Matters

Miriam McCabe
Salesforce Architects

--

3D Blocks combined together to create a design

“A system architected to be composable is built in meaningful units […] that can operate gracefully with one another and can be easily swapped in and out of service. ” - Salesforce Well Architected Composable

Being able to swap components in and out of service easily is important because, as we all know, business objectives, business requirements, and the solutions needed to support the business change constantly. So how can you architect Salesforce solutions to be composable? This post will help you answer that question by walking through the mindset to adopt, as well as anti-patterns to avoid and ready-to-use best practices that will lead to composable Salesforce solutions capable of dealing with change gracefully.

Intentionally designing for composability

The first and most important point is setting your mindset to be intentional about composability. Simply put, you need to set out to create a composable solution design, because it is more difficult to refactor your solution and introduce composability later. Once you have established this as one of your key design principles, you can use the following guidelines to follow through.

Don’t skimp on discovery. Make sure that before you even think about design, you form a full picture of the business objectives, vision, and the key processes and capabilities required. Every time you find yourself in front of a stakeholder, be curious. What do they want to achieve? Why? What is holding them back? What would make them more productive? Use the power of “Why?” to get to the true requirements rather than just designing the solution that is being asked for.

Design before you build. Once you have a clear view of what the customer is trying to achieve from a business and process perspective, invest the time to design before you build. It is a myth that agile and design do not go hand in hand! Design can be iterative as well, and design is a key step that allows you to identify patterns, commonalities, and concepts.

The patterns you identify will form the building blocks of your composable units and will enable you to design for modularity. This approach to design will also help you to avoid implementing long sequential processes individually, and instead break them into subprocesses with orchestration.

Example of a clean process with no crossing lines, that fits into a screen.
Example of a clean process with no crossing lines, that fits into a screen. Source.

Plan for the future. And finally, no matter where you are in the process, ask yourself what is likely to change in the future and what would happen if it does? This is not an invitation to try to solve problems that may occur in the future, but rather a thought exercise to gently prod the solution direction you have in mind for weaknesses that can be easily avoided.

So, now you’ve started off with the right mindset by aiming for composability, you have a clear view of the objectives you are trying to achieve, and you are aware of repeatable patterns and concepts. Does that mean you’re there? It does not. Even with this solid pre-work completed, you still need to be mindful of anti-patterns that can prevent solutions from being composable.

Anti-patterns to look out for

  • It’s getting too complicated. If there is one thing that should make all alarm bells go off when working on designing a solution for customers it’s this one: It’s getting too complicated! How do you know it is getting too complicated? A good indicator for me is that whenever I leave my desk to grab a cup a coffee, I need to explain the logic to myself again and that takes a good few minutes. Another clear indicator is when your process flow no longer fits onto one screen, not even at 30%. In short, it just keeps on getting more complicated.
  • You’re implementing similar logic in multiple places. Whenever I find myself designing functionalities that seem distinct on the lowest level, but have many similarities a level up, I know that I need to take special care. The risk that I run here is that I am building separate implementations of logic that are nearly the same. Take for example the difference between an input validation for say an address and address completion. Functionally, these happen in different use cases, maybe at different places in a user journey. However, when building a solution for it, I can reuse the pieces that make a call to the address service. The only difference is that in the one case I return a yes/no value as output of the validation and in the other case I return a completed address. Because of the similarities, these slightly different use cases can be solved with the same logic applied slightly differently based on an input parameter.
  • You’re trying too hard; it’s supposed to be clear. The last anti-pattern is the nagging feeling that you are not working with Lego blocks that fit together to form the desired structure. Instead it feels more like trying to force a triangle into a round shape or forcing ill-fitting puzzle pieces together. There is no sense of clarity, and requirements and processes are just lists of functionalities without any logical and underpinning principles. Instead of having a limited number of concepts that can be applied in various circumstances, you are designing exception after exception.

When you see these anti-patterns, they are clear indications that not enough time has been spent understanding the problem. A true understanding of the problem goes hand in hand with a clear solution that favors simplicity and reuse and has organizing principles. Take away: If you are still in a place of chaos, spend more time with the problem until you find a solution that fits.

Composable best practices

So, now that you know how to be intentional about composability and what to look out for when designing solutions, let’s take a look at some concrete best practices to make your solution design (more) composable in the areas of automation, user experience, and permissions.

Composable automation

Automation comes to mind almost naturally when thinking about composability. This is probably because in automation there is a natural drive to structure and optimize reuse. Nevertheless, no matter how technical you are, designing composable automation starts with business process design. Use tools such as Lucidchart, Miro, or Elements.Cloud to draw the business processes together with your business stakeholders and use the visualizations to help identify groups of reusable logic that make sense for the business. Such groupings of logic are likely to be good candidates for subflows, or, depending on the scale and complexity of the logic, invocable methods.

Chain reusable pieces together to achieve your business processes, rather than building massive flows. To orchestrate your flows, use the trigger order (start with increments of 100 for your trigger order values so you can adjust easily later) or use flow orchestration. Last but not least, create a mapping of your flows in a diagramming tool that enables you to understand dependencies and which flows are calling each other for when the time comes to make changes.

Composable user experience

Ensure that you design discrete experiences. Functionalities that multiple audiences have in common may become underpinning logic and can be reused, for example, for both customer and employee experiences with different layouts or components. Resist the temptation to create a new record type for each process variation. Instead, use the power of dynamic forms together with custom permissions, and, if it is all becoming too complicated, don’t shy away from using LWCs that do exactly what need to be done.

Composable permissions

Last but not least, security and setting up a permissions structure that responds well to change is also an integral part of designing composable Salesforce solutions. Setting up Salesforce permission-based security for composability comes back to design: Spend time doing discovery and design and use this to identify and define the key personas that will be served with the solution. Next, assign permission sets to features that make up reusable blocks of functionality and group them together based on personas using permission set groups. Here, the art of the architect is to use the appropriate level of granularity to ensure that the permission set in itself does not become a monolith while at the same time avoiding assigning permissions on the object level. For very slight variations, in for example region or country level, consider using a muting permission set.

Finally, as with the dependencies between flows, find a way to document your permissions structure and setup in a level of detail that is suitable for your stakeholders. Your admins may think it is OK to take a look at the UAT environment, but to appease your legal teams and ensure appropriate role-based access control (RBAC) is in place, consider maintaining a separate administration or using a product that will help you report on the current state of your production org. There are several good products for this on AppExchange.

Next steps

Now that you have a deeper understanding of the importance of adopting a composable mindset and how to approach it — as well as anti-patterns to avoid — the next step is to get hands-on and use the best practices discussed here to introduce more composability into your solution designs.

--

--

Miriam McCabe
Salesforce Architects

Salesforce Architect since 2018. Salesforce CTA since 2022. Writes about the importance of business process in IT.