CINXE.COM

Composable | Salesforce Architects

<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title> Composable | Salesforce Architects</title> <!-- One Trust --> <script async type="text/javascript" src="https://a.sfdcstatic.com/digital/one-trust/core/stable/scripttemplates/otSDKStub.js" data-domain-script="8e783e8c-0ad0-475d-8fca-4a03afa0a02a" crossorigin ></script> <!-- Data Cloud Manager --> <script type="text/javascript" src="https://cdn.c360a.salesforce.com/beacon/c360a/1264deb6-4cc0-4a48-b265-ce707a286cfd/scripts/c360a.min.js" defer></script> <!-- Google Tag Manager --> <script> (function (w, d, s, l, i) { w[l] = w[l] || []; w[l].push({'gtm.start': new Date().getTime(), event: 'gtm.js'}); var f = d.getElementsByTagName(s)[0], j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : ''; j.async = true; j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; f .parentNode .insertBefore(j, f); })(window, document, 'script', 'dataLayer', 'GTM-MPDHG6B'); </script> <!-- End Google Tag Manager --> <link rel="apple-touch-icon" sizes="180x180" href="/1/asset/immutable/s/17304959070000000/assets/images/favicons/apple-touch-icon.png"> <link rel="icon" type="image/png" sizes="32x32" href="/1/asset/immutable/s/17304959070000000/assets/images/favicons/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="16x16" href="/1/asset/immutable/s/17304959070000000/assets/images/favicons/favicon-16x16.png"> <link rel="manifest" href="/1/asset/immutable/s/17304959070000000/assets/site.webmanifest" crossorigin="use-credentials"> <link rel="mask-icon" href="/1/asset/immutable/s/17304959070000000/assets/images/favicons/safari-pinned-tab.svg" color="#5bbad5"> <link rel="shortcut icon" href="/1/asset/immutable/s/17304959070000000/assets/images/favicons/favicon.ico"> <link rel="canonical" href="https://architect.salesforce.com/well-architected/adaptable/composable"/> <meta name="google-site-verification" content="9nBLHedRs97kceoTtOMsUGrVIhNfsJHbExzaKVARgAM"> <meta name="google-site-verification" content="GiaTqJgaiTF7nPD6gVxphfKcgFK9leNVs5Wp4mpqoGc"/> <meta name="msapplication-TileColor" content="#da532c"> <meta name="msapplication-config" content="/assets/browserconfig.xml"> <meta name="theme-color" content="#ffffff"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta property="og:url" content="https://architect.salesforce.com/well-architected/adaptable/composable"> <meta property="og:type" content="website"> <meta name="author" content="Salesforce Architects"> <meta name="title" property="og:title" content="Salesforce Architects | Composable"> <meta name="description" property="og:description" content="Build Salesforce solutions in units that handle change well."> <meta name="image" property="og:image" content="https://architect.salesforce.com/assets/images/cards/composable.png"> <meta property="og:image:url" content="https://architect.salesforce.com/assets/images/cards/composable.png"> <meta name="twitter:image" content="https://architect.salesforce.com/assets/images/cards/composable.png"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:site" content="@SalesforceArchs"> </script> <link rel="preload" href="/1/asset/immutable/s/17304959070000000/assets/css/styles.css" as="style"> <link rel="stylesheet" href="/1/asset/immutable/s/17304959070000000/assets/css/styles.css"> <link rel="preload" href="/1/asset/immutable/s/17304959070000000/assets/dx/css/index.css" as="style"> <link rel="stylesheet" href="/1/asset/immutable/s/17304959070000000/assets/dx/css/index.css"> <style> .preview { width: 100%; display: flex; align-items: center; justify-content: center; background-image: linear-gradient(45deg,rgba(0,0,0,.025) 25%,transparent 0,transparent 50%,rgba(0,0,0,.025) 0,rgba(0,0,0,.025) 75%,transparent 0,transparent); background-size: 64px 64px; color: #102c62; background-color: rgb(234, 245, 254); padding: 8px; box-sizing: border-box; } .preview a:active, .preview a:hover, .preview a:link, .preview a:visited { color: #0071D1; } .preview > span { padding: 0 6px; } </style> </head> <body> <header> <tds-header config="{&quot;logo&quot;:{&quot;assistiveText&quot;:&quot;Salesforce Architects logo&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/&quot;},&quot;url&quot;:&quot;/assets/images/architects_logo_vertical.svg&quot;},&quot;logoMobile&quot;:{&quot;assistiveText&quot;:&quot;Salesforce Architects logo&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/&quot;},&quot;url&quot;:&quot;/assets/images/architects_logo_vertical.svg&quot;},&quot;header&quot;:[{&quot;label&quot;:&quot;Home&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/&quot;,&quot;target&quot;:null},&quot;active&quot;:true},{&quot;label&quot;:&quot;Well-Architected&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Build trusted, easy and adaptable solutions&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Well-Architected Overview&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/well-architected/overview&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/overview-icon.svg&quot;,&quot;description&quot;:&quot;Build healthy solutions&quot;},{&quot;label&quot;:&quot;Trusted&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/well-architected/trusted/overview&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/trusted-icon.svg&quot;,&quot;description&quot;:&quot;Protect your business and stakeholders&quot;},{&quot;label&quot;:&quot;Easy&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/well-architected/easy/overview&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/easy-icon.svg&quot;,&quot;description&quot;:&quot;Deliver value fast&quot;},{&quot;label&quot;:&quot;Adaptable&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/well-architected/adaptable/overview&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/adaptable-icon.svg&quot;,&quot;description&quot;:&quot;Evolve with your business&quot;}]},{&quot;label&quot;:&quot;Well-Architected Tools&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Pattern &amp; Anti-Pattern Explorer&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/well-architected/explorer&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/roadmap-explorer.svg&quot;,&quot;description&quot;:&quot;Create lists of patterns or anti-patterns&quot;}]}]},{&quot;label&quot;:&quot;Diagrams&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Create and find artifacts for your solutions&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Salesforce Diagrams Overview&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/diagrams/#framework&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/salesforce-diagram-framework.svg&quot;,&quot;description&quot;:&quot;Learn how to create effective diagrams&quot;},{&quot;label&quot;:&quot;Reference Architecture Gallery&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/diagrams/#reference-architecture-gallery&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/template-gallery.svg&quot;,&quot;description&quot;:&quot;Pre-built artifacts to get started fast&quot;},{&quot;label&quot;:&quot;Data Model Gallery&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/diagrams/#data-model-gallery&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/design-patterns.svg&quot;,&quot;description&quot;:&quot;Product entity relationship diagrams&quot;}]}]},{&quot;label&quot;:&quot;Decision Guides&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Choose the right Salesforce tools&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Asynchronous Processing&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides/async-processing&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/Asynchronous-Processing-Decision-Guide.svg&quot;,&quot;description&quot;:&quot;Architect&#39;s Guide to Asynchronous Processing with Salesforce&quot;},{&quot;label&quot;:&quot;Event-Driven Architecture&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides/event-driven&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/event-driven-architecture.svg&quot;,&quot;description&quot;:&quot;Architect&#39;s Guide to Event-Driven Architecture with Salesforce&quot;},{&quot;label&quot;:&quot;Data Integration&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides/data-integration&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/data-integration.svg&quot;,&quot;description&quot;:&quot;Architect&#39;s Guide to Data Integration with Salesforce&quot;},{&quot;label&quot;:&quot;Record-Triggered Automation&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides/trigger-automation&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/record-triggered-automation.svg&quot;,&quot;description&quot;:&quot;Architect&#39;s Guide to Record-Triggered Automation on Salesforce&quot;},{&quot;label&quot;:&quot;Building Forms&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides/build-forms&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/building-forms.svg&quot;,&quot;description&quot;:&quot;Architect&#39;s Guide to Building Forms on Salesforce&quot;},{&quot;label&quot;:&quot;See All Guides&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/decision-guides&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/decision-guides.svg&quot;}]}]},{&quot;label&quot;:&quot;Fundamentals&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Know the basics of Salesforce architecture&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;The Salesforce Platform - Transformed for Tomorrow&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/fundamentals/platform-transformation&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/next-gen-salesforce-platform.svg&quot;,&quot;description&quot;:&quot;Learn about the latest Salesforce Platform innovations&quot;},{&quot;label&quot;:&quot;Architecture Basics&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/fundamentals/architecture-basics&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/architecture-basics.svg&quot;,&quot;description&quot;:&quot;Learn basics of architecting with Salesforce&quot;},{&quot;label&quot;:&quot;Platform Multitenant Architecture&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/fundamentals/platform-multitenant-architecture&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/platform-mulitenant-architecture.svg&quot;,&quot;description&quot;:&quot;Learn about the architecture of Salesforce Customer 360 Platform&quot;},{&quot;label&quot;:&quot;Platform Sharing Architecture&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/fundamentals/platform-sharing-architecture&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/sharing-guide.svg&quot;,&quot;description&quot;:&quot;Learn how to provide secure data access&quot;},{&quot;label&quot;:&quot;See All Fundamentals&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/fundamentals&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/decision-guides.svg&quot;}]}]},{&quot;label&quot;:&quot;Resources&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Project Resource Gallery&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Artificial Intelligence&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/resources/project-resource-gallery/ai&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/template-gallery.svg&quot;,&quot;description&quot;:&quot;Get AI projects started fast&quot;}]},{&quot;label&quot;:&quot;Releases&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Release Overviews&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/releases&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/releases.svg&quot;,&quot;description&quot;:&quot;Explore what&#39;s changed across releases&quot;}]},{&quot;label&quot;:&quot;Roadmap Explorer&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Roadmap Explorer&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/roadmaps/roadmap-explorer&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/nav/roadmap-explorer.svg&quot;,&quot;description&quot;:&quot;Plan in alignment with Salesforce innovation&quot;}]}]},{&quot;label&quot;:&quot;Connect&quot;,&quot;sections&quot;:[{&quot;label&quot;:&quot;Connect with Salesforce Architects&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Our Blog&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;/connect/blog&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/images/architects_logo_vertical.svg&quot;,&quot;description&quot;:&quot;A tech publication for architects&quot;},{&quot;label&quot;:&quot;Our Youtube Channel&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;https://www.youtube.com/c/SalesforceArchitects&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},&quot;iconUrl&quot;:&quot;/assets/images/nav-youtube.png&quot;,&quot;description&quot;:&quot;Videos to empower and inspire architects&quot;},{&quot;label&quot;:&quot;Trailblazer Community&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;https://trailblazer.salesforce.com/about&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},&quot;iconUrl&quot;:&quot;/assets/images/nav-community-groups.png&quot;,&quot;description&quot;:&quot;Get help, answers, and inspiration from peers&quot;}]},{&quot;label&quot;:&quot;Stay up to date with our feeds&quot;,&quot;items&quot;:[{&quot;label&quot;:&quot;Our Website Feed&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;https://architect.salesforce.com/feed.xml&quot;,&quot;target&quot;:null},&quot;iconUrl&quot;:&quot;/assets/icons/rss.png&quot;,&quot;description&quot;:&quot;Get new diagrams and content updates&quot;},{&quot;label&quot;:&quot;Our Blog Feed&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;https://medium.com/feed/salesforce-architects&quot;,&quot;target&quot;:&quot;noopener&quot;},&quot;iconUrl&quot;:&quot;/assets/icons/rss-black.png&quot;,&quot;description&quot;:&quot;Our latest blogs delivered&quot;},{&quot;label&quot;:&quot;Our Youtube Channel Feed&quot;,&quot;link&quot;:{&quot;href&quot;:&quot;https://www.youtube.com/feeds/videos.xml?channel_id=UC9OaSDoddWJ7Zwu83nANsCA&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},&quot;iconUrl&quot;:&quot;/assets/icons/rss-red.png&quot;,&quot;description&quot;:&quot;Subscribe for video updates&quot;}]}]}],&quot;footer&quot;:{&quot;columns&quot;:[{&quot;heading&quot;:&quot;Well-Architected&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/well-architected/overview&quot;,&quot;label&quot;:&quot;Overview&quot;},{&quot;href&quot;:&quot;/well-architected/trusted/overview&quot;,&quot;label&quot;:&quot;Trusted&quot;},{&quot;href&quot;:&quot;/well-architected/easy/overview&quot;,&quot;label&quot;:&quot;Easy&quot;},{&quot;href&quot;:&quot;/well-architected/adaptable/overview&quot;,&quot;label&quot;:&quot;Adaptable&quot;},{&quot;href&quot;:&quot;/well-architected/explorer&quot;,&quot;label&quot;:&quot;Pattern &amp; Anti-Pattern Explorer&quot;}]},{&quot;heading&quot;:&quot;Diagrams&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/diagrams/#framework&quot;,&quot;label&quot;:&quot;Salesforce Diagrams Overview&quot;},{&quot;href&quot;:&quot;/diagrams/#reference-architecture-gallery&quot;,&quot;label&quot;:&quot;Reference Architecture Gallery&quot;},{&quot;href&quot;:&quot;/diagrams/#data-model-gallery&quot;,&quot;label&quot;:&quot;Data Model Gallery&quot;}]},{&quot;heading&quot;:&quot;Decision Guides&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/decision-guides/event-driven&quot;,&quot;label&quot;:&quot;Event-Driven Architectures&quot;},{&quot;href&quot;:&quot;/decision-guides/data-integration&quot;,&quot;label&quot;:&quot;Data Integration&quot;},{&quot;href&quot;:&quot;/decision-guides/trigger-automation&quot;,&quot;label&quot;:&quot;Record-Triggered Automation&quot;},{&quot;href&quot;:&quot;/decision-guides/build-forms&quot;,&quot;label&quot;:&quot;Building Forms&quot;},{&quot;href&quot;:&quot;/decision-guides&quot;,&quot;label&quot;:&quot;See All Guides&quot;}]},{&quot;heading&quot;:&quot;Fundamentals&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/fundamentals/platform-transformation&quot;,&quot;label&quot;:&quot;Platform Transformation&quot;},{&quot;href&quot;:&quot;/fundamentals/architecture-basics&quot;,&quot;label&quot;:&quot;Architecture Basics&quot;},{&quot;href&quot;:&quot;/fundamentals/platform-multitenant-architecture&quot;,&quot;label&quot;:&quot;Platform Multitenant Architecture&quot;},{&quot;href&quot;:&quot;/fundamentals/platform-sharing-architecture&quot;,&quot;label&quot;:&quot;Plaform Sharing Architecture&quot;}]},{&quot;heading&quot;:&quot;Resources&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/resources/project-resource-gallery/ai&quot;,&quot;label&quot;:&quot;Project Resource Gallery&quot;},{&quot;href&quot;:&quot;/roadmaps/roadmap-explorer&quot;,&quot;label&quot;:&quot;Roadmap Explorer&quot;},{&quot;href&quot;:&quot;/releases&quot;,&quot;label&quot;:&quot;Release Overviews&quot;}]},{&quot;heading&quot;:&quot;Connect&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/connect/blog&quot;,&quot;label&quot;:&quot;Our Blog&quot;},{&quot;href&quot;:&quot;https://www.youtube.com/c/SalesforceArchitects&quot;,&quot;label&quot;:&quot;Our Youtube Channel&quot;},{&quot;href&quot;:&quot;https://trailblazer.salesforce.com/about&quot;,&quot;label&quot;:&quot;Trailblazer Community&quot;}]}],&quot;global&quot;:{&quot;logo&quot;:{&quot;assistiveText&quot;:&quot;Salesforce Logo&quot;,&quot;url&quot;:&quot;/assets/images/salesforce-corp-logo.jpg&quot;},&quot;copyrightTitle&quot;:&quot;© Copyright 2024 Salesforce, Inc. &quot;,&quot;copyrightEnd&quot;:&quot; Various trademarks held by their respective owners. Salesforce, Inc. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/&quot;,&quot;label&quot;:&quot;Legal&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/sfdc-website-terms-of-service/&quot;,&quot;label&quot;:&quot;Terms of Service&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/privacy/&quot;,&quot;label&quot;:&quot;Privacy Information&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/disclosure/&quot;,&quot;label&quot;:&quot;Responsible Disclosure&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://trust.salesforce.com/&quot;,&quot;label&quot;:&quot;Trust&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/contact-us/?d=cta-glob-footer-11&quot;,&quot;label&quot;:&quot;Contact&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/form/other/privacy-request/&quot;,&quot;label&quot;:&quot;Your Privacy Choices&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;,&quot;icon&quot;:&quot;/assets/images/privacyicon.png&quot;}]}}}"> <tds-search slot="search"></tds-search> </tds-header> </header> <div class="guide"> <tm-page-header-a title="Composable" jptranslation="https://sf-archs.cdn.salesforce-experience.com/cms/delivery/media/MCKOO24WLCIZGV7HOB5HAUHGUFQQ?version=2.1&amp;channelId=0apHs000000y0QG&amp;oid=00DHs000003Wrxy" url="/well-architected/adaptable/composable"></tm-page-header-a> <tm-content reading-time="30" last-updated="July 2024" image-hash="7mkom"> <blockquote> <p>Read about our update schedules <a href="../contributors">here</a>.</p> </blockquote> <h2 id="introduction">Introduction</h2> <p>Composable solutions adjust quickly and with greater stability. A system architected to be composable is built in meaningful units, or building blocks, that can operate gracefully with one another and can be easily swapped in and out of service. Building composability into a system enables you to introduce new features or remove technical debt by refactoring or reassembling individual units of a system. Composability enables faster, more predictable delivery cycles and releases, as teams can focus on building and delivering meaningful features via smaller amounts of change.</p> <p>Composable systems make it possible for businesses to adapt more quickly and with greater stability — whether the stimulus is internal to the business or caused by external factors. Composability helps systems be more <a href="/../well-architected/adaptable/resilient">resilient</a> and can help make solutions and architectural patterns more <a href="/../well-architected/easy/intentional">intentional</a>.</p> <p>You can make your Salesforce solutions more composable by building three key habits: separation of concerns, interoperability, and packageability. Below, you can see the relationship of these habits in two ways: for a single unit of in a composable system, and across multiple units in a composable system.</p> <p><b>A single, composable unit:</b></p> <a href="/assets/images/composable-capabilities.jpeg" target="_blank"> <img style="border:1px solid #e5e5e5;margin:2rem 0rem;width:50%;" src="/1/asset/immutable/s/17304959070000000/assets/images/composable-capabilities.jpeg" alt="This is a diagram showing how the topics in composable relate through three nested cards. The innermost card is a functional unit, the next layer is interoperability, and the outer layer is packagability."> </a> <p><b>A composable system:</b></p> <a href="/assets/images/composable-multi-package-capabilities.jpeg" target="_blank"> <img style="border:1px solid #e5e5e5;margin:2rem 0rem" src="/1/asset/immutable/s/17304959070000000/assets/images/composable-multi-package-capabilities.jpeg" alt="This is a diagram showing how the topics in composable relate through three nested cards. The innermost card is a functional unit, the next layer is interoperability, and the outer layer is packagability."> </a> <h2 id="separation-of-concerns">Separation of Concerns</h2> <p>A fundamental concept in software engineering and system architecture, <em>separation of concerns</em> entails identifying various concerns within a larger system that can be separated into modular units. Achieving a strong separation of concerns within a system requires the creation of meaningful units for application logic and functions throughout the system. Smaller units make it easier for app delivery and maintenance teams to understand how and where to make changes, with minimal disruption to the larger system. Smaller units also make it clearer how and where to focus work when addressing <a href="/../well-architected/easy/intentional#Technical_Debt">technical debt</a> and contribute to the overall <a href="/../well-architected/easy/intentional#Readability">readability</a> of your system.</p> <p>You can build better separation of concerns into your Salesforce org by orienting to business capability and managing state.</p> <h3 id="functional-units">Functional Units</h3> <p>For Salesforce systems, the best approach for separation of concerns applies a business-oriented perspective to identify and organize modular units (or capabilities) within the system. This is unlike an engineering-focused view, which identifies units based on their technical function. A business-oriented perspective in separation of concerns requires organizing the code and customizations in your system based on the service they provide to the business and business users. Taking this approach does not mean ignoring potential for redundant or duplicative technical functions in a system. Rather, it means that technical services are clearly mapped to an organizing principle that is ultimately transparent to the business.</p> <p>Orienting to business capabilities helps ensure that the hand-offs between business analysis and discovery teams to delivery teams are as straightforward as possible. If app builders have no idea where their work units map into your composable architecture, you have a mess, not a composable app landscape. Unclear mappings between the end state required by the business and the modular units within an org also increase the chances of development teams or vendors building redundant functions into the system.</p> <p>Consider the following to orient functional units to business capability:</p> <ul> <li><strong>Start with jobs to be done</strong>. Focus on the jobs to be done (JTBD) of users and the business itself. Pioneered by Tony Ulwick, the JTBD approach centers on understanding the “job,” or true purpose, that people are trying to accomplish by using a product or service. It’s a higher level of abstraction than users’ role-related tasks or the individual steps in a business process. For example, tasks like duplicate checks and address validations might fall into a higher-order function of “establish a single view of the customer.” After you have a clear sense of these higher-order business capabilities, you can begin to map parts of your system to them.</li> <li><strong>Orient to capabilities, not reporting structures</strong>. The internal hierarchy of your business units are not a proxy for meaningful capabilities or jobs to be done. The internal hierarchy of your business does have material impact on processes and team structures (not to mention budgets). Those are important logistical considerations. But the functional needs of the business operate at a higher level of abstraction than logistics. If you are creating a module to serve a reporting structure instead of a higher-order function, be aware that you may have to take additional steps to identify how that module relates to business capabilities.</li> <li><strong>Be iterative</strong>. Start by partnering with the business to identify what capability could work for a minimum viable product (MVP). When you identify a capability, start building that MVP. As you build, identify the processes, metadata, and <a href="/../well-architected/adaptable/composable#Messaging_and_Eventing">events or messages</a> that are central to the functional unit you are creating. Identify any processes, metadata, and events or messages that are external dependencies. As more functional units are designed, implement <a href="/../well-architected/adaptable/composable#API_Management">API management</a> and <a href="/../well-architected/adaptable/composable#Dependency_Management">dependency management</a> to build units that work well with one another (instead of building siloed units).</li> </ul> <p>The list of <a href="/../well-architected/adaptable/composable#Separation_of_Concerns_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) orientation to business function looks like within a Salesforce solution. You can use these to validate your designs before you build, or identify areas of your system that need to be refactored.</p> <p>To learn more about tools available from Salesforce to help you better orient to business capabilities, see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>.</p> <h3 id="state-management">State Management</h3> <p>State management centers on movement of information throughout a system at various points in time. Effective state management enables applications to handle complex flows of data or interactions with a minimum of unplanned or indeterminate outcomes. Managing state in a modular Salesforce org means building clear paths for logic flows within and between units, as well as graceful paths for unplanned execution behaviors. State management makes it possible to form coherent streams of logic from modular Salesforce application units. In most cases, this requires <a href="/../well-architected/adaptable/composable#Interoperability">interoperability</a> to structure information flow between units.</p> <p>Difficulties in managing state across loosely coupled units often lead to monolithic application development in Salesforce. You can see this in large “monoflows", which are built in an attempt to orchestrate a complex process within a singular flow. Another example is massive Apex classes, which orchestrate complex processes through <em>spaghetti code</em>, or a lengthy series of single-use methods. These types of application architectures make refactoring and debugging difficult and increase onboarding times for new team members or vendors. They also reduce the value of the applications delivered to the business, as functionality isn’t reusable.</p> <p>Consider the following to manage state across a modular Salesforce org:</p> <ul> <li><strong>Decide on when to use stateful versus stateless patterns</strong>. Stateful patterns retain information throughout an execution path, stateless patterns do not. In a loosely coupled system, stateless patterns make it possible for components to be refactored more quickly and with fewer side effects. However, stateless patterns are not appropriate for all use cases. If you are building components for data operations, stateful patterns can help with data integrity and consistency throughout your systems. Use a stateful pattern if your component meets any of the following criteria: <ul> <li>Awareness of placement within a greater execution path is essential to the component’s behavior</li> <li>The behavior of the component needs to change based on the results of a downstream action (for example, it needs to change execution based on rollback/error/success messages from downstream components)</li> <li>The component needs to wait for responses from an external or downstream system to finish its work</li> </ul> </li> <li><strong>Create meaningful categories for stateful information</strong>. <em>State</em> is an ambiguous term that can be applied to such a deep and wide array of information within (and beyond) a Salesforce org that by itself the term is almost meaningless. A necessary first step to building stateful patterns, therefore, is creating <em>meaningful</em> categories for the most important stateful execution paths (or kinds of stateful behaviors) within your system. Some categories to consider: <ul> <li>Navigation and forms</li> <li>Database operations</li> <li>Batch and bulk operations</li> <li>Errors</li> </ul> </li> <li><strong>Define data-related states in terms of <a href="/../fundamentals/architecture-basics#Database_Manipulation">database transactions</a></strong>. The built-in behaviors of the platform will circumscribe the majority of state considerations for data in Salesforce. Don’t try to manage against or around this behavior. Design for and with it. Design solutions that minimize, or eliminate, distributed transaction logic. (See <a href="/../well-architected/easy/automated#Data_Handling">data handling</a> for more details).</li> <li><strong>Identify states that occur within (and across) functional units</strong>. As you assemble functional units into larger systems, be aware of when you’re mixing stateless and stateful component behavior, and prevent combinations that might create endless loops or gaps in processing.</li> <li><strong>Define hand-offs</strong>. Consider what <a href="/../well-architected/adaptable/composable#Messaging_and_Eventing">messaging or eventing</a> patterns components will use to transmit state-related data to another part of the system. Ensure you are building transaction awareness and <a href="/../well-architected/easy/automated#Data_Handling">handling</a> into your components. Do not include any distributed transaction logic in your hand-offs.</li> <li><strong>Create mappings between your process diagrams and states</strong>. Process diagrams detail the steps that move information through your system at various points in time. A state diagram shows the actual changes in the information (the state). Use the metadata footer portion of the <a href="/../diagrams/framework/kit-of-parts">Salesforce Diagrams</a> shapes to capture the changing state of information within each step of your process. If you separate process diagrams and state diagrams, be sure to link them. This concept should not be confused with capturing current and future state of processes or system landscapes during design and implementation, as that is not about the information moving through the system.</li> </ul> <p>The list of <a href="/../well-architected/adaptable/composable#Separation_of_Concerns_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) state management looks like within a Salesforce solution. You can use these to validate your designs before you build, or identify places in your system that need to be refactored.</p> <p>To learn more about Salesforce tools for managing state, see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>.</p> <h3 id="separation-of-concerns-patterns-and-anti-patterns">Separation of Concerns Patterns and Anti-Patterns</h3> <p>The following table shows a selection of patterns to look for (or build) in your org and anti-patterns to avoid or target for remediation.</p> <p>✨ Discover more patterns for separation of concerns in the <a href="/../well-architected/explorer?Adaptable=Separation+of+Concerns">Pattern &#x26; Anti-Pattern Explorer</a>.</p> <table> <colgroup> <col span="1" style="width: 10%;"> <col span="1" style="width: 45%;"> <col span="1" style="width: 45%;"> </colgroup> <tbody> <tr> <th scope="colgroup"></th> <th scope="colgroup">Patterns</th> <th scope="colgroup">Anti-Patterns</th> </tr> <tr> <td rowspan="3"><b>Functional Units</b></td> <td><b>In your design standards:</b> <br> - Naming conventions address how to denote a functional unit <br> - A list of all currently defined functional units (and related naming conventions) exists <br> - Standards for proposing functional unit additions or changes exist</td> <td><b>In your design standards:</b> <br> - Design standards do not exist or do not deal with functional units and use cases </td> </tr> <tr> <td><b>In your documentation:</b> <br> - System landscape diagrams clearly show the functional units in an org <br> - All documentation and implementation diagrams clearly show the functional unit(s) for components <br> - Documentation for individual components include functional unit mapping for the component <br> - All components within a functional unit are searchable and easy to find </td> <td><b>In your documentation:</b> <br> - Component documentation does not exist <br> - Component documentation describes the functional unit a component belongs to, but that is the only place the definition of that functional unit appears <br> - You cannot search for a particular functional unit and/or searches do not help identify all the components within a functional unit </td> </tr> <tr> <td><b>In your org:</b> <br> - It is possible to quickly identify functional unit alignment for a given piece of metadata (for example, a flow, Apex class, or Lightning page) <br> - Functional units are labelled in business-friendly terms </td> <td><b>In your org:</b> <br> - It is not possible to identify functional unit alignment for any metadata <br> - Functional unit information is inconsistent or inaccurate <br> - Functional unit information is labelled in engineering-focused terms that are meaningless to business users </td> </tr> <tr> <td rowspan="4"><b>State Management</b></td> <td><b>In your design standards:</b> <br> - Use cases for stateful vs. stateless designs are clear <br> - Approved patterns for stateless communication exist <br> - Approved patterns for stateful communication exist <br> - Clear categories for state exist </td> <td><b>In your design standards:</b> <br> - Design standards do not exist or do not deal with state/stateless patterns and use cases </td> </tr> <tr> <td><b>In your documentation:</b> <br> - Every component that handles stateful and/or stateless communication indicates what pattern has been implemented <br> - It is possible to search for and find all components that have implemented a particular stateful/stateless pattern <br> - Process and interaction diagrams provide detail about state categories and hand-offs </td> <td><b>In your documentation:</b> <br> - Component documentation does not exist <br> - Component documentation describes the stateful/stateless pattern implemented, but that is the only place the definition appears <br> - It is not possible to search for a particular pattern and/or searches do not help identify all the components using that pattern </td> </tr> <tr> <td><b>In Apex:</b><br> - Savepoints and rollback behaviors are used in all data operations</td> <td><b>In Apex:</b><br> - Savepoints and rollback behaviors are not used</td> </tr> <tr> <td><b>In Flow:</b><br> - Fault paths and the Roll Back Records element is used</td> <td><b>In Flow:</b><br> - The Roll Back Records element is not used</td> </tr> </tbody> </table> <h2 id="interoperability">Interoperability</h2> <p>In a system architected for interoperability, components can exchange information and operate together effectively. Interoperability is a key to making a modular system composable rather than siloed. Interoperability can be difficult to achieve in a <a href="/../well-architected/adaptable/composable#Loose_Coupling">loosely coupled</a> system. You need to establish standards for consistent methods of integration that don’t undermine the independence between units and overall <a href="/../well-architected/adaptable/composable#Separation_Of_Concerns">separation of concerns</a> across the system.</p> <p>Interoperability also impacts the quality of your user experiences. Your users expect data created in one area (like order information) to be usable in another (like marketing campaigns), and your builders expect that if they learn how to do something (like build a flow, or authenticate to an API) that they’ll find familiar techniques work when they move on to the next problem. Failing to design for interoperability will result in redundant architectures, replicated data, process inefficiencies, and increased development and support costs.</p> <p>You can create interoperability in modular systems with messaging and eventing as well as with API management.</p> <h3 id="messaging-and-eventing">Messaging and Eventing</h3> <p>Messages and events are two ways you can enable components across a system to send and receive information. In terms of the content they can carry, events and messages are similar. A key difference is the behavior of the sender. A component sending a <em>message</em> typically sends data to a specific destination, and awaits some kind of response from the recipient. In contrast, a component emits an <em>event</em> when something has happened. There is no specific destination, nor an expectation of a response. These differences in behavior support different communication patterns. Messages support stateful communication patterns, and events support stateless communication patterns. (See <a href="/../well-architected/adaptable/composable#State_Management">State Management</a> for more about this distinction.)</p> <p>It’s important to align teams on protocols and use cases for messaging and eventing. Unclear standards can result in a mix of patterns across your system, leading to:</p> <ul> <li>Performance and scalability issues where the wrong patterns are applied to a specific use case</li> <li>Inconsistent processing that makes the system appear unstable to end users</li> <li>Longer troubleshooting times and more complex maintenance processes</li> </ul> <p>Consider the following when designing messages and events to create more loosely coupled structures within your Salesforce org:</p> <ul> <li><strong>Identify sync and async use cases</strong>. Eventing allows for loosely coupled, stateless, and asynchronous communications across a system. Messaging allows for more tightly controlled, stateful, and synchronous patterns of communication. When deciding when to use messages or events, you need to decide if your communication needs to be synchronous (and potentially blocking) versus asynchronous and non-blocking.</li> <li><strong>Define data structures carefully</strong>. The structure of the information that components pass between them is an important part of keeping a loosely coupled system manageable and coherent. (See <a href="/well-architected/adaptable/composable#API_Management">API Management</a> for more on this.) A key consideration when designing a message or event is how often the structure of the information may need to change. Once a message or event structure is defined and implemented in your system, it can be difficult to handle updates — especially if the event or message is already being used to send information to an external system.</li> <li><strong>Right-size messages</strong>. In general, it is a best practice to keep message sizes small. However, there is also a balancing act between message <em>size</em> and message <em>volume</em>. Systems can process smaller amounts of data more quickly. The act of processing comes with an amount of additional overhead as recipients have to unpack, interpret, and determine what to do with information they’ve received. These steps may take a negligible amount of time to complete, but they can build up and create a burden on systems at scale. Avoid designs that require components in the system to process many small messages in succession to complete a piece of work. To right-size your messages, think about designing for the minimum data downstream components will need to successfully process and act on information they’ve been sent, without also assuming every downstream component will be capable of requesting or processing numerous follow-on messages.</li> <li><strong>Design for scalability</strong>. Loosely coupled components can make it easier to scale your architecture. Eliminating cross-component dependencies enables teams to work on improving performance or scalability of any individual component with minimal effects on the others. However, loosely coupled components also introduce significant complexity into your architecture at scale (especially when it comes to <a href="/../well-architected/adaptable/composable#State_Management">managing state</a>). Identify processes that need to have more tightly coupled logic or dependencies for valid user experience or data integrity reasons — and don’t attempt to introduce async/event-based patterns into those processes. Use sync/message-based patterns and proper error handling instead.</li> </ul> <p>The list of <a href="/../well-architected/adaptable/composable#Interoperability_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) messaging and eventing looks like within a Salesforce solution. You can use these to validate your designs before you build, or identify places in your system that need to be refactored.</p> <p>To learn more about Salesforce messaging and eventing tools,see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>. For more on choosing an eventing pattern or tool for a given use case, see the <a href="/../decision-guides/event-driven#Key_Takeaways">Architect’s Guide to Event-Driven Architecture with Salesforce</a>.</p> <h3 id="api-management">API Management</h3> <p>Building proper application programming interface (API) management within a Salesforce solution enables individual components of your system follow predictable communication patterns. Salesforce provides built-in, secure APIs to use for communication with systems outside Salesforce. (For more on Salesforce Platform APIs see <a href="/../fundamentals/architecture-basics#Platform_APIs">Architecture Basics</a>.)</p> <p>Effective API management within Salesforce solutions is key to building truly composable architectures. It enables components inside a Salesforce org to send and receive information efficiently. It also enables solution builders to follow clear protocols for how the components they build communicate with other components in the system, and helps them identify poor implementations early. Further, it enables solution builders to more narrowly focus on the particular component they are building or refactoring, which boosts productivity and quality.</p> <p>API Management at the enterprise level is a separate topic — and is best achieved with a comprehensive API Management tool. (For more on the MuleSoft perspective on this topic, see <a href="https://www.mulesoft.com/resources/api/what-is-api-management#:~:text=API%20management%20is%20the%20process,create%20are%20consumable%20and%20secure.">What is API Management?</a>.)</p> <p>Consider the following to build API management capabilities within your Salesforce solutions:</p> <ul> <li> <p><strong>Think of APIs as <em>predictable</em> patterns or contracts for communication</strong>. The data type of input or output variables, variable names, the pieces of information that should (or should not) appear in a given pattern — these are the keys to effective API management. These definitions should appear in your design standards, and teams should be able to find out how these definitions have been implemented in particular parts of your system via your documentation. One way to view difficulties merging changes from new development into an integration environment is to look at them as evidence of where you have poorly implemented API communications (or perhaps no API definition at all).</p> </li> <li> <p><strong>Don’t limit your thinking on APIs to code exclusively</strong>. What defines an API in this context is the consistency of the message structures and variables within that message. As long as that consistency is maintained, an API can be implemented in code as well as in declarative customizations, such as modular autolaunched (or platform event-triggered) flows, or even flow templates. Base your decisions around what to define in code versus in flows not on API implementation but rather on <a href="/../well-architected/adaptable/composable#Packageability">packageablility</a> and <a href="/../well-architected/adaptable/resilient#Application_Lifecycle_Management">testability</a>.</p> </li> <li> <p><strong>Keep your lifecycle and versioning simple</strong>. Like all parts of application development, APIs have a lifecycle: define, build, test, deploy, and maintain (including retire). Salesforce Platform APIs release several versions within a calendar year, because of the platform’s rapid release cycle. (You can read more about this behavior in Salesforce <a href="/../fundamentals/architecture-basics#Platform_APIs">Architecture Basics</a>.) This means that platform APIs have a fairly complex lifecycle, as several versions of a particular API need to be maintained and available for Salesforce customers. This level of complexity is appropriate for PaaS use cases — but it is most likely unnecessary complexity for your on-platform solution architectures (see: <a href="/../well-architected/easy/intentional#Readability_Patterns_and_Anti_Patterns">Readablility anti-patterns</a>). Focus on defining a clear purpose for an API (for example, error handling) and clear baseline definitions. Aim to have only one version of each API.</p> </li> <li> <p><strong>Make your APIs discoverable, accessible, and manageable</strong>. <a href="/../well-architected/easy/intentional#Design_Standards">Document your APIs</a> so potential consumers can find available APIs connect to them easily. APIs need to function smoothly as part of a landscape of <a href="/../well-architected/adaptable/composable#Functional_Units">capabilities</a>.</p> </li> <li> <p><strong>Be iterative</strong>. Focus on defining and implementing only one internal API at a time. That way, you can focus on iterating the API definition rapidly, find the right form for your <em>one</em> supported version and establish best practices from the experience of implementation.</p> </li> </ul> <p>The list of <a href="/../well-architected/adaptable/composable#Interoperability_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) API management looks like within a Salesforce solution. You can use these to validate your designs before you build, or identify areas of your system that need to be refactored.</p> <p>To learn more about tools available from Salesforce to help you build more interoperability, see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>.</p> <h3 id="interoperability-patterns-and-anti-patterns">Interoperability Patterns and Anti-Patterns</h3> <p>The following table shows a selection of patterns to look for (or build) in your org and anti-patterns to avoid or target for remediation.</p> <p>✨ Discover more patterns for interoperability in the <a href="/../well-architected/explorer?Adaptable=Interoperability">Pattern &#x26; Anti-Pattern Explorer</a>.</p> <table> <colgroup> <col span="1" style="width: 10%;"> <col span="1" style="width: 45%;"> <col span="1" style="width: 45%;"> </colgroup> <tbody> <tr> <th scope="colgroup"></th> <th scope="colgroup">Patterns</th> <th scope="colgroup">Anti-Patterns</th> </tr> <tr> <td rowspan="3"><b>Messaging and Eventing</b></td> <td><b>In your design standards:</b> <br> - Clear standards exist for when to use synchronous patterns (messaging) and asynchronous patterns (eventing) <br> - Clear standards exist for event and message structures </td> <td><b>In your design standards:</b> <br> - Design standards do not exist, or they lack clear standards for sync vs. async patterns and clear standards for message or event structures </td> </tr> <tr> <td><b>In your org:</b> <br> - Platform events used for internal system messaging are clearly labelled <br> - Salesforce Flow tools reference system-wide messaging or eventing services <br> - Consistent messaging and eventing patterns appear in flows and code </td> <td><b>In your org:</b> <br> - Platform events used for internal system messaging are not clearly labelled or do not exist <br> - Different strategies for messaging and eventing patterns appear across flow and code </td> </tr> <tr> <td><b>In Apex or LWC:</b> <br> - Custom event definitions are limited in scope (no system-wide events or messages are defined in code) <br> - System-wide messaging or eventing services in Apex are annotated in ways that make them available in Salesforce Flow tools </td> <td><b>In Apex or LWC:</b> <br> - System-wide message and/or event structures are defined in Apex or JavaScript <br> - System-wide event or message structures defined in Apex are not available in tools like flow </td> </tr> <tr> <td rowspan="3"><b>API Management</b></td> <td><b>In your design standards:</b> <br> - Clear protocols for cross-component communication (i.e. APIs) exist <br> - Protocols/APIs are outlined in logical groups that builders can search for and find <br> - Protocols/APIs define variable data types, variable names, what is required or optional and provide a clear description of when to use </td> <td><b>In your design standards:</b> <br> - Design standards do not exist or do not define APIs and use cases </td> </tr> <tr> <td><b>In your documentation:</b> <br> - Every component's documentation clearly lists which API/communication protocol has been implemented <br> - It is possible to search for a particular API or protocol and identify components where it is implemented </td> <td><b>In your documentation:</b> <br> - Component documentation does not exist <br> - Component documentation describes the API implemented within a component, but that is the only place the API definition appears <br> - It is not possible to search for a particular API or protocol and/or searches do not help identify components where an API or protocol has been implemented </td> </tr> <tr> <td><b>In your org:</b> <br> - API message formats and variables for internal communication are defined with custom metadata types <br> - API message formats and variables for internal communication are defined with platform events <br> - Code and declarative customizations reference the appropriate custom metadata type (or platform event) in order to send or receive information </td> <td><b>In your org:</b> <br> - Communication between components of the system (code and declarative customizations) is ad hoc <br> - APIs are defined exclusively for communication between Salesforce and external systems </td> </tr> </tbody> </table> <h2 id="packageability">Packageability</h2> <p>Creating packageability in a Salesforce org means functionality in the org comes from units that can be developed and deployed independently and reliably, as packages. Ideally, these units are defined as a type of <a href="https://developer.salesforce.com/docs/atlas.en-us.218.0.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp_plan_pkg_types.htm">second-generation</a> package (either an unlocked package or managed package for ISVs). Note: Because well-architected solutions use these package types exclusively, first-generation managed packages are not covered here.</p> <p>It’s one thing to define <a href="/../well-architected/adaptable/composable#Separation_Of_Concerns">separations of concerns</a> and create functional units in a Salesforce org. It’s another thing to untangle and manage dependencies clearly enough to successfully version those units as package artifacts. Achieving that level of stability and metadata isolation requires a significant level of DevOps (and architectural) maturity. It also speeds up development time, improves app builder experiences, and brings predictability and control to releases and release management. Not every organization will be capable of supporting the infrastructure required to define, maintain, and develop effective packages. But achieving packageability should be the ultimate goal for nearly every Salesforce org.</p> <p>You can build packageability in your Salesforce solutions by focusing on loose coupling and dependency management.</p> <h3 id="loose-coupling">Loose Coupling</h3> <p>In a system with loose coupling, individual pieces are not strongly tied to one another. Many of the advantages of a composable system stem from loose coupling. In packageable systems, achieving loose coupling between packages (and installing orgs) will enable you to have well-defined packages and more productive development cycles for teams working with packages.</p> <p>On the Salesforce Platform, you can build packages that are <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_unlocked_pkg_org_dependent.htm">tightly coupled to a particular org</a>. This capability is useful in defining functional units and experimenting with proper <a href="/../well-architected/adaptable/composable#Separation_Of_Concerns">separation of concerns</a> in your org, as you progress in packaging maturity. If you choose this approach, however, you will realize few of the benefits of truly packageable metadata, including source-driven development, the ability to use versioning, and artifact stability. Instead, you will likely continue to experience the drawbacks of a tightly coupled system, including:</p> <ul> <li>Single points of failure causing outages and performance issues</li> <li>Slow, unpredictable deployments</li> <li>Difficult, complex debugging and troubleshooting cycles</li> <li>Issues with <a href="/../well-architected/trusted/reliable#Scalability">scale</a> and <a href="/../well-architected/trusted/reliable#Performance">performance</a></li> </ul> <p>The end goal for any packageable Salesforce system is loosely coupled packages.</p> <p>Consider the following as you look at separating your Salesforce metadata into effective packages:</p> <ul> <li><strong>What customizations are data versus metadata</strong>. When it comes to packageability, the Salesforce Platform treats data and metadata very differently. It is important to understand what features in your org are <a href="/../fundamentals/architecture-basics#Metadata_Versus_Data">metadata or data</a>. You cannot include data in any packaged units. As you decide where to begin abstracting functionality into a packaged unit, your teams will need to decide if customizations stored as data should be excluded from the package altogether or refactored into a metadata-based implementation.</li> <li><strong>How packaging will impact teams</strong>. A logistical reality of Salesforce packaging is that much of the work of producing and releasing a package version requires skill with the Salesforce CLI and/or CI/CD technologies. This means low-code and programmatic customizations alike will require time and attention from someone capable of working with package-related DevOps technology. Depending on how your team manages feature delivery, package adoption may pose significant slowdowns or blockers to different teams across an org. You will have to identify if teams will be able to manage feature delivery via packaging, and make a plan to address any skill or staffing gaps. Solutions might include adopting paired programming or implementing CI/CD jobs for dev environments.</li> <li><strong>How packaging will change environment strategies</strong>. In a package-driven development lifecycle, early work should be done in <a href="https://developer.salesforce.com/docs/atlas.en-us.238.0.sfdx_setup.meta/sfdx_setup/sfdx_setup_next_steps.htm?q=scratch%20org">scratch orgs</a>. These temporary, source-driven development environments allow for faster, more iterative cycles. They also support more granular environment access controls for your development teams and greater isolation from production. The more dependencies your packages have on unpackaged metadata or data that only exists in a sandbox or production environment, the less likely it is teams will be able to actually use scratch orgs. You can <a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_setup_enable_source_tracking_sandboxes.htm">enable source tracking in sandboxes</a>, to allow for source-driven development patterns in non-scratch org environments — but your development teams will not benefit from the speed and iterative velocity of scratch orgs.</li> <li><strong>How package versions relate to releases</strong>. Plan for how often and at what stage of development package versioning should happen. Package version requests are limited (per org) on a 24-hour rolling basis. As a general best practice, only version a package when you are confident none of the package contents need to change. Ideally, you will provision package versions after quality assurance processes have completed. Do not allow development teams to use the success or failure of package creation requests as “tests” of how well they’ve defined package boundaries. There are ways to do this without attempting to version a package artifact.</li> <li><strong>What the ideal end-state should support</strong>. The ideal packaging strategy allows for controlled, stable Salesforce releases that can be developed and delivered rapidly. Defining too many packages throughout your org can generate new kinds of complexities and bottlenecks for development teams. An overly modularized org can also cause releases to be slow and difficult. Start with building and releasing a few versions of a single, meaningful package. Derive follow-on packages incrementally. Stop introducing packages when you have a release cadence that serves your business well. Refactor packages over time, if business needs change or release quality declines. The ideal package end-state is subjective.</li> </ul> <p>Regardless of how you decide to define your packages, you will only successfully version a loosely coupled package through effective <a href="/../well-architected/adaptable/composable#Dependency_Management">dependency management</a>.</p> <p>The list of <a href="/../well-architected/adaptable/composable#Packageability_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) loose coupling looks like for Salesforce packaging. You can use these to validate your designs before you build, or identify areas of your system that need to be refactored.</p> <p>To learn more about Salesforce tools to help you build more packageability, see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>.</p> <h3 id="dependency-management">Dependency Management</h3> <p>In the context of a Salesforce solution, dependency management means identifying and structuring the relationships between the metadata in your packages and the metadata in the orgs into which those packages will be installed. Dependency management is a key part of developing stable package artifacts.</p> <p>Dependencies can be at odds with efforts to create perfectly separated, <a href="/../well-architected/adaptable/composable#Loose_Coupling">loosely coupled</a> functional units. In an ideal engineering state, a loosely coupled system has no dependencies between units. In the real-world, however, eliminating all dependencies is not practical.</p> <p>Often, the balance between making systems <a href="/../well-architected/easy/intentional#Readability">readable</a> and using business-friendly <a href="/../well-architected/adaptable/composable#Functional_Units">functional units</a> requires a trade-offs in terms of perfect isolation across the units in a system. More pragmatically, the core services provided by the <a href="/../well-architected/easy/intentional#Standard_Versus_Custom_Functionality">standard functionality</a> of the Salesforce Platform create key, net-positive dependencies for any Salesforce solution. Many built-in scalability, performance, and security advantages come from how deeply they are integrated into the platform. When designing packageable Salesforce solutions, it’s important to remember that package dependencies are not inherently bad. Poor dependency management <em>is</em> bad.</p> <p>Effective dependency management with Salesforce packaging means development and maintenance teams can:</p> <ul> <li>Onboard to new projects faster and with limited environment access</li> <li>Quickly develop and test changes</li> <li>Understand how complex functionality should be delivered in smaller, specific commitments</li> <li>Control release cadences, and reduce system maintenance/release outage windows</li> <li>Predictably rollback adverse changes in any environment</li> </ul> <p>The techniques for dependency management with Salesforce are fairly straightforward:</p> <ul> <li>Use <a href="/../well-architected/adaptable/composable#Messaging_and_Eventing">messaging and eventing</a> to handle graceful hand-offs of stateful or stateless information between components.</li> <li>Use custom metadata types to provide dynamic run-time information and to support dependency injection patterns.</li> <li>Have Apex developers use <a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_extending.htm">abstract or virtual classes</a>.</li> </ul> <p>In the end, you will need to decide the design patterns that are allowed in your org across declarative and programmatic development. The most important considerations (architecturally) are to define where you want to add more engineering complexity in order to have fewer dependencies, and where you need to tolerate more dependencies to simplify app builder workflows.</p> <p>As you build dependency management strategies into your packages, consider the two primary organizing principles for package units: horizontal and vertical.</p> <ul> <li><strong>Horizontal boundaries</strong>. In horizontal paradigms, functionality that might be needed by more than one package is abstracted into a horizontal layer. Horizontal layers then become the source of common functionality, and are accessed via a declared dependency. Minimizing redundant functionality across packages is favored over minimizing dependencies.</li> <li><strong>Vertical boundaries</strong>. Vertical paradigms maximize isolation and loose coupling between parts of the system. Shared functionality is limited, and similar work might appear across units. Dependencies are strictly limited, in order to maximize isolation between package units.</li> </ul> <p>Note that this is not an either/or decision. You can mix vertical and horizontal paradigms as needed. Often, the fastest way to start with a package is to create horizontal service layers. As the scale and complexity of your package adoption grows, abstracting more vertical units will help simplify complex environment setup processes or developer onboarding.</p> <p>A system with two functional units (A and B), for example, can be structured with package dependencies arranged in vertical, horizontal, and vertical-horizontal hybrid paradigms.</p> <a href="/assets/images/composable-vertical-horizontal-slices.jpeg" target="_blank"> <img style="border:1px solid #e5e5e5;margin:2rem 0rem" src="/1/asset/immutable/s/17304959070000000/assets/images/composable-vertical-horizontal-slices.jpeg" alt="This is a diagram showing two packages, A and B, built to have no shared dependencies (vertical slice), built to have many common services (horizontal) and a mix of each (hybrid)."> </a> <p>Regardless of the package organizing paradigm you choose, there are some absolutes to keep in mind:</p> <ul> <li><strong>Do not duplicate metadata across packages</strong>. Metadata needed by more than one package should be abstracted into one or more packages that are declared as dependencies.</li> <li><strong>Make use of the built-in dependencies of Salesforce Platform metadata</strong>. For app builders, the built-in services offered by the Salesforce Platform provide a great deal of functionality that can be configured quickly. Many of these services have built-in dependencies that make them difficult to abstract into low-level functional units. For a given metadata type, you need to understand where it falls along the <a href="https://developer.salesforce.com/blogs/2018/06/lets-talk-deployment-and-reasons-why-they-succeed-or-fail">spectrum of built-in dependencies</a>, and use this understanding to <a href="https://developer.salesforce.com/blogs/2018/06/working-with-modular-development-and-unlocked-packages-part-2">define your package dependency chains</a>. Don’t start package adoption by trying force loose coupling into a piece of standard platform functionality with lots of built-in dependencies. It will add complexity (not value) as you reach higher-order capabilities. It is also another way to fall into <a href="/../well-architected/easy/intentional#Standard_Versus_Custom_Functionality">standard vs. custom</a> <a href="/../well-architected/easy/intentional#Maintainability_Patterns_and_Anti_Patterns">anti-patterns</a>. Package metadata from the bottom (fewest dependencies) up — and iterate over time.</li> <li><strong>Watch your dependency chains</strong>. Avoid creating package dependency chains that will require developers to split their changes into many different packages at any one time.</li> <li><strong>Think about what makes sense for source control</strong>. There are two basic ways to manage your packages in source control. The first is a single <em>monorepo</em> with packages isolated within folders. The second is multiple repos with packages isolated in their own repos. There are complexities to managing each kind of source strategy, long-term. In terms of developer onboarding, vertical boundaries are more efficient in multiple repo paradigms. Horizontal boundaries are more comprehensible in a monorepo. Again, you can mix and match strategies as your architecture matures.</li> </ul> <p>The list of <a href="/../well-architected/adaptable/composable#Packageability_Patterns_and_Anti_Patterns">patterns and anti-patterns</a> below shows what proper (and poor) dependency management looks like with Salesforce packages. You can use these to validate your designs before you build, or identify areas of your system that need to be refactored.</p> <p>To learn more about Salesforce tools for dependency management, see <a href="/../well-architected/adaptable/composable#Tools_Relevant_To_Composable">Tools Relevant to Composable</a>.</p> <h3 id="packageability-patterns-and-anti-patterns">Packageability Patterns and Anti-Patterns</h3> <p>The following table shows a selection of patterns to look for (or build) in your org and anti-patterns to avoid or target for remediation.</p> <p>✨ Discover more patterns for packageability in the <a href="/../well-architected/explorer?Adaptable=Packageability">Pattern &#x26; Anti-Pattern Explorer</a>.</p> <table> <colgroup> <col span="1" style="width: 10%;"> <col span="1" style="width: 45%;"> <col span="1" style="width: 45%;"> </colgroup> <tbody> <tr> <th scope="colgroup"></th> <th scope="colgroup">Patterns</th> <th scope="colgroup">Anti-Patterns</th> </tr> <tr> <td rowspan="5"><b>Loose Coupling</b></td> <td><b>In your design standards:</b> <br> - Naming conventions address how to denote package units <br> - It's possible to search for and find a list of all currently defined package units (and related naming conventions) <br> - Standards for proposing package unit additions or changes exist <br> - (Optional) All approved use cases for custom settings are clearly listed (if you have any) </td> <td><b>In your design standards:</b> <br> - Design standards do not exist or do not deal with package units and use cases </td> </tr> <tr> <td><b>In your org:</b> <br> - Custom metadata types provide dynamic, run-time information for code and declarative customizations <br> - No custom settings exist or few custom settings exist, and none are related to packaged functionality <br> - No custom objects exist in order to provide dynamic, run-time information for code or declarative customizations </td> <td><b>In your org:</b> <br> - Custom settings are used <br> - Custom objects exist in order to provide dynamic, run-time information for code or declarative customizations <br> - Custom metadata types are not used (or are not used consistently) to provide dynamic, run-time information for code and declarative customizations </td> </tr> <tr> <td><b>In Apex:</b> <br> - Common services and boilerplate code are defined using abstract or virtual Apex classes <br> - Methods dependent on dynamic, run-time information reference appropriate custom metadata types </td> <td><b>In Apex:</b> <br> - Common services and boilerplate code are not easily distinguished from other classes <br> - Internal references across classes and methods are hard to follow and are inconsistent throughout the codebase <br> - Methods do not use a consistent approach for accessing dynamic, run-time information, or methods query custom objects for runtime behavior information, or code references custom settings </td> </tr> <tr> <td><b>In source control and development environments:</b> <br> - package.xml files only appear in early stage or proof-of-concept project manifests </td> <td><b>In source control and development environments:</b> <br> - package.xml files are used to control metadata deployments </td> </tr> <tr> <td><b>In packages:</b> <br> - Org-dependent unlocked packages are used only for early-stage or proof-of-concept experiments <br> - No unmanaged packages are defined in production or sandboxes </td> <td><b>In packages:</b> <br> - All packages are org-dependent unlocked packages <br> - Unmanaged packages are defined in production or sandboxes </td> </tr> <tr> <td rowspan="4"><b>Dependency Management</b></td> <td><b>In your design standards:</b> <br> - Standards for declaring dependencies exist <br> - Standards for introducing or modifying dependencies exist </td> <td><b>In your design standards:</b> <br> - Design standards do not exist or do not deal with how to declare dependencies </td> </tr> <tr> <td><b>In source control:</b> <br> - Package versions for unlocked packages use aliasing (<code>LATEST</code>) to declare dependencies in <code>sfdx-project.json</code> manifests <br> - Developers can create scratch orgs and deploy package metadata successfully from source control </td> <td><b>In source control:</b> <br> - Package versions for unlocked packages are declared explicitly (no <code>LATEST</code> aliasing) in <code>sfdx-project.json</code> manifests <br> - Developers cannot work successfully with scratch orgs using source control </td> </tr> <tr> <td><b>In your packages:</b> <br> - No metadata is duplicated across packages <br> - For package development, all early-stage development work happens in scratch orgs </td> <td><b>In your packages:</b> <br> - Dependencies are circumvented by duplicating metadata in different packages <br> - Early package development happens in developer sandboxes or early package development cannot happen in scratch orgs </td> </tr> <tr> <td colspan="2">Also see: <a href="/../well-architected/adaptable/composable#Loose_Coupling">Loose Coupling</a></td> </tr> </tbody> </table> <h2 id="tools-relevant-to-composable">Tools Relevant to Composable</h2> <table class="tools-table"><tbody><tr><th>Tool</th><th>Description</th><th>Separation of Concerns</th><th>Interoperability</th><th>Packageability</th></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_rest.htm">Apex REST Web Services</a></td><td>Expose your Apex classes and methods to external applications via REST</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_web_services.htm#apex_web_services">Apex SOAP Web Services</a></td><td>Expose your Apex classes and methods to external applications via SOAP</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.change_data_capture.meta/change_data_capture/cdc_intro.htm">Change Data Capture</a></td><td>Publish changes to Salesforce records</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://help.salesforce.com/s/articleView?id=sf.custommetadatatypes_overview.htm&#x26;language=en_US&#x26;r=https%3A%2F%2Fwww.google.com%2F&#x26;type=5">Custom Metadata Types</a></td><td>Define reusable, customizable, packageable functionality</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/component-library/documentation/en/lwc/reference_decorators">Decorators</a></td><td>Expose functions or properties publically as an api</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_setup_enable_devhub.htm">Dev Hub</a></td><td>Manage scratch orgs, second-generation packages, and Einstein features.</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/generic_streaming_intro.htm">Generic Events (Legacy)*</a></td><td>Send custom events that are not tied to Salesforce data changes</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/component-library/documentation/en/lwc/lwc.data_ui_api">Lightning Data Service</a></td><td>Cache and share data across components</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_intro.htm">Metadata API</a></td><td>Deploy customizations between Salesforce environments</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://mdcoverage.secure.force.com/docs/metadata-coverage">Metadata Coverage Report</a></td><td>Determine supported metadata coverage across several channels </td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://docs.mulesoft.com/composer/ms_composer_overview">Mulesoft Composer</a></td><td>Build process automation for data using clicks instead of code</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_om_outboundmessaging.htm">Outbound Messages</a></td><td>Send messages to external endpoints when field values are updated</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_intro.htm">Platform Events </a></td><td>Send secure and scalable messages that contain near real-time event data</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/blogs/2021/07/pub-sub-api-building-event-driven-integrations-just-got-even-easier">Pub/Sub API</a></td><td>Subscribe to platform events, Change Data Capture, or Real-Time Event Monitoring</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api_streaming.meta/api_streaming/pushtopic_events_intro.htm">PushTopic Events (Legacy)*</a></td><td>Send and receivedata change notifications matching a user-defined SOQL query</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/tools/sfdxcli">Salesforce CLI</a></td><td>Develop and build automation when working with your Salesforce organization</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://architect.salesforce.com/diagrams/#getting-started">Salesforce Diagrams</a></td><td>Create diagrams to show business capabilities and technical details</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col"></td></tr> <tr><td><a href="https://marketplace.visualstudio.com/items?itemName=salesforce.salesforcedx-vscode-expanded">Salesforce Extensions for Visual Studio Code (Expanded)</a></td><td>Official VS Code extensions for Salesforce development</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_scratch_orgs.htm">Scratch Orgs</a></td><td>Deploy Salesforce code and metadata to a disposable org</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp.htm">Second Generation Managed Packages</a></td><td>Develop and distribute apps for the AppExchange</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api_tooling.meta/api_tooling/intro_tasks.htm">Tooling API</a></td><td>Build custom development tools or apps for Lightning Platform applications</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_unlocked_pkg_intro.htm">Unlocked Packages</a></td><td>Organize metadata, package an app, or extend an AppExchange app</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr> <td colspan="5">*Salesforce will continue to support PushTopic and Generic Events within current functional capabilities, but does not plan to make further investments in this technology.</td> </tr> </tbody></table> <h2 id="resources-relevant-to-composable">Resources Relevant to Composable</h2> <table class="tools-table"><tbody><tr><th>Resource</th><th>Description</th><th>Separation of Concerns</th><th>Interoperability</th><th>Packageability</th></tr> <tr><td><a href="https://blogs.mulesoft.com/api-integration/strategy/a-primitive-look-at-digital-integration/">A Primitive Look at Digital Integration</a></td><td>Develop a common language for connectivity concepts</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://medium.com/p/cd4b7ebe926b">Applying Domain-Driven Design with Salesforce</a></td><td>Orient your solutions around business capabilities</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.218.0.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp_plan_best_practices.htm">Best Practices for Second-Generation Packages</a></td><td>Understand 2GP packaging patterns and practices</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.238.0.sfdx_dev.meta/sfdx_dev/packaging_packageable_components.htm">Components Available in Managed Packages</a></td><td>Understand managed package metadata components</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="/../resources/design-standards-template">Design Standards Template</a></td><td>Create design standards for your organization</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col">X</td></tr> <tr><td><a href="https://architect.salesforce.com/decision-guides/event-driven">Event-Driven Architecture Decision Guide</a></td><td>Compare event-driven architecture patterns and tools</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/events_anti_patterns.htm">Events Anti-Patterns</a></td><td>Identify anti-patterns to avoid when using events</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://blogs.mulesoft.com/dev-guides/design-message-driven-and-event-driven-apis/">How to design message-driven and event-driven APIs</a></td><td>Read up on the differences in a MuleSoft dev guide</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://trailhead.salesforce.com/en/content/learn/modules/jobs-to-be-done-framework-for-designers/learn-about-the-jobs-to-be-done-framework">Learn About the Jobs to be Done Framework</a></td><td>Explore JTBD on Trailhead</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/managing-global-state.html">Manage Global State in B2C Commerce</a></td><td>Easily pass data between components to maintain state</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col"></td></tr> <tr><td><a href="https://www.lightningdesignsystem.com/guidelines/messaging/overview/">Messaging Guidelines</a></td><td>Communicate relevant information and create moments of delight</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://www.lightningdesignsystem.com/guidelines/messaging/types/">Messaging Types</a></td><td>Understand different messaging types by the nature of user interaction</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.238.0.api_meta.meta/api_meta/meta_types_list.htm">Metadata Types</a></td><td>Understand the different types of metadata in your Salesforce org</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://architect.salesforce.com/decision-guides/migrate-change">Migrating Changes Decision Guide</a></td><td>Choose the right deployment option for your solution</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> <tr><td><a href="https://help.salesforce.com/s/articleView?id=sf.salesforce_app_enable_push_notifications.htm&#x26;type=5">Mobile App Notification Types</a></td><td>Understand notification types for Salesforce mobile apps</td><td class="check-col"></td><td class="check-col">X</td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.salesforce_visualforce_best_practices.meta/salesforce_visualforce_best_practices/pages_best_practices_perf_code_view_state.htm">Optimizing the View State</a></td><td>Maintain state in a Visualforce page</td><td class="check-col">X</td><td class="check-col"></td><td class="check-col"></td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro.htm">Salesforce Developer Experience (DX)</a></td><td>Manage and develop apps on the Lightning Platform</td><td class="check-col">X</td><td class="check-col">X</td><td class="check-col">X</td></tr> <tr><td><a href="https://developer.salesforce.com/docs/atlas.en-us.api_meta.meta/api_meta/meta_unsupported_types.htm">Unsupported Metadata Types</a></td><td>Identify components that aren’t available in Metadata API</td><td class="check-col"></td><td class="check-col"></td><td class="check-col">X</td></tr> </tbody></table> <h2 id="tell-us-what-you-think">Tell us what you think</h2> <p>Help us keep Salesforce Well-Architected relevant to you; take our <a href="https://sfdc.co/bxNtvh">survey</a> to provide feedback on this content and tell us what you’d like to see next.</p> </tm-content> </div> <script type="application/ld+json"> { "@context": "https://schema.org", "@type": "Article", "headline": "Composable", "image": ["https://architect.salesforce.com/assets/images/cards/composable.png"], "author": "Salesforce Architects", "publisher": { "@type": "Organization", "name": "Salesforce", "logo": { "@type": "ImageObject", "url": "https://architect.salesforce.com'/assets/images/favicon-192x192.png" } }, "url": "https://architect.salesforce.com", "mainEntityOfPage": "https://architect.salesforce.com/well-architected/adaptable/composable", "datePublished": "July 2024", "dateModified": "July 2024", "description": "Read about our update schedules here. Introduction Composable solutions adjust quickly and with greater stability. A system architected to..." } </script> <footer> <tds-footer config="{&quot;columns&quot;:[{&quot;heading&quot;:&quot;Well-Architected&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/well-architected/overview&quot;,&quot;label&quot;:&quot;Overview&quot;},{&quot;href&quot;:&quot;/well-architected/trusted/overview&quot;,&quot;label&quot;:&quot;Trusted&quot;},{&quot;href&quot;:&quot;/well-architected/easy/overview&quot;,&quot;label&quot;:&quot;Easy&quot;},{&quot;href&quot;:&quot;/well-architected/adaptable/overview&quot;,&quot;label&quot;:&quot;Adaptable&quot;},{&quot;href&quot;:&quot;/well-architected/explorer&quot;,&quot;label&quot;:&quot;Pattern &amp; Anti-Pattern Explorer&quot;}]},{&quot;heading&quot;:&quot;Diagrams&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/diagrams/#framework&quot;,&quot;label&quot;:&quot;Salesforce Diagrams Overview&quot;},{&quot;href&quot;:&quot;/diagrams/#reference-architecture-gallery&quot;,&quot;label&quot;:&quot;Reference Architecture Gallery&quot;},{&quot;href&quot;:&quot;/diagrams/#data-model-gallery&quot;,&quot;label&quot;:&quot;Data Model Gallery&quot;}]},{&quot;heading&quot;:&quot;Decision Guides&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/decision-guides/event-driven&quot;,&quot;label&quot;:&quot;Event-Driven Architectures&quot;},{&quot;href&quot;:&quot;/decision-guides/data-integration&quot;,&quot;label&quot;:&quot;Data Integration&quot;},{&quot;href&quot;:&quot;/decision-guides/trigger-automation&quot;,&quot;label&quot;:&quot;Record-Triggered Automation&quot;},{&quot;href&quot;:&quot;/decision-guides/build-forms&quot;,&quot;label&quot;:&quot;Building Forms&quot;},{&quot;href&quot;:&quot;/decision-guides&quot;,&quot;label&quot;:&quot;See All Guides&quot;}]},{&quot;heading&quot;:&quot;Fundamentals&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/fundamentals/platform-transformation&quot;,&quot;label&quot;:&quot;Platform Transformation&quot;},{&quot;href&quot;:&quot;/fundamentals/architecture-basics&quot;,&quot;label&quot;:&quot;Architecture Basics&quot;},{&quot;href&quot;:&quot;/fundamentals/platform-multitenant-architecture&quot;,&quot;label&quot;:&quot;Platform Multitenant Architecture&quot;},{&quot;href&quot;:&quot;/fundamentals/platform-sharing-architecture&quot;,&quot;label&quot;:&quot;Plaform Sharing Architecture&quot;}]},{&quot;heading&quot;:&quot;Resources&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/resources/project-resource-gallery/ai&quot;,&quot;label&quot;:&quot;Project Resource Gallery&quot;},{&quot;href&quot;:&quot;/roadmaps/roadmap-explorer&quot;,&quot;label&quot;:&quot;Roadmap Explorer&quot;},{&quot;href&quot;:&quot;/releases&quot;,&quot;label&quot;:&quot;Release Overviews&quot;}]},{&quot;heading&quot;:&quot;Connect&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;/connect/blog&quot;,&quot;label&quot;:&quot;Our Blog&quot;},{&quot;href&quot;:&quot;https://www.youtube.com/c/SalesforceArchitects&quot;,&quot;label&quot;:&quot;Our Youtube Channel&quot;},{&quot;href&quot;:&quot;https://trailblazer.salesforce.com/about&quot;,&quot;label&quot;:&quot;Trailblazer Community&quot;}]}],&quot;global&quot;:{&quot;logo&quot;:{&quot;assistiveText&quot;:&quot;Salesforce Logo&quot;,&quot;url&quot;:&quot;/assets/images/salesforce-corp-logo.jpg&quot;},&quot;copyrightTitle&quot;:&quot;© Copyright 2024 Salesforce, Inc. &quot;,&quot;copyrightEnd&quot;:&quot; Various trademarks held by their respective owners. Salesforce, Inc. Salesforce Tower, 415 Mission Street, 3rd Floor, San Francisco, CA 94105, United States&quot;,&quot;links&quot;:[{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/&quot;,&quot;label&quot;:&quot;Legal&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/sfdc-website-terms-of-service/&quot;,&quot;label&quot;:&quot;Terms of Service&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/legal/privacy/&quot;,&quot;label&quot;:&quot;Privacy Information&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/disclosure/&quot;,&quot;label&quot;:&quot;Responsible Disclosure&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://trust.salesforce.com/&quot;,&quot;label&quot;:&quot;Trust&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/company/contact-us/?d=cta-glob-footer-11&quot;,&quot;label&quot;:&quot;Contact&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;},{&quot;href&quot;:&quot;https://www.salesforce.com/form/other/privacy-request/&quot;,&quot;label&quot;:&quot;Your Privacy Choices&quot;,&quot;target&quot;:&quot;_blank&quot;,&quot;rel&quot;:&quot;noopener&quot;,&quot;icon&quot;:&quot;/assets/images/privacyicon.png&quot;}]}}"></tds-footer> </footer> <script type="application/javascript">/* This script is generated */ /* Client Bootstrap configuration */ globalThis.LWR = globalThis.LWR || {}; Object.assign(globalThis.LWR, {"appId":"genericRouteHandler","bootstrapModule":"@lwrjs/app-service/genericRouteHandler/module/esm/v/0_11_15","autoBoot":true,"imports":{"/1/bundle/esm/l/en-US/bi/0/module/mi/%40lwrjs%2Fapp-service%2FgenericRouteHandler%2Fmodule%2Fesm%2Fv%2F0_11_15/s/b6ad7971baa5047e7bbcc1e3720daf77d2e9a4e8/bundle_@lwrjs_app-service_genericRouteHandler_module_esm.js":["@lwrjs/app-service/genericRouteHandler/module/esm/v/0_11_15"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Fheader%2Fv%2F1_0_1/s/f1ae5fd3b59a385b871f876495d5741e0957add6/bundle_tds_header.js":["tds/header/v/1_0_1"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Fsearch%2Fv%2F1_0_1/s/ba146dfefa0db013dde40c32eb477d1546205919/bundle_tds_search.js":["tds/search/v/1_0_1"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tm%2FpageHeaderA%2Fv%2F1_0_1/s/c8f9c55107f494dec9b72e13a6bb453e5f9f65bd/bundle_tm_pageHeaderA.js":["tm/pageHeaderA/v/1_0_1"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tm%2Fcontent%2Fv%2F1_0_1/s/dee4bef2d0f5ca8a26d7c6e1b844af5611d11762/bundle_tm_content.js":["tm/content/v/1_0_1"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Ffooter%2Fv%2F1_0_1/s/1f66aa6c773f6411635ee086a6f51d1560c26190/bundle_tds_footer.js":["tds/footer/v/1_0_1"],"/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Finstrumentation%2Fv%2F1_0_1/s/9c0fc260e15d54da8ccbbd08bcaf7480b9943fff/bundle_tds_instrumentation.js":["tds/instrumentation/v/1_0_1"]},"index":{"@lwrjs/app-service/genericRouteHandler/module/esm/v/0_11_15":"/1/module/esm/0/l/en-US/mi/%40lwrjs%2Fapp-service%2FgenericRouteHandler%2Fmodule%2Fesm%2Fv%2F0_11_15/latest/@lwrjs_app-service_genericRouteHandler_module_esm.js","tds/header/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tds%2Fheader%2Fv%2F1_0_1/latest/tds_header.js","tds/search/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tds%2Fsearch%2Fv%2F1_0_1/latest/tds_search.js","tm/pageHeaderA/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tm%2FpageHeaderA%2Fv%2F1_0_1/latest/tm_pageHeaderA.js","tm/content/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tm%2Fcontent%2Fv%2F1_0_1/latest/tm_content.js","tds/footer/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tds%2Ffooter%2Fv%2F1_0_1/latest/tds_footer.js","tds/instrumentation/v/1_0_1":"/1/module/esm/0/l/en-US/mi/tds%2Finstrumentation%2Fv%2F1_0_1/latest/tds_instrumentation.js"},"rootComponents":["tds/header/v/1_0_1","tds/search/v/1_0_1","tm/pageHeaderA/v/1_0_1","tm/content/v/1_0_1","tds/footer/v/1_0_1","tds/instrumentation/v/1_0_1"],"serverData":{},"endpoints":{"uris":{"mapping":"/1/mapping/esm/0/l/en-US/bi/0/mp/","module":"/1/bundle/esm/l/en-US/bi/0/module/mi/"}}}); globalThis.process = { env: {"NODE_ENV":"prod","SSR":false,"basePath":"","locale":"en-US","assetBasePath":"","uiBasePath":""} }; globalThis.lwcRuntimeFlags = { ENABLE_MIXED_SHADOW_MODE: false };</script> <script type="module" src="/1/bundle/esm/l/en-US/bi/0/module/mi/%40lwrjs%2Fapp-service%2FgenericRouteHandler%2Fmodule%2Fesm%2Fv%2F0_11_15/s/b6ad7971baa5047e7bbcc1e3720daf77d2e9a4e8/bundle_@lwrjs_app-service_genericRouteHandler_module_esm.js"></script> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Fheader%2Fv%2F1_0_1/s/f1ae5fd3b59a385b871f876495d5741e0957add6/bundle_tds_header.js" /> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Fsearch%2Fv%2F1_0_1/s/ba146dfefa0db013dde40c32eb477d1546205919/bundle_tds_search.js" /> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tm%2FpageHeaderA%2Fv%2F1_0_1/s/c8f9c55107f494dec9b72e13a6bb453e5f9f65bd/bundle_tm_pageHeaderA.js" /> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tm%2Fcontent%2Fv%2F1_0_1/s/dee4bef2d0f5ca8a26d7c6e1b844af5611d11762/bundle_tm_content.js" /> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Ffooter%2Fv%2F1_0_1/s/1f66aa6c773f6411635ee086a6f51d1560c26190/bundle_tds_footer.js" /> <link rel="modulepreload" href="/1/bundle/esm/l/en-US/bi/0/module/mi/tds%2Finstrumentation%2Fv%2F1_0_1/s/9c0fc260e15d54da8ccbbd08bcaf7480b9943fff/bundle_tds_instrumentation.js" /> <tds-instrumentation use-google-tag-manager="true"></tds-instrumentation> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10